import { exports } from "cloudflare:workers"; import { describe, expect, it } from "vitest"; import { ISSUER, testHeaders } from "./helpers"; const SELF = exports.default; // remoteIp is the CF-Connecting-IP gate for every tessera-owned public // flow that runs Turnstile or rate-limit. It must: // - return the CF-Connecting-IP value when present // - reject 400 when absent (no fallback to "unknown" or X-Forwarded-For) // - ignore X-Forwarded-For entirely (forgeable on non-Cloudflare paths) describe("remoteIp fail-closed contract", () => { it("400 missing_client_ip when CF-Connecting-IP is absent on /api/sign-in", async () => { const res = await SELF.fetch(`${ISSUER}/api/sign-in`, { method: "POST", headers: testHeaders(), body: JSON.stringify({ email: "x@example.com", password: "y", turnstileToken: "z" }), }); expect(res.status).toBe(400); const body = (await res.json()) as { error?: string }; expect(body.error).toBe("missing_client_ip"); }); it("ignores X-Forwarded-For (forgeable; not the Cloudflare contract)", async () => { const res = await SELF.fetch(`${ISSUER}/api/sign-in`, { method: "POST", headers: testHeaders({ "X-Forwarded-For": "1.2.3.4" }), body: JSON.stringify({ email: "x@example.com", password: "y", turnstileToken: "z" }), }); expect(res.status).toBe(400); const body = (await res.json()) as { error?: string }; expect(body.error).toBe("missing_client_ip"); }); it("accepts CF-Connecting-IP and lets the request progress past the IP gate", async () => { // Without a seeded user this still 401s on the credential check, but // the gate has been crossed — proves remoteIp returned a real value. const res = await SELF.fetch(`${ISSUER}/api/sign-in`, { method: "POST", headers: testHeaders({ "CF-Connecting-IP": "203.0.113.7" }), body: JSON.stringify({ email: "ghost@example.com", password: "y", turnstileToken: "z" }), }); // Whatever the downstream status, it is not the 400 missing_client_ip. expect(res.status).not.toBe(400); }); it("400 missing_client_ip on POST /api/invite/:token (invite flow uses remoteIp too)", async () => { const res = await SELF.fetch(`${ISSUER}/api/invite/never-existed`, { method: "POST", headers: testHeaders(), body: JSON.stringify({ name: "x", password: "y", turnstileToken: "z" }), }); expect(res.status).toBe(400); const body = (await res.json()) as { error?: string }; expect(body.error).toBe("missing_client_ip"); }); });