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 {
|
import {
|
||||||
UserDto,
|
UserDto,
|
||||||
UserNotificationDto,
|
UserNotificationDto,
|
||||||
@ -155,6 +162,9 @@ export class UserOtpEntity extends AbstractEntity<UserOtpDto> {
|
|||||||
})
|
})
|
||||||
type: OtpType;
|
type: OtpType;
|
||||||
|
|
||||||
|
@DeleteDateColumn({ nullable: true })
|
||||||
|
deletedAt?: Date;
|
||||||
|
|
||||||
constructor(partial: Partial<UserOtpEntity>) {
|
constructor(partial: Partial<UserOtpEntity>) {
|
||||||
super();
|
super();
|
||||||
Object.assign(this, partial);
|
Object.assign(this, partial);
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
import { OtpType } from '../../../libs/common/src/constants/otp-type.enum';
|
import { OtpType } from '../../../libs/common/src/constants/otp-type.enum';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
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 {
|
export class UserOtpDto {
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@ -12,6 +18,11 @@ export class UserOtpDto {
|
|||||||
@IsEnum(OtpType)
|
@IsEnum(OtpType)
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
type: OtpType;
|
type: OtpType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
regionUuid?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class VerifyOtpDto extends UserOtpDto {
|
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 { OtpType } from '../../../libs/common/src/constants/otp-type.enum';
|
||||||
import { UserEntity } from '../../../libs/common/src/modules/user/entities/user.entity';
|
import { UserEntity } from '../../../libs/common/src/modules/user/entities/user.entity';
|
||||||
import * as argon2 from 'argon2';
|
import * as argon2 from 'argon2';
|
||||||
|
import { differenceInSeconds } from '@app/common/helper/differenceInSeconds';
|
||||||
|
import { LessThan, MoreThan } from 'typeorm';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserAuthService {
|
export class UserAuthService {
|
||||||
@ -114,7 +116,7 @@ export class UserAuthService {
|
|||||||
async deleteUser(uuid: string) {
|
async deleteUser(uuid: string) {
|
||||||
const user = await this.findOneById(uuid);
|
const user = await this.findOneById(uuid);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new BadRequestException('User does not found');
|
throw new BadRequestException('User not found');
|
||||||
}
|
}
|
||||||
return await this.userRepository.update({ uuid }, { isActive: false });
|
return await this.userRepository.update({ uuid }, { isActive: false });
|
||||||
}
|
}
|
||||||
@ -124,7 +126,55 @@ export class UserAuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async generateOTP(data: UserOtpDto): Promise<string> {
|
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 otpCode = Math.floor(100000 + Math.random() * 900000).toString();
|
||||||
const expiryTime = new Date();
|
const expiryTime = new Date();
|
||||||
expiryTime.setMinutes(expiryTime.getMinutes() + 1);
|
expiryTime.setMinutes(expiryTime.getMinutes() + 1);
|
||||||
|
Reference in New Issue
Block a user