mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 22:18:12 +00:00
chore: add loger
This commit is contained in:
@@ -1,9 +1,6 @@
|
|||||||
// otp.service.ts
|
// otp.service.ts
|
||||||
|
|
||||||
import {
|
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
|
||||||
BadRequestException,
|
|
||||||
Injectable,
|
|
||||||
} from "@nestjs/common";
|
|
||||||
|
|
||||||
import { OtpRepository } from "./otp.repository";
|
import { OtpRepository } from "./otp.repository";
|
||||||
|
|
||||||
@@ -16,20 +13,19 @@ export type OtpTarget = { phone?: string; email?: string };
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OtpService {
|
export class OtpService {
|
||||||
|
logger = new Logger(OtpService.name);
|
||||||
constructor(
|
constructor(
|
||||||
private readonly otpRepository: OtpRepository,
|
private readonly otpRepository: OtpRepository,
|
||||||
private readonly smsClient: SmsClientService,
|
private readonly smsClient: SmsClientService,
|
||||||
private readonly emailClient: EmailClientService
|
private readonly emailClient: EmailClientService,
|
||||||
) {}
|
) { }
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Generate OTP
|
// Generate OTP
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
generateOtp(): string {
|
generateOtp(): string {
|
||||||
return Math.floor(
|
return Math.floor(100000 + Math.random() * 900000).toString();
|
||||||
100000 + Math.random() * 900000
|
|
||||||
).toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -44,23 +40,14 @@ export class OtpService {
|
|||||||
const otp = this.generateOtp();
|
const otp = this.generateOtp();
|
||||||
|
|
||||||
// find existing row for this channel
|
// find existing row for this channel
|
||||||
const existing =
|
const existing = await this.otpRepository.findByTarget(target);
|
||||||
await this.otpRepository.findByTarget(
|
|
||||||
target
|
|
||||||
);
|
|
||||||
|
|
||||||
// update existing otp
|
// update existing otp
|
||||||
if (existing) {
|
if (existing) {
|
||||||
await this.otpRepository.updateOtp(
|
await this.otpRepository.updateOtp(existing, otp);
|
||||||
existing,
|
|
||||||
otp
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// create new otp
|
// create new otp
|
||||||
await this.otpRepository.createOtp(
|
await this.otpRepository.createOtp(target, otp);
|
||||||
target,
|
|
||||||
otp
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.email) {
|
if (target.email) {
|
||||||
@@ -78,18 +65,16 @@ export class OtpService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.logger.log(`OTP send for ${target.email ?? target.phone}: ${otp}`);
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
|
||||||
message:
|
message: "OTP sent successfully",
|
||||||
"OTP sent successfully",
|
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
||||||
throw new BadRequestException(
|
throw new BadRequestException("Failed to send OTP");
|
||||||
"Failed to send OTP"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,44 +82,31 @@ export class OtpService {
|
|||||||
// Verify OTP
|
// Verify OTP
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
async verifyOtp(
|
async verifyOtp(target: OtpTarget, otp: string) {
|
||||||
target: OtpTarget,
|
|
||||||
otp: string
|
|
||||||
) {
|
|
||||||
// find the channel's row
|
// find the channel's row
|
||||||
const otpData =
|
const otpData = await this.otpRepository.findByTarget(target);
|
||||||
await this.otpRepository.findByTarget(
|
|
||||||
target
|
|
||||||
);
|
|
||||||
|
|
||||||
// not found
|
// not found
|
||||||
if (!otpData) {
|
if (!otpData) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
target.email
|
target.email ? "Email address not found" : "Phone number not found",
|
||||||
? "Email address not found"
|
|
||||||
: "Phone number not found"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// invalid otp
|
// invalid otp
|
||||||
if (otpData.otp !== otp) {
|
if (otpData.otp !== otp) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException("Invalid OTP");
|
||||||
"Invalid OTP"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark verified
|
// mark verified
|
||||||
await this.otpRepository.markVerified(
|
await this.otpRepository.markVerified(otpData);
|
||||||
otpData
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
|
||||||
message:
|
message: target.email
|
||||||
target.email
|
? "Email verified successfully"
|
||||||
? "Email verified successfully"
|
: "Phone verified successfully",
|
||||||
: "Phone verified successfully",
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,50 +118,33 @@ export class OtpService {
|
|||||||
// contract signature). Unlike verifyOtp above — which marks a phone verified
|
// contract signature). Unlike verifyOtp above — which marks a phone verified
|
||||||
// and leaves the code in place — this enforces a short TTL and consumes the
|
// and leaves the code in place — this enforces a short TTL and consumes the
|
||||||
// code on success so it can never be replayed.
|
// code on success so it can never be replayed.
|
||||||
private readonly ACTION_OTP_TTL_MS =
|
private readonly ACTION_OTP_TTL_MS = 5 * 60 * 1000;
|
||||||
5 * 60 * 1000;
|
|
||||||
|
|
||||||
async verifyOtpForAction(
|
async verifyOtpForAction(phone: string, otp: string) {
|
||||||
phone: string,
|
const otpData = await this.otpRepository.findByPhone(phone);
|
||||||
otp: string
|
|
||||||
) {
|
|
||||||
const otpData =
|
|
||||||
await this.otpRepository.findByPhone(
|
|
||||||
phone
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!otpData) {
|
if (!otpData) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
"No verification code was requested for this phone"
|
"No verification code was requested for this phone",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ageMs =
|
const ageMs = Date.now() - new Date(otpData.updatedAt).getTime();
|
||||||
Date.now() -
|
|
||||||
new Date(
|
|
||||||
otpData.updatedAt
|
|
||||||
).getTime();
|
|
||||||
|
|
||||||
if (ageMs > this.ACTION_OTP_TTL_MS) {
|
if (ageMs > this.ACTION_OTP_TTL_MS) {
|
||||||
await this.otpRepository.deleteOtp(
|
await this.otpRepository.deleteOtp(otpData);
|
||||||
otpData
|
|
||||||
);
|
|
||||||
|
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
"Verification code has expired. Request a new one."
|
"Verification code has expired. Request a new one.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (otpData.otp !== otp) {
|
if (otpData.otp !== otp) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException("Invalid verification code");
|
||||||
"Invalid verification code"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// single-use: consume on success
|
// single-use: consume on success
|
||||||
await this.otpRepository.deleteOtp(
|
await this.otpRepository.deleteOtp(otpData);
|
||||||
otpData
|
|
||||||
);
|
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user