import { describe, expect, it } from "vitest"; import { hashPassword, passwordHasher, passwordPolicy, storedHashAlgorithm, verifyPassword } from "./passwords.js"; describe("passwordPolicy", () => { it("accepts a valid password", () => expect(passwordPolicy("Password123").ok).toBe(true)); it("rejects short", () => { const r = passwordPolicy("a1bcdef"); expect(r.ok).toBe(false); expect(r.errors.some((e) => /10/.test(e))).toBe(true); }); it("rejects no letter", () => expect(passwordPolicy("12345678901").ok).toBe(false)); it("rejects no number", () => expect(passwordPolicy("abcdefghijkl").ok).toBe(false)); it("rejects overlong", () => expect(passwordPolicy("a1" + "x".repeat(71)).ok).toBe(false)); }); describe("hash/verify", () => { it("roundtrips", async () => { const h = await hashPassword("Password123"); expect(h.startsWith("$factory$pbkdf2-sha512$12$")).toBe(true); await expect(verifyPassword("Password123", h)).resolves.toBe(true); }); it("rejects wrong password", async () => { const h = await hashPassword("Password123"); await expect(verifyPassword("Password124", h)).resolves.toBe(false); }); it("salts are unique", async () => { const a = await hashPassword("Password123"); const b = await hashPassword("Password123"); expect(a).not.toBe(b); }); it("rejects malformed stored", async () => { await expect(verifyPassword("x", "garbage")).resolves.toBe(false); await expect(verifyPassword("x", "$factory$pbkdf2-sha512$99$!!$!!")).resolves.toBe(false); }); it("detects algorithms", () => { expect(storedHashAlgorithm("$2b$12$Cn4mHs5Q9KZvJ3pL8xYzZuGf7Wq1aB2cD3eF4gH5iJ6kL7mN8oP9q")).toBe("bcrypt"); expect(storedHashAlgorithm("$factory$pbkdf2-sha512$12$aa$bb")).toBe("pbkdf2-sha512"); expect(storedHashAlgorithm("???")).toBe("unknown"); }); it("exposes the algorithm name", () => expect(passwordHasher.algorithm).toBe("pbkdf2-sha512")); });