forked from Yara724/api
YARA-1075
This commit is contained in:
@@ -2092,14 +2092,32 @@ export class RequestManagementService {
|
|||||||
(req.parties[secondIdx].person as any).phoneNumber = phoneNumber;
|
(req.parties[secondIdx].person as any).phoneNumber = phoneNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a valid OTP is already active for this number, return 200 immediately —
|
||||||
|
// no duplicate SMS, no unnecessary write, no error shown to the expert.
|
||||||
|
const canonicalPhoneAdv = normalizeIranMobile(phoneNumber) ?? phoneNumber;
|
||||||
|
const existingUserAdv = await this.userDbService.findOne(
|
||||||
|
buildUserLookupByPhone(canonicalPhoneAdv),
|
||||||
|
);
|
||||||
|
if (existingUserAdv && isOtpExpiryActive(existingUserAdv.otpExpire)) {
|
||||||
|
return {
|
||||||
|
requestId: req._id,
|
||||||
|
publicId: req.publicId,
|
||||||
|
workflow: req.workflow,
|
||||||
|
message: `OTP already sent to ${phoneNumber} and is still valid. Collect the code and call verify-party-otp.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Send OTP to second party — expert collects it from them in person
|
// Send OTP to second party — expert collects it from them in person
|
||||||
try {
|
try {
|
||||||
await this.userAuthService.sendOtpRequest(phoneNumber);
|
await this.userAuthService.sendOtpRequest(phoneNumber);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e?.message?.includes("Wait for expiry")) {
|
if (e?.message?.includes("Wait for expiry")) {
|
||||||
throw new BadRequestException(
|
return {
|
||||||
`(${phoneNumber}): OTP was recently sent. Wait for the expiry time before requesting again.`,
|
requestId: req._id,
|
||||||
);
|
publicId: req.publicId,
|
||||||
|
workflow: req.workflow,
|
||||||
|
message: `OTP already sent to ${phoneNumber} and is still valid. Collect the code and call verify-party-otp.`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@@ -4548,29 +4566,32 @@ export class RequestManagementService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
const sent: string[] = [];
|
const sent: string[] = [];
|
||||||
try {
|
|
||||||
await this.userAuthService.sendOtpRequest(dto.firstPartyPhoneNumber);
|
// Helper: send OTP or silently succeed when a valid OTP already exists.
|
||||||
sent.push(dto.firstPartyPhoneNumber);
|
const sendOrSkipIfActive = async (phone: string): Promise<void> => {
|
||||||
} catch (e: any) {
|
const canonical = normalizeIranMobile(phone) ?? phone;
|
||||||
if (e?.message?.includes("Wait for expiry")) {
|
const existing = await this.userDbService.findOne(
|
||||||
throw new BadRequestException(
|
buildUserLookupByPhone(canonical),
|
||||||
`First party (${dto.firstPartyPhoneNumber}): OTP was recently sent. Wait for the expiry time before requesting again.`,
|
);
|
||||||
);
|
if (existing && isOtpExpiryActive(existing.otpExpire)) {
|
||||||
|
sent.push(phone); // already has a live OTP — treat as sent
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
if (dto.secondPartyPhoneNumber) {
|
|
||||||
try {
|
try {
|
||||||
await this.userAuthService.sendOtpRequest(dto.secondPartyPhoneNumber);
|
await this.userAuthService.sendOtpRequest(phone);
|
||||||
sent.push(dto.secondPartyPhoneNumber);
|
sent.push(phone);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e?.message?.includes("Wait for expiry")) {
|
if (e?.message?.includes("Wait for expiry")) {
|
||||||
throw new BadRequestException(
|
sent.push(phone); // race: sendOtpRequest found it active too — treat as sent
|
||||||
`Second party (${dto.secondPartyPhoneNumber}): OTP was recently sent. Wait for the expiry time before requesting again.`,
|
return;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await sendOrSkipIfActive(dto.firstPartyPhoneNumber);
|
||||||
|
if (dto.secondPartyPhoneNumber) {
|
||||||
|
await sendOrSkipIfActive(dto.secondPartyPhoneNumber);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
sent: true,
|
sent: true,
|
||||||
@@ -4749,32 +4770,34 @@ export class RequestManagementService {
|
|||||||
new Date(event.timestamp) > twoMinutesAgo,
|
new Date(event.timestamp) > twoMinutesAgo,
|
||||||
);
|
);
|
||||||
if (recentlySentToPhone) {
|
if (recentlySentToPhone) {
|
||||||
throw new BadRequestException(
|
return {
|
||||||
`(${phone}): OTP was sent recently. Please wait 2 minutes before requesting again.`,
|
sent: true,
|
||||||
);
|
message: `OTP already sent to ${phone} and is still valid. Collect the code from the party, then call verify-party-otp.`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- DB-level cooldown guard (catches burst/concurrent requests before history is saved) ---
|
// --- DB-level cooldown guard (catches burst/concurrent requests before history is saved) ---
|
||||||
// Read the user's otpExpire directly from the users collection. If a live
|
// Read the user's otpExpire directly from the users collection. If a live
|
||||||
// OTP already exists we return 400 immediately — no SMS call, no DB writes.
|
// OTP already exists return 200 immediately — no duplicate SMS, no DB writes.
|
||||||
const canonicalPhone =
|
const canonicalPhone = normalizeIranMobile(phone) ?? phone;
|
||||||
normalizeIranMobile(phone) ?? phone;
|
|
||||||
const existingUser = await this.userDbService.findOne(
|
const existingUser = await this.userDbService.findOne(
|
||||||
buildUserLookupByPhone(canonicalPhone),
|
buildUserLookupByPhone(canonicalPhone),
|
||||||
);
|
);
|
||||||
if (existingUser && isOtpExpiryActive(existingUser.otpExpire)) {
|
if (existingUser && isOtpExpiryActive(existingUser.otpExpire)) {
|
||||||
throw new BadRequestException(
|
return {
|
||||||
`(${phone}): OTP was sent recently. Please wait before requesting again.`,
|
sent: true,
|
||||||
);
|
message: `OTP already sent to ${phone} and is still valid. Collect the code from the party, then call verify-party-otp.`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.userAuthService.sendOtpRequest(phone);
|
await this.userAuthService.sendOtpRequest(phone);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e?.message?.includes("Wait for expiry")) {
|
if (e?.message?.includes("Wait for expiry")) {
|
||||||
throw new BadRequestException(
|
return {
|
||||||
`(${phone}): OTP was recently sent. Wait for the expiry time before requesting again.`,
|
sent: true,
|
||||||
);
|
message: `OTP already sent to ${phone} and is still valid. Collect the code from the party, then call verify-party-otp.`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user