import { beforeAll, describe, expect, it } from "vitest"; import { hashPassword, passwordPolicyError, verifyPassword } from "../lib/auth/password.ts"; import { createSession, destroyAllSessions, userForToken } from "../lib/auth/session.ts"; import { db, run } from "../lib/db/index.ts"; import { rateLimit } from "../lib/auth/rate-limit.ts"; describe("Mots de passe", () => { it("hache et vérifie avec bcrypt", () => { const h = hashPassword("MonMotDePasseSolide!"); expect(h).not.toContain("MonMotDePasse"); expect(verifyPassword("MonMotDePasseSolide!", h)).toBe(true); expect(verifyPassword("mauvais", h)).toBe(false); }); it("refuse admin123 comme mot de passe permanent", () => { expect(passwordPolicyError("admin123")).toBeTruthy(); expect(passwordPolicyError("Admin123")).toBeTruthy(); }); it("exige 10 caractères", () => { expect(passwordPolicyError("court")).toBeTruthy(); expect(passwordPolicyError("assez-long-2026")).toBeNull(); }); }); describe("Sessions", () => { let userId: number; beforeAll(() => { db(); const r = run( "INSERT INTO users (username, display_name, password_hash) VALUES ('test-session', 'Test', 'x')" ); userId = Number(r.lastInsertRowid); }); it("le jeton n'est jamais stocké en clair (haché en BD)", () => { const { token } = createSession(userId); const raw = db().prepare("SELECT token_hash FROM sessions WHERE user_id = ?").all(userId) as { token_hash: string }[]; expect(raw.some((r) => r.token_hash === token)).toBe(false); expect(userForToken(token)?.username).toBe("test-session"); }); it("un jeton inconnu ou révoqué ne donne aucun accès", () => { const { token } = createSession(userId); destroyAllSessions(userId); expect(userForToken(token)).toBeNull(); expect(userForToken("0".repeat(64))).toBeNull(); }); }); describe("Limitation de débit", () => { it("bloque après le maximum de tentatives dans la fenêtre", () => { const key = "test:" + Math.random(); for (let i = 0; i < 5; i++) expect(rateLimit(key, 5, 60_000).ok).toBe(true); const blocked = rateLimit(key, 5, 60_000); expect(blocked.ok).toBe(false); expect(blocked.retryAfterS).toBeGreaterThan(0); }); });