import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { NotificationsService } from '../../notification/services/notifications.service'; import { DEFAULT_OTP_DIGIT, DEFAULT_OTP_LENGTH } from '../constants'; import { OtpType } from '../enums'; import { ISendOtp, IVerifyOtp } from '../interfaces'; import { OtpRepository } from '../repositories'; import { generateRandomOtp } from '../utils'; @Injectable() export class OtpService { private readonly logger = new Logger(OtpService.name); constructor( private readonly configService: ConfigService, private readonly otpRepository: OtpRepository, private readonly notificationService: NotificationsService, ) {} private useMock = [true, 'true'].includes(this.configService.get('USE_MOCK', false)); async generateAndSendOtp(sendOtpRequest: ISendOtp): Promise { this.logger.log(`invalidate OTP for ${sendOtpRequest.recipient} and ${sendOtpRequest.otpType}`); await this.otpRepository.invalidateOtp(sendOtpRequest); this.logger.log(`Generating OTP for ${sendOtpRequest.recipient}`); const otp = this.useMock ? DEFAULT_OTP_DIGIT.repeat(DEFAULT_OTP_LENGTH) : generateRandomOtp(DEFAULT_OTP_LENGTH); await this.otpRepository.createOtp({ ...sendOtpRequest, value: otp }); await this.sendOtp(sendOtpRequest, otp); this.logger.log(`OTP generated and sent successfully to ${sendOtpRequest.recipient}`); return sendOtpRequest.otpType == OtpType.EMAIL ? sendOtpRequest.recipient : sendOtpRequest.recipient?.replace(/.(?=.{4})/g, '*'); } async verifyOtp(verifyOtpRequest: IVerifyOtp) { this.logger.log(`Verifying OTP for ${verifyOtpRequest.userId}`); const otp = await this.otpRepository.findOtp(verifyOtpRequest); if (!otp) { this.logger.error( `OTP value ${verifyOtpRequest.value} not found for ${verifyOtpRequest.userId} and ${verifyOtpRequest.otpType} or used`, ); return false; } await this.otpRepository.updateOtp(otp.id, { isUsed: true }); this.logger.log(`OTP verified successfully for ${verifyOtpRequest.userId}`); return !!otp; } private sendOtp(sendOtpRequest: ISendOtp, otp: string) { return this.notificationService.sendOtpNotification(sendOtpRequest, otp); } }