From 842e64a4d1428b3ade24f1be5c87892be08aa364 Mon Sep 17 00:00:00 2001 From: yousef-alkhrissat Date: Fri, 9 Aug 2024 18:44:28 +0300 Subject: [PATCH] otp cooldown --- libs/common/src/helper/differenceInSeconds.ts | 4 +++ src/auth/services/user-auth.service.ts | 35 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 libs/common/src/helper/differenceInSeconds.ts diff --git a/libs/common/src/helper/differenceInSeconds.ts b/libs/common/src/helper/differenceInSeconds.ts new file mode 100644 index 0000000..d3ce7f5 --- /dev/null +++ b/libs/common/src/helper/differenceInSeconds.ts @@ -0,0 +1,4 @@ +export function differenceInSeconds(date1: Date, date2: Date): number { + const diffInMilliseconds = date1.getTime() - date2.getTime(); // Difference in milliseconds + return Math.floor(diffInMilliseconds / 1000); // Convert to seconds and round down +} diff --git a/src/auth/services/user-auth.service.ts b/src/auth/services/user-auth.service.ts index a514c1c..69541cc 100644 --- a/src/auth/services/user-auth.service.ts +++ b/src/auth/services/user-auth.service.ts @@ -18,6 +18,8 @@ import { EmailService } from '../../../libs/common/src/util/email.service'; import { OtpType } from '../../../libs/common/src/constants/otp-type.enum'; import { UserEntity } from '../../../libs/common/src/modules/user/entities/user.entity'; import * as argon2 from 'argon2'; +import { differenceInSeconds } from '@app/common/helper/differenceInSeconds'; +import { LessThan, MoreThan } from 'typeorm'; @Injectable() export class UserAuthService { @@ -124,7 +126,38 @@ export class UserAuthService { } async generateOTP(data: UserOtpDto): Promise { - await this.otpRepository.delete({ email: data.email, type: data.type }); + const threeDaysAgo = new Date(); + threeDaysAgo.setDate(threeDaysAgo.getDate() - 3); + await this.otpRepository.softDelete({ email: data.email, type: data.type }); + await this.otpRepository.delete({ + email: data.email, + type: data.type, + createdAt: LessThan(threeDaysAgo), + }); + const countOfOtp = await this.otpRepository.count({ + withDeleted: true, + where: { + email: data.email, + type: data.type, + createdAt: MoreThan(threeDaysAgo), + }, + }); + const lastOtp = await this.otpRepository.findOne({ + where: { email: data.email, type: data.type }, + order: { createdAt: 'DESC' }, + withDeleted: true, + }); + const cooldown = 30 * Math.pow(2, countOfOtp - 1); + if (lastOtp) { + const now = new Date(); + const timeSinceLastOtp = differenceInSeconds(now, lastOtp.createdAt); + + if (timeSinceLastOtp < cooldown) { + throw new Error( + `Please wait ${cooldown - timeSinceLastOtp} more seconds before requesting a new OTP.`, + ); + } + } const otpCode = Math.floor(100000 + Math.random() * 900000).toString(); const expiryTime = new Date(); expiryTime.setMinutes(expiryTime.getMinutes() + 1);