69 lines
2.9 KiB
TypeScript
69 lines
2.9 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { test } from "node:test";
|
|
import { verifyTurnstileToken } from "../lib/turnstile/server";
|
|
|
|
const request = new Request("https://anouma.org/api/test", {
|
|
headers: { "x-forwarded-for": "203.0.113.10" },
|
|
});
|
|
|
|
test("Turnstile verification fails closed for missing configuration or token", async () => {
|
|
const originalFetch = globalThis.fetch;
|
|
let called = false;
|
|
globalThis.fetch = async () => {
|
|
called = true;
|
|
throw new Error("fetch must not run");
|
|
};
|
|
try {
|
|
delete process.env.TURNSTILE_SECRET_KEY;
|
|
process.env.TURNSTILE_HOSTNAMES = "anouma.org";
|
|
assert.equal(await verifyTurnstileToken("token", "contact", request), false);
|
|
process.env.TURNSTILE_SECRET_KEY = "test-secret";
|
|
assert.equal(await verifyTurnstileToken(undefined, "contact", request), false);
|
|
assert.equal(called, false);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
delete process.env.TURNSTILE_SECRET_KEY;
|
|
delete process.env.TURNSTILE_HOSTNAMES;
|
|
}
|
|
});
|
|
|
|
test("Turnstile verification accepts the expected action and hostname", async () => {
|
|
const originalFetch = globalThis.fetch;
|
|
let receivedBody = "";
|
|
globalThis.fetch = async (_input, init) => {
|
|
receivedBody = String(init?.body ?? "");
|
|
return new Response(JSON.stringify({ success: true, action: "contact", hostname: "anouma.org" }), { status: 200 });
|
|
};
|
|
try {
|
|
process.env.TURNSTILE_SECRET_KEY = "test-secret";
|
|
process.env.TURNSTILE_HOSTNAMES = "anouma.org";
|
|
assert.equal(await verifyTurnstileToken("fresh-token", "contact", request), true);
|
|
const params = new URLSearchParams(receivedBody);
|
|
assert.equal(params.get("response"), "fresh-token");
|
|
assert.equal(params.get("secret"), "test-secret");
|
|
assert.equal(params.get("remoteip"), "203.0.113.10");
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
delete process.env.TURNSTILE_SECRET_KEY;
|
|
delete process.env.TURNSTILE_HOSTNAMES;
|
|
}
|
|
});
|
|
|
|
test("Turnstile verification rejects action, hostname, and upstream failures", async () => {
|
|
const originalFetch = globalThis.fetch;
|
|
process.env.TURNSTILE_SECRET_KEY = "test-secret";
|
|
process.env.TURNSTILE_HOSTNAMES = "anouma.org";
|
|
try {
|
|
globalThis.fetch = async () => new Response(JSON.stringify({ success: true, action: "login", hostname: "anouma.org" }), { status: 200 });
|
|
assert.equal(await verifyTurnstileToken("token", "contact", request), false);
|
|
globalThis.fetch = async () => new Response(JSON.stringify({ success: true, action: "contact", hostname: "evil.example" }), { status: 200 });
|
|
assert.equal(await verifyTurnstileToken("token", "contact", request), false);
|
|
globalThis.fetch = async () => new Response("upstream error", { status: 503 });
|
|
assert.equal(await verifyTurnstileToken("token", "contact", request), false);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
delete process.env.TURNSTILE_SECRET_KEY;
|
|
delete process.env.TURNSTILE_HOSTNAMES;
|
|
}
|
|
});
|