chore: add loger

This commit is contained in:
Nathnael
2026-07-03 11:48:39 +00:00
parent 2d71f24937
commit 37ec1c40ab

View File

@@ -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,51 +118,34 @@ 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 };
} }
} }