feat:forget password

This commit is contained in:
Abdalhamid Alhamad
2024-12-08 13:15:38 +03:00
parent c486d558ad
commit 90ee8023e6
19 changed files with 154 additions and 48 deletions

View File

@ -4,16 +4,19 @@ import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcrypt';
import { OtpScope, OtpType } from '~/common/modules/otp/enums';
import { OtpService } from '~/common/modules/otp/services';
import { PASSCODE_REGEX, PASSWORD_REGEX } from '../constants';
import {
CreateUnverifiedUserRequestDto,
DisableBiometricRequestDto,
EnableBiometricRequestDto,
ForgetPasswordRequestDto,
LoginRequestDto,
SendForgetPasswordOtpRequestDto,
SetEmailRequestDto,
} from '../dtos/request';
import { VerifyUserRequestDto } from '../dtos/request/verify-user.request.dto';
import { User } from '../entities';
import { GrantType } from '../enums';
import { GrantType, Roles } from '../enums';
import { ILoginResponse } from '../interfaces';
import { removePadding, verifySignature } from '../utils';
import { DeviceService } from './device.service';
@ -35,7 +38,7 @@ export class AuthService {
return this.otpService.generateAndSendOtp({
userId: user.id,
phoneNumber: user.phoneNumber,
recipient: user.phoneNumber,
scope: OtpScope.VERIFY_PHONE,
otpType: OtpType.SMS,
});
@ -126,6 +129,44 @@ export class AuthService {
return this.deviceService.updateDevice(deviceId, { publicKey: null });
}
async sendForgetPasswordOtp({ email }: SendForgetPasswordOtpRequestDto) {
const user = await this.userService.findUserOrThrow({ email });
if (!user.isProfileCompleted) {
throw new BadRequestException('USERS.PROFILE_NOT_COMPLETED');
}
return this.otpService.generateAndSendOtp({
userId: user.id,
recipient: user.email,
scope: OtpScope.FORGET_PASSWORD,
otpType: OtpType.EMAIL,
});
}
async verifyForgetPasswordOtp({ email, otp, password, confirmPassword }: ForgetPasswordRequestDto) {
const user = await this.userService.findUserOrThrow({ email });
if (!user.isProfileCompleted) {
throw new BadRequestException('USERS.PROFILE_NOT_COMPLETED');
}
const isOtpValid = await this.otpService.verifyOtp({
userId: user.id,
scope: OtpScope.FORGET_PASSWORD,
otpType: OtpType.EMAIL,
value: otp,
});
if (!isOtpValid) {
throw new BadRequestException('USERS.INVALID_OTP');
}
this.validatePassword(password, confirmPassword, user);
const hashedPassword = bcrypt.hashSync(password, user.salt);
await this.userService.setPasscode(user.id, hashedPassword, user.salt);
}
async login(loginDto: LoginRequestDto, deviceId: string): Promise<[ILoginResponse, User]> {
const user = await this.userService.findUser({ email: loginDto.email });
let tokens;
@ -205,4 +246,20 @@ export class AuthService {
return { accessToken, refreshToken, expiresAt: new Date(this.jwtService.decode(accessToken).exp * ONE_THOUSAND) };
}
private validatePassword(password: string, confirmPassword: string, user: User) {
if (password !== confirmPassword) {
throw new BadRequestException('AUTH.PASSWORD_MISMATCH');
}
const roles = user.roles;
if (roles.includes(Roles.GUARDIAN) && !PASSCODE_REGEX.test(password)) {
throw new BadRequestException('AUTH.INVALID_PASSCODE');
}
if (roles.includes(Roles.JUNIOR) && !PASSWORD_REGEX.test(password)) {
throw new BadRequestException('AUTH.INVALID_PASSWORD');
}
}
}