diff --git a/.env.example b/.env.example index 7edc6d9..1575ba6 100644 --- a/.env.example +++ b/.env.example @@ -60,6 +60,7 @@ SMS_PROVIDER = SMS_API_KEY = AUTH_SMS_TEMPLATE = EXP_OTP_TIME = +FAKE_OTP = # --------------------------------------------- # ⚙️ Application Features / Flags diff --git a/src/auth/auth-services/user.auth.service.ts b/src/auth/auth-services/user.auth.service.ts index 3555f6f..3d1ba7f 100644 --- a/src/auth/auth-services/user.auth.service.ts +++ b/src/auth/auth-services/user.auth.service.ts @@ -13,6 +13,8 @@ import { } from "src/helpers/iran-mobile"; import { computeOtpExpireMs, + FAKE_OTP_CODE, + isFakeOtpEnabled, isOtpExpiryActive, readOtpExpireMinutesFromEnv, } from "src/helpers/user-otp-expiry"; @@ -109,7 +111,7 @@ export class UserAuthService { const userExist = await this.userDbService.findOne( buildUserLookupByPhone(canonicalMobile), ); - const otp = this.otpCreator.create(); + const otp = this.createOtpForRequest(); const hashOtp = await this.hashService.hash(otp); const expireMinutes = readOtpExpireMinutesFromEnv(); const nowMs = Date.now(); @@ -158,7 +160,23 @@ export class UserAuthService { return new LoginDtoRs(userExist); } + private createOtpForRequest(): string { + if (isFakeOtpEnabled()) { + this.logger.warn( + "FAKE_OTP=true — using fixed dev OTP; SMS provider is not called", + ); + return FAKE_OTP_CODE; + } + return this.otpCreator.create(); + } + private async smsSender(otp: string, mobile: string) { + if (isFakeOtpEnabled()) { + this.logger.log( + `FAKE_OTP=true — skipped SMS for phone=${mobile} (use OTP ${FAKE_OTP_CODE})`, + ); + return; + } const ok = await this.smsOrchestrationService.sendAuthOtp( mobile, otp, diff --git a/src/helpers/user-otp-expiry.ts b/src/helpers/user-otp-expiry.ts index 43c5f03..85352bd 100644 --- a/src/helpers/user-otp-expiry.ts +++ b/src/helpers/user-otp-expiry.ts @@ -41,3 +41,10 @@ export function readOtpExpireMinutesFromEnv(): number { const raw = Number(process.env.EXP_OTP_TIME ?? "2"); return Number.isFinite(raw) && raw > 0 ? raw : 2; } + +/** Dev-only: skip SMS provider and accept a fixed OTP for any mobile. */ +export const FAKE_OTP_CODE = "12345"; + +export function isFakeOtpEnabled(): boolean { + return process.env.FAKE_OTP === "true"; +}