Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 87x 2x 85x 85x 85x 85x 85x 85x 47x 47x 47x 1504x 11x 10x 10x 518x 10x 8x 8x | import { WHATSAPP_OTP_LENGTH } from "@interioring/utils/constants/whatsapp";
export function generateOtp(length: number = WHATSAPP_OTP_LENGTH): string {
if (length < 4 || length > 10) {
throw new Error("OTP length must be between 4 and 10");
}
const min = 10 ** (length - 1);
const range = 9 * min;
const buf = new Uint8Array(4);
crypto.getRandomValues(buf);
const n = new DataView(buf.buffer).getUint32(0);
return String(min + (n % range));
}
export async function hashOtp(code: string): Promise<string> {
const data = new TextEncoder().encode(code);
const digest = await crypto.subtle.digest("SHA-256", data);
return [...new Uint8Array(digest)]
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
}
export function constantTimeEqual(a: string, b: string): boolean {
if (a.length !== b.length) return false;
let result = 0;
for (let i = 0; i < a.length; i++) {
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
}
return result === 0;
}
export async function verifyOtp(
candidate: string,
storedHash: string,
): Promise<boolean> {
const candidateHash = await hashOtp(candidate);
return constantTimeEqual(candidateHash, storedHash);
}
|