import { describe, expect, test } from "bun:test"; import { createCaptchaEngine, MemoryCaptchaStore, type CaptchaChallengeGenerator, } from "@wrnexus/captcha/server"; import { ManagedCaptchaService } from "../src/service.ts"; let seed = 11; function randomBytes(length: number): Uint8Array { const output = new Uint8Array(length); for (let index = 0; index < length; index += 1) { seed = (seed * 1103515245 + 12345) >>> 0; output[index] = seed & 255; } return output; } const generator: CaptchaChallengeGenerator = { type: "number", generate: () => ({ type: "number", presentation: "visual", prompt: "Enter 7", answer: "7", answerKind: "text", inputMode: "numeric", }), }; describe("managed CAPTCHA service", () => { test("creates a project and completes the public-to-server flow", async () => { const service = new ManagedCaptchaService({ adminToken: "a-long-admin-token-for-managed-captcha-tests", baseUrl: "https://captcha.test", randomBytes, engineFactory: (project) => createCaptchaEngine({ secret: project.engineSecret, store: new MemoryCaptchaStore(), generators: [generator], defaultType: "number", minCompletionMs: 0, randomBytes, }), }); const project = await service.createProject({ name: "Test", allowedHostnames: ["app.test"] }); const created = await service.handle( new Request("https://captcha.test/v1/challenges", { method: "POST", headers: { origin: "https://app.test", "content-type": "application/json" }, body: JSON.stringify({ siteKey: project.siteKey, action: "signup", type: "number" }), }), ); expect(created.status).toBe(201); const challenge = (await created.json()) as { id: string; provider: string }; expect(challenge.provider).toBe("wrnexus-managed"); const solved = await service.handle( new Request("https://captcha.test/v1/solve", { method: "POST", headers: { origin: "https://app.test", "content-type": "application/json" }, body: JSON.stringify({ challengeId: challenge.id, action: "signup", answer: "7" }), }), ); expect(solved.status).toBe(200); const solution = (await solved.json()) as { responseToken: string }; const verified = await service.handle( new Request("https://captcha.test/v1/verify", { method: "POST", headers: { authorization: `Bearer ${project.secretKey}`, "content-type": "application/json", }, body: JSON.stringify({ responseToken: solution.responseToken, action: "signup", hostname: "app.test", }), }), ); expect(verified.status).toBe(200); const replay = await service.handle( new Request("https://captcha.test/v1/verify", { method: "POST", headers: { authorization: `Bearer ${project.secretKey}`, "content-type": "application/json", }, body: JSON.stringify({ responseToken: solution.responseToken, action: "signup", hostname: "app.test", }), }), ); expect(replay.status).toBe(400); }); });