mirror of
https://github.com/BradNut/AdelieStack
synced 2025-09-08 17:40:20 +00:00
105 lines
3.8 KiB
TypeScript
105 lines
3.8 KiB
TypeScript
|
|
import type { ResetPasswordCodeDto } from '$lib/dtos/reset-password';
|
||
|
|
import type { ResetPasswordNewPasswordDto } from '$lib/dtos/reset-password/reset-password-new-password.dto';
|
||
|
|
import { inject, injectable } from '@needle-di/core';
|
||
|
|
import type { CreateLoginRequestDto } from '../../../../dtos/login/create-login-request.dto';
|
||
|
|
import type { } from '../../../../dtos/login/verify-login-request.dto';
|
||
|
|
import { LoggerService } from '../../common/services/logger.service';
|
||
|
|
import { VerificationCodesService } from '../../common/services/verification-codes.service';
|
||
|
|
import { BadRequest } from '../../common/utils/exceptions';
|
||
|
|
import { MailerService } from '../../mail/mailer.service';
|
||
|
|
import { ResetPasswordEmail } from '../../mail/templates/reset-password.template';
|
||
|
|
import { UsersRepository } from '../../users/users.repository';
|
||
|
|
import { UsersService } from '../../users/users.service';
|
||
|
|
import { SessionsService } from '../sessions/sessions.service';
|
||
|
|
import { ResetPasswordRequestsRepository } from './reset-password-requests.repository';
|
||
|
|
|
||
|
|
@injectable()
|
||
|
|
export class ResetPasswordRequestsService {
|
||
|
|
constructor(
|
||
|
|
private loggerService = inject(LoggerService),
|
||
|
|
private resetPasswordRequestsRepository = inject(ResetPasswordRequestsRepository),
|
||
|
|
private usersRepository = inject(UsersRepository),
|
||
|
|
private verificationCodesService = inject(VerificationCodesService),
|
||
|
|
private usersService = inject(UsersService),
|
||
|
|
private sessionsService = inject(SessionsService),
|
||
|
|
private mailer = inject(MailerService),
|
||
|
|
) {}
|
||
|
|
|
||
|
|
async verify({ email, code }: ResetPasswordCodeDto) {
|
||
|
|
// find the hashed verification code for the email
|
||
|
|
const resetPasswordRequest = await this.resetPasswordRequestsRepository.get(email);
|
||
|
|
|
||
|
|
// if no hashed code is found, the request is invalid
|
||
|
|
if (!resetPasswordRequest) throw BadRequest('Invalid code');
|
||
|
|
|
||
|
|
// verify the code
|
||
|
|
const isValid = await this.verificationCodesService.verify({
|
||
|
|
verificationCode: code,
|
||
|
|
hashedVerificationCode: resetPasswordRequest.hashedCode,
|
||
|
|
});
|
||
|
|
|
||
|
|
// if the code is invalid, throw an error
|
||
|
|
if (!isValid) {
|
||
|
|
throw BadRequest('Invalid code');
|
||
|
|
}
|
||
|
|
|
||
|
|
// burn the login request so it can't be used again
|
||
|
|
await this.resetPasswordRequestsRepository.delete(email);
|
||
|
|
|
||
|
|
// check if the user already exists
|
||
|
|
const existingUser = await this.usersRepository.findOneByEmail(email);
|
||
|
|
|
||
|
|
if (!existingUser) {
|
||
|
|
this.loggerService.log.debug('User not found for email', email);
|
||
|
|
throw BadRequest('Unable to reset password');
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
async sendResetPasswordCode({ email }: CreateLoginRequestDto) {
|
||
|
|
// check if the user already exists
|
||
|
|
const existingUser = await this.usersRepository.findOneByEmail(email);
|
||
|
|
|
||
|
|
if (!existingUser) {
|
||
|
|
this.loggerService.log.debug(`User not found for email: ${email}`);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// remove any existing login requests
|
||
|
|
await this.resetPasswordRequestsRepository.delete(email);
|
||
|
|
|
||
|
|
// generate a new verification code and hash
|
||
|
|
const { verificationCode, hashedVerificationCode } = await this.verificationCodesService.generateCodeWithHash();
|
||
|
|
|
||
|
|
// create a new login request
|
||
|
|
await this.resetPasswordRequestsRepository.set({
|
||
|
|
email,
|
||
|
|
hashedCode: hashedVerificationCode,
|
||
|
|
});
|
||
|
|
|
||
|
|
// send the verification email
|
||
|
|
await this.mailer.send({
|
||
|
|
to: email,
|
||
|
|
template: new ResetPasswordEmail(verificationCode),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
async resetPassword({ email, password, confirm_password }: ResetPasswordNewPasswordDto) {
|
||
|
|
if (password !== confirm_password) {
|
||
|
|
throw BadRequest('Passwords do not match');
|
||
|
|
}
|
||
|
|
|
||
|
|
// check if the user already exists
|
||
|
|
const existingUser = await this.usersRepository.findOneByEmail(email);
|
||
|
|
|
||
|
|
if (!existingUser) {
|
||
|
|
throw BadRequest('Unable to reset password');
|
||
|
|
}
|
||
|
|
|
||
|
|
await this.usersService.updatePassword(existingUser.id, password);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
private async authExistingUser({ userId }: { userId: string }) {
|
||
|
|
return this.sessionsService.createSession(userId);
|
||
|
|
}
|
||
|
|
}
|