197 lines
6.0 KiB
TypeScript
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' };
|
|
}
|
|
}
|