spb/phi-conseil
Public
1import { describe, expect, it } from "vitest";2import {3 createMemoryRateLimiter,4 createDedupe,5 clientIp,6 fingerprint,7 contentSecurityPolicy,8} from "@/lib/security";910describe("limitation de débit", () => {11 it("bloque après N requêtes dans la fenêtre puis libère", () => {12 const rl = createMemoryRateLimiter(3, 60);13 const t0 = 1_000_000;14 expect(rl.check("a", t0).allowed).toBe(true);15 expect(rl.check("a", t0 + 1).allowed).toBe(true);16 expect(rl.check("a", t0 + 2).allowed).toBe(true);17 const blocked = rl.check("a", t0 + 3);18 expect(blocked.allowed).toBe(false);19 expect(blocked.retryAfterS).toBeGreaterThan(0);20 expect(rl.check("b", t0 + 3).allowed).toBe(true);21 expect(rl.check("a", t0 + 61_000).allowed).toBe(true);22 });23});2425describe("dédoublonnage", () => {26 it("signale un doublon dans la fenêtre seulement", () => {27 const d = createDedupe(10);28 expect(d.isDuplicate("k", 0)).toBe(false);29 expect(d.isDuplicate("k", 5_000)).toBe(true);30 expect(d.isDuplicate("k", 20_000)).toBe(false);31 });32});3334describe("utilitaires", () => {35 it("lit la première IP de X-Forwarded-For", () => {36 expect(clientIp(new Headers({ "x-forwarded-for": "203.0.113.5, 10.0.0.1" }))).toBe(37 "203.0.113.5",38 );39 expect(clientIp(new Headers())).toBe("unknown");40 });41 it("produit une empreinte stable non réversible", () => {42 expect(fingerprint("a")).toBe(fingerprint("a"));43 expect(fingerprint("a")).not.toBe(fingerprint("b"));44 expect(fingerprint("a")).toHaveLength(12);45 });46 it("la CSP interdit l'intégration dans une iframe et les objets", () => {47 const csp = contentSecurityPolicy();48 expect(csp).toContain("frame-ancestors 'none'");49 expect(csp).toContain("object-src 'none'");50 });51});52