production-evyos-systems-an.../ServicesApi/src/auth/password/change/change.service.ts

197 lines
6.0 KiB
TypeScript

import { PrismaService } from '@/src/prisma.service';
import {
Injectable,
BadRequestException,
UnauthorizedException,
} from '@nestjs/common';
import { userChangePasswordValidator } from './dtoValidator';
import { RedisHandlers } from '@/src/utils/store/redisHandlers';
import { PasswordHandlers } from '@/src/utils/store/loginHandler';
@Injectable()
export class ChangePasswordService {
constructor(
private readonly prisma: PrismaService,
private readonly redis: RedisHandlers,
private readonly passHandlers: PasswordHandlers,
) { }
private async syncPasswordHistory(
foundUser: any,
dto: userChangePasswordValidator,
hashPassword: string,
) {
const passwordHistory = await this.prisma.password_history.findFirst({
where: { userUUID: foundUser.uu_id },
});
console.log('passwordHistory', passwordHistory);
console.log('dto', dto);
console.log('hashPassword', hashPassword);
if (passwordHistory) {
if (!passwordHistory.old_password_first) {
await this.prisma.password_history.update({
where: { id: passwordHistory.id },
data: {
password: hashPassword,
old_password_first: dto.password,
old_password_first_modified_at: new Date(),
},
});
} else if (!passwordHistory.old_password_second) {
await this.prisma.password_history.update({
where: { id: passwordHistory.id },
data: {
password: hashPassword,
old_password_second: dto.password,
old_password_second_modified_at: new Date(),
},
});
} else if (!passwordHistory.old_password_third) {
await this.prisma.password_history.update({
where: { id: passwordHistory.id },
data: {
password: hashPassword,
old_password_third: dto.password,
old_password_third_modified_at: new Date(),
},
});
} else {
const firstTimestamp = new Date(
passwordHistory.old_password_first_modified_at,
).getTime();
const secondTimestamp = new Date(
passwordHistory.old_password_second_modified_at,
).getTime();
const thirdTimestamp = new Date(
passwordHistory.old_password_third_modified_at,
).getTime();
let oldestIndex = 'first';
let oldestTimestamp = firstTimestamp;
if (secondTimestamp < oldestTimestamp) {
oldestIndex = 'second';
oldestTimestamp = secondTimestamp;
}
if (thirdTimestamp < oldestTimestamp) {
oldestIndex = 'third';
}
await this.prisma.password_history.update({
where: { id: passwordHistory.id },
data: {
password: hashPassword,
...(oldestIndex === 'first'
? {
old_password_first: dto.password,
old_password_first_modified_at: new Date(),
}
: oldestIndex === 'second'
? {
old_password_second: dto.password,
old_password_second_modified_at: new Date(),
}
: {
old_password_third: dto.password,
old_password_third_modified_at: new Date(),
}),
},
});
}
} else {
await this.prisma.password_history.create({
data: {
userUUID: foundUser.uu_id,
password: hashPassword,
old_password_first: dto.password,
old_password_first_modified_at: new Date(),
old_password_second: '',
old_password_second_modified_at: new Date(),
old_password_third: '',
old_password_third_modified_at: new Date(),
},
});
}
}
async run(dto: userChangePasswordValidator, req: Request) {
const isValid = () => {
const isOldPasswordDifferent = dto.password !== dto.oldPassword;
const isPasswordMatchesWithRePassword = dto.password === dto.rePassword;
return isOldPasswordDifferent && isPasswordMatchesWithRePassword;
};
if (!isValid()) {
throw new BadRequestException(
'Passwords do not match or new password is the same as old password',
);
}
const accessObject = await this.redis.getLoginFromRedis(req);
const userFromRedis = accessObject?.value.users;
if (!userFromRedis) {
throw new UnauthorizedException('User not authenticated');
}
const foundUser = await this.prisma.users.findFirstOrThrow({
where: { uu_id: userFromRedis.uu_id },
});
if (foundUser.password_token) {
throw new BadRequestException('Set password first before changing');
}
const isPasswordValid = this.passHandlers.check_password(
foundUser.uu_id,
dto.oldPassword,
foundUser.hash_password,
);
if (!isPasswordValid) {
throw new UnauthorizedException('Invalid password');
}
const passwordHistory = await this.prisma.password_history.findFirst({
where: {
userUUID: foundUser.uu_id,
OR: [
{
old_password_first: {
equals: dto.password,
mode: 'insensitive',
},
},
{
old_password_second: {
equals: dto.password,
mode: 'insensitive',
},
},
{
old_password_third: {
equals: dto.password,
mode: 'insensitive',
},
},
],
},
});
if (passwordHistory) {
throw new UnauthorizedException(
'Invalid password, new password can not be same as old password',
);
}
const hashPassword = this.passHandlers.create_hashed_password(
foundUser.uu_id,
dto.password,
);
await this.prisma.users.update({
where: { id: foundUser.id },
data: {
hash_password: hashPassword,
},
});
await this.syncPasswordHistory(foundUser, dto, hashPassword);
return { message: 'Password changed successfully' };
}
}