import { describe, expect, test } from "bun:test"; import { captchaPageGate } from "../src/middleware.ts"; import type { CaptchaEngine } from "../src/types.ts"; function fakeEngine(): CaptchaEngine { return { provider: "self-hosted", basePath: "/api/captcha", async create() { throw new Error("not used"); }, async verify() { throw new Error("not used"); }, async verifyResponseToken(input) { return input.responseToken === "verified-token" ? { success: true, provider: "self-hosted", action: input.action } : { success: false, provider: "self-hosted", action: input.action, code: "invalid-input" }; }, async renderAudio() { return undefined; }, async gc() {}, }; } function sessionFixture() { const values = new Map(); return { id: () => "session-1", get(key: string): T | undefined { return values.get(key) as T | undefined; }, set(key: string, value: T): void { values.set(key, value); }, delete(key: string): void { values.delete(key); }, }; } describe("CAPTCHA page gate", () => { test("accepts a verified form token and grants the protected route", async () => { const session = sessionFixture(); const gate = captchaPageGate({ action: "protected-page-access", engine: fakeEngine(), challengePath: "/captcha", policy: { mode: "session", verifiedForMs: 15 * 60_000, routeGroups: ["/protected"], }, }); const body = new URLSearchParams({ returnTo: "/protected", "wrn-captcha-response": "verified-token", }); const request = new Request("https://example.test/api/page-grant", { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body, }); const context = { req: request, url: new URL(request.url), session, ip: "127.0.0.1", locals: {}, }; const granted = await gate(context, () => Response.redirect("https://example.test/protected", 303), ); expect(granted.status).toBe(303); const protectedRequest = new Request("https://example.test/protected"); const protectedContext = { ...context, req: protectedRequest, url: new URL(protectedRequest.url), locals: {}, }; const allowed = await gate(protectedContext, () => new Response("unlocked")); expect(await allowed.text()).toBe("unlocked"); }); });