import assert from "node:assert/strict"; import { describe, it } from "node:test"; import { VERIFICATION_CODE_LENGTH, hashPhoneNumber, hashVerificationCode, mintVerificationCode, verificationCodeMatches, } from "../../src/util/smsVerificationCode.js"; const SECRET = "test-sms-code-secret"; describe("mintVerificationCode", () => { it("always produces six digits, leading zeros included", () => { for (let i = 0; i < 2000; i += 1) { const code = mintVerificationCode(); assert.equal(code.length, VERIFICATION_CODE_LENGTH); assert.match(code, /^\d{6}$/); } }); it("does not return the same code every call", () => { const seen = new Set(); for (let i = 0; i < 200; i += 1) seen.add(mintVerificationCode()); assert.ok(seen.size > 100, `expected varied codes, got ${seen.size}`); }); }); describe("hashVerificationCode", () => { it("is stable for one secret and different across secrets", () => { assert.equal( hashVerificationCode("483920", SECRET), hashVerificationCode("483920", SECRET) ); assert.notEqual( hashVerificationCode("483920", SECRET), hashVerificationCode("483920", "other-secret") ); }); it("never contains the plaintext code", () => { assert.equal(hashVerificationCode("483920", SECRET).includes("483920"), false); }); }); describe("hashPhoneNumber", () => { it("is stable per number and does not contain the number", () => { const hash = hashPhoneNumber("+15555550123", SECRET); assert.equal(hash, hashPhoneNumber("+15555550123", SECRET)); assert.notEqual(hash, hashPhoneNumber("+15555550124", SECRET)); assert.equal(hash.includes("5555550123"), false); }); }); describe("verificationCodeMatches", () => { it("accepts the matching code and rejects every near miss", () => { const stored = hashVerificationCode("483920", SECRET); assert.equal(verificationCodeMatches("483920", stored, SECRET), true); assert.equal(verificationCodeMatches("483921", stored, SECRET), false); assert.equal(verificationCodeMatches("48392", stored, SECRET), false); assert.equal(verificationCodeMatches("", stored, SECRET), false); assert.equal(verificationCodeMatches("483920", stored, "wrong"), false); }); it("compares full hashes, so a shared prefix is not a partial match", () => { const stored = hashVerificationCode("111111", SECRET); const truncated = stored.slice(0, 10); assert.equal(verificationCodeMatches("111111", truncated, SECRET), false); }); });