import { describe, it, expect } from "vitest"; import { generateSecret, generateSync } from "otplib"; import { hashPassword, verifyPassword, verifyTotp, issueJwt, verifyJwt, login, type AuthConfig, } from "../src/api/auth.js"; describe("password (scrypt)", () => { it("vérifie un mot de passe correct et rejette un faux", () => { const h = hashPassword("s3cr3t!"); expect(verifyPassword("s3cr3t!", h)).toBe(true); expect(verifyPassword("wrong", h)).toBe(false); }); it("rejette un hash malformé", () => { expect(verifyPassword("x", "pasunhash")).toBe(false); }); }); describe("TOTP", () => { it("valide un code généré pour le secret", () => { const secret = generateSecret(); const code = generateSync({ secret: secret }); expect(verifyTotp(code, secret)).toBe(true); expect(verifyTotp("000000", secret)).toBe(false); }); }); const cfg = (): AuthConfig => ({ adminUser: "kantin", adminPasswordHash: hashPassword("pw"), totpSecret: generateSecret(), jwtSecret: "a-very-long-jwt-secret-value-32+chars", }); describe("JWT", () => { it("émet et vérifie un JWT", async () => { const c = cfg(); const token = await issueJwt(c); expect(await verifyJwt(token, c.jwtSecret)).toBe("kantin"); }); it("rejette un JWT avec mauvais secret", async () => { const c = cfg(); const token = await issueJwt(c); expect(await verifyJwt(token, "autre-secret-completement-different")).toBeNull(); }); }); describe("login (mdp + TOTP, tout-ou-rien)", () => { it("réussit avec les bons facteurs", async () => { const c = cfg(); const token = await login(c, { user: "kantin", password: "pw", totp: generateSync({ secret: c.totpSecret }), }); expect(token).not.toBeNull(); }); it("échoue si un seul facteur est faux", async () => { const c = cfg(); const good = generateSync({ secret: c.totpSecret }); expect(await login(c, { user: "kantin", password: "bad", totp: good })).toBeNull(); expect(await login(c, { user: "kantin", password: "pw", totp: "000000" })).toBeNull(); expect(await login(c, { user: "intrus", password: "pw", totp: good })).toBeNull(); }); });