From 842e64a4d1428b3ade24f1be5c87892be08aa364 Mon Sep 17 00:00:00 2001 From: yousef-alkhrissat Date: Fri, 9 Aug 2024 18:44:28 +0300 Subject: [PATCH 1/7] 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); From 966762556230e66e56c0729f930c564459bd04c5 Mon Sep 17 00:00:00 2001 From: yousef-alkhrissat Date: Fri, 9 Aug 2024 18:54:53 +0300 Subject: [PATCH 2/7] otp check if user exists in region --- src/auth/dtos/user-otp.dto.ts | 5 +++++ src/auth/services/user-auth.service.ts | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/auth/dtos/user-otp.dto.ts b/src/auth/dtos/user-otp.dto.ts index bab47c8..b588cb2 100644 --- a/src/auth/dtos/user-otp.dto.ts +++ b/src/auth/dtos/user-otp.dto.ts @@ -12,6 +12,11 @@ export class UserOtpDto { @IsEnum(OtpType) @IsNotEmpty() type: OtpType; + + @ApiProperty() + @IsNotEmpty() + @IsString() + regionName: string; } export class VerifyOtpDto extends UserOtpDto { diff --git a/src/auth/services/user-auth.service.ts b/src/auth/services/user-auth.service.ts index 69541cc..5bc8a6b 100644 --- a/src/auth/services/user-auth.service.ts +++ b/src/auth/services/user-auth.service.ts @@ -116,7 +116,7 @@ export class UserAuthService { async deleteUser(uuid: string) { const user = await this.findOneById(uuid); if (!user) { - throw new BadRequestException('User does not found'); + throw new BadRequestException('User not found'); } return await this.userRepository.update({ uuid }, { isActive: false }); } @@ -128,6 +128,17 @@ export class UserAuthService { async generateOTP(data: UserOtpDto): Promise { const threeDaysAgo = new Date(); threeDaysAgo.setDate(threeDaysAgo.getDate() - 3); + const userExists = await this.userRepository.exists({ + where: { + region: { + regionName: data.regionName, + }, + email: data.email, + }, + }); + if (!userExists) { + throw new BadRequestException('User not found'); + } await this.otpRepository.softDelete({ email: data.email, type: data.type }); await this.otpRepository.delete({ email: data.email, @@ -153,7 +164,7 @@ export class UserAuthService { const timeSinceLastOtp = differenceInSeconds(now, lastOtp.createdAt); if (timeSinceLastOtp < cooldown) { - throw new Error( + throw new BadRequestException( `Please wait ${cooldown - timeSinceLastOtp} more seconds before requesting a new OTP.`, ); } From be8152bad98fc28a12a643683574875e9d2d26b3 Mon Sep 17 00:00:00 2001 From: yousef-alkhrissat Date: Fri, 9 Aug 2024 18:57:17 +0300 Subject: [PATCH 3/7] otp check if user is verified --- libs/common/src/helper/differenceInSeconds.ts | 4 ++-- src/auth/services/user-auth.service.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/common/src/helper/differenceInSeconds.ts b/libs/common/src/helper/differenceInSeconds.ts index d3ce7f5..9f05d67 100644 --- a/libs/common/src/helper/differenceInSeconds.ts +++ b/libs/common/src/helper/differenceInSeconds.ts @@ -1,4 +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 + const diffInMilliseconds = date1.getTime() - date2.getTime(); + return Math.floor(diffInMilliseconds / 1000); } diff --git a/src/auth/services/user-auth.service.ts b/src/auth/services/user-auth.service.ts index 5bc8a6b..fe459cb 100644 --- a/src/auth/services/user-auth.service.ts +++ b/src/auth/services/user-auth.service.ts @@ -134,6 +134,7 @@ export class UserAuthService { regionName: data.regionName, }, email: data.email, + isUserVerified: true, }, }); if (!userExists) { From a899633d8c55abb807f66a29846ce85539e84377 Mon Sep 17 00:00:00 2001 From: yousef-alkhrissat Date: Fri, 9 Aug 2024 19:30:06 +0300 Subject: [PATCH 4/7] added default region in otp --- src/auth/dtos/user-otp.dto.ts | 12 +++++++++--- src/auth/services/user-auth.service.ts | 10 +++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/auth/dtos/user-otp.dto.ts b/src/auth/dtos/user-otp.dto.ts index b588cb2..043eebc 100644 --- a/src/auth/dtos/user-otp.dto.ts +++ b/src/auth/dtos/user-otp.dto.ts @@ -1,6 +1,12 @@ import { OtpType } from '../../../libs/common/src/constants/otp-type.enum'; import { ApiProperty } from '@nestjs/swagger'; -import { IsEmail, IsEnum, IsNotEmpty, IsString } from 'class-validator'; +import { + IsEmail, + IsEnum, + IsNotEmpty, + IsOptional, + IsString, +} from 'class-validator'; export class UserOtpDto { @ApiProperty() @@ -14,9 +20,9 @@ export class UserOtpDto { type: OtpType; @ApiProperty() - @IsNotEmpty() + @IsOptional() @IsString() - regionName: string; + regionUuid?: string; } export class VerifyOtpDto extends UserOtpDto { diff --git a/src/auth/services/user-auth.service.ts b/src/auth/services/user-auth.service.ts index fe459cb..085807a 100644 --- a/src/auth/services/user-auth.service.ts +++ b/src/auth/services/user-auth.service.ts @@ -130,9 +130,13 @@ export class UserAuthService { threeDaysAgo.setDate(threeDaysAgo.getDate() - 3); const userExists = await this.userRepository.exists({ where: { - region: { - regionName: data.regionName, - }, + region: data.regionUuid + ? { + uuid: data.regionUuid, + } + : { + regionName: 'United Arab Emirates', + }, email: data.email, isUserVerified: true, }, From 0d852cf0d1f11cdc41f0eb158c0ec9521a610960 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 11 Aug 2024 10:56:47 +0300 Subject: [PATCH 5/7] added cooldown to data --- src/auth/services/user-auth.service.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/auth/services/user-auth.service.ts b/src/auth/services/user-auth.service.ts index 085807a..ef47a5a 100644 --- a/src/auth/services/user-auth.service.ts +++ b/src/auth/services/user-auth.service.ts @@ -169,9 +169,12 @@ export class UserAuthService { const timeSinceLastOtp = differenceInSeconds(now, lastOtp.createdAt); if (timeSinceLastOtp < cooldown) { - throw new BadRequestException( - `Please wait ${cooldown - timeSinceLastOtp} more seconds before requesting a new OTP.`, - ); + throw new BadRequestException({ + message: `Please wait ${cooldown - timeSinceLastOtp} more seconds before requesting a new OTP.`, + data: { + cooldown: cooldown - timeSinceLastOtp, + }, + }); } } const otpCode = Math.floor(100000 + Math.random() * 900000).toString(); From 5825ce01d2d3c1aac4e9bddd36eb86b8c9d0962c Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 11 Aug 2024 11:41:00 +0300 Subject: [PATCH 6/7] added deleted at --- libs/common/src/modules/user-otp/entities/user-otp.entity.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/common/src/modules/user-otp/entities/user-otp.entity.ts b/libs/common/src/modules/user-otp/entities/user-otp.entity.ts index 454a3b1..527133a 100644 --- a/libs/common/src/modules/user-otp/entities/user-otp.entity.ts +++ b/libs/common/src/modules/user-otp/entities/user-otp.entity.ts @@ -1,4 +1,4 @@ -import { Column, Entity } from 'typeorm'; +import { Column, DeleteDateColumn, Entity } from 'typeorm'; import { AbstractEntity } from '../../abstract/entities/abstract.entity'; import { UserOtpDto } from '../dtos'; import { OtpType } from '../../../../src/constants/otp-type.enum'; @@ -27,6 +27,9 @@ export class UserOtpEntity extends AbstractEntity { }) type: OtpType; + @DeleteDateColumn({ nullable: true }) + deletedAt?: Date; + constructor(partial: Partial) { super(); Object.assign(this, partial); From 53799583bbc9ac536dd98f0a40a64bf0ca34d8e1 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 11 Aug 2024 11:46:23 +0300 Subject: [PATCH 7/7] removed region from otp on no regionuuid --- src/auth/services/user-auth.service.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/auth/services/user-auth.service.ts b/src/auth/services/user-auth.service.ts index ef47a5a..03a6b9f 100644 --- a/src/auth/services/user-auth.service.ts +++ b/src/auth/services/user-auth.service.ts @@ -134,9 +134,7 @@ export class UserAuthService { ? { uuid: data.regionUuid, } - : { - regionName: 'United Arab Emirates', - }, + : undefined, email: data.email, isUserVerified: true, },