1import { describe, expect, it } from "vitest"; 2import { 3 hashPassword, 4 passwordHasher, 5 passwordPolicy, 6 storedHashAlgorithm, 7 verifyPassword 8} from "./passwords.js"; 9 10describe("passwordPolicy", () => { 11 it("accepts a valid password", () => expect(passwordPolicy("Password123").ok).toBe(true)); 12 it("rejects short", () => { 13 const r = passwordPolicy("a1bcdef"); 14 expect(r.ok).toBe(false); 15 expect(r.errors.some((e) => /10/.test(e))).toBe(true); 16 }); 17 it("rejects no letter", () => expect(passwordPolicy("12345678901").ok).toBe(false)); 18 it("rejects no number", () => expect(passwordPolicy("abcdefghijkl").ok).toBe(false)); 19 it("rejects overlong", () => expect(passwordPolicy("a1" + "x".repeat(71)).ok).toBe(false)); 20}); 21 22describe("hash/verify", () => { 23 it("roundtrips", async () => { 24 const h = await hashPassword("Password123"); 25 expect(h.startsWith("$factory$pbkdf2-sha512$12$")).toBe(true); 26 await expect(verifyPassword("Password123", h)).resolves.toBe(true); 27 }); 28 it("rejects wrong password", async () => { 29 const h = await hashPassword("Password123"); 30 await expect(verifyPassword("Password124", h)).resolves.toBe(false); 31 }); 32 it("salts are unique", async () => { 33 const a = await hashPassword("Password123"); 34 const b = await hashPassword("Password123"); 35 expect(a).not.toBe(b); 36 }); 37 it("rejects malformed stored", async () => { 38 await expect(verifyPassword("x", "garbage")).resolves.toBe(false); 39 await expect(verifyPassword("x", "$factory$pbkdf2-sha512$99$!!$!!")).resolves.toBe(false); 40 }); 41 it("detects algorithms", () => { 42 expect(storedHashAlgorithm("$2b$12$Cn4mHs5Q9KZvJ3pL8xYzZuGf7Wq1aB2cD3eF4gH5iJ6kL7mN8oP9q")).toBe("bcrypt"); 43 expect(storedHashAlgorithm("$factory$pbkdf2-sha512$12$aa$bb")).toBe("pbkdf2-sha512"); 44 expect(storedHashAlgorithm("???")).toBe("unknown"); 45 }); 46 it("exposes the algorithm name", () => expect(passwordHasher.algorithm).toBe("pbkdf2-sha512")); 47}); 48