mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-15 10:25:23 +00:00
Merge pull request #73 from SyncrowIOT/SP-340-implement-send-otp-endpoint
otp cooldown
This commit is contained in:
4
libs/common/src/helper/differenceInSeconds.ts
Normal file
4
libs/common/src/helper/differenceInSeconds.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export function differenceInSeconds(date1: Date, date2: Date): number {
|
||||
const diffInMilliseconds = date1.getTime() - date2.getTime();
|
||||
return Math.floor(diffInMilliseconds / 1000);
|
||||
}
|
@ -1,4 +1,11 @@
|
||||
import { Column, Entity, ManyToOne, OneToMany, Unique } from 'typeorm';
|
||||
import {
|
||||
Column,
|
||||
DeleteDateColumn,
|
||||
Entity,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
Unique,
|
||||
} from 'typeorm';
|
||||
import {
|
||||
UserDto,
|
||||
UserNotificationDto,
|
||||
@ -155,6 +162,9 @@ export class UserOtpEntity extends AbstractEntity<UserOtpDto> {
|
||||
})
|
||||
type: OtpType;
|
||||
|
||||
@DeleteDateColumn({ nullable: true })
|
||||
deletedAt?: Date;
|
||||
|
||||
constructor(partial: Partial<UserOtpEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
|
@ -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()
|
||||
@ -12,6 +18,11 @@ export class UserOtpDto {
|
||||
@IsEnum(OtpType)
|
||||
@IsNotEmpty()
|
||||
type: OtpType;
|
||||
|
||||
@ApiProperty()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
regionUuid?: string;
|
||||
}
|
||||
|
||||
export class VerifyOtpDto extends UserOtpDto {
|
||||
|
@ -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 {
|
||||
@ -114,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 });
|
||||
}
|
||||
@ -124,7 +126,55 @@ export class UserAuthService {
|
||||
}
|
||||
|
||||
async generateOTP(data: UserOtpDto): Promise<string> {
|
||||
await this.otpRepository.delete({ email: data.email, type: data.type });
|
||||
const threeDaysAgo = new Date();
|
||||
threeDaysAgo.setDate(threeDaysAgo.getDate() - 3);
|
||||
const userExists = await this.userRepository.exists({
|
||||
where: {
|
||||
region: data.regionUuid
|
||||
? {
|
||||
uuid: data.regionUuid,
|
||||
}
|
||||
: undefined,
|
||||
email: data.email,
|
||||
isUserVerified: true,
|
||||
},
|
||||
});
|
||||
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,
|
||||
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 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();
|
||||
const expiryTime = new Date();
|
||||
expiryTime.setMinutes(expiryTime.getMinutes() + 1);
|
||||
|
Reference in New Issue
Block a user