turnstile fix

This commit is contained in:
evanpelle
2026-05-03 19:27:32 -06:00
parent 257fb9b38e
commit 46266c28fe
2 changed files with 50 additions and 6 deletions
+49 -3
View File
@@ -1033,9 +1033,27 @@ if (document.readyState === "loading") {
bootstrap();
}
// Concurrent renders into the same container tangle Cloudflare's widget
// bookkeeping and produce "already executing" + postMessage origin-mismatch
// errors plus malformed tokens that fail siteverify with invalid-input-response.
// Serialize callers and give each their own container element.
let inFlightTurnstileChain: Promise<unknown> = Promise.resolve();
const TURNSTILE_TIMEOUT_MS = 20_000;
async function getTurnstileToken(): Promise<{
token: string;
createdAt: number;
}> {
const myCall = inFlightTurnstileChain
.catch(() => {})
.then(() => fetchOneTurnstileToken());
inFlightTurnstileChain = myCall;
return myCall;
}
async function fetchOneTurnstileToken(): Promise<{
token: string;
createdAt: number;
}> {
// Wait for Turnstile script to load (handles slow connections)
let attempts = 0;
@@ -1049,7 +1067,28 @@ async function getTurnstileToken(): Promise<{
}
const config = await getRuntimeClientServerConfig();
const widgetId = window.turnstile.render("#turnstile-container", {
const parent = document.getElementById("turnstile-container");
if (!parent) {
throw new Error("Missing #turnstile-container element");
}
const target = document.createElement("div");
parent.appendChild(target);
let widgetId: string | undefined;
const cleanup = () => {
if (widgetId !== undefined) {
try {
window.turnstile.remove(widgetId);
} catch (e) {
console.warn("turnstile.remove failed", e);
}
widgetId = undefined;
}
target.remove();
};
widgetId = window.turnstile.render(target, {
sitekey: config.turnstileSiteKey(),
size: "normal",
appearance: "interaction-only",
@@ -1057,14 +1096,21 @@ async function getTurnstileToken(): Promise<{
});
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
cleanup();
reject(new Error(`Turnstile timed out after ${TURNSTILE_TIMEOUT_MS}ms`));
}, TURNSTILE_TIMEOUT_MS);
window.turnstile.execute(widgetId, {
callback: (token: string) => {
window.turnstile.remove(widgetId);
clearTimeout(timeoutId);
cleanup();
console.log(`Turnstile token received: ${token}`);
resolve({ token, createdAt: Date.now() });
},
"error-callback": (errorCode: string) => {
window.turnstile.remove(widgetId);
clearTimeout(timeoutId);
cleanup();
console.error(`Turnstile error: ${errorCode}`);
alert(`Turnstile error: ${errorCode}. Please refresh and try again.`);
reject(new Error(`Turnstile failed: ${errorCode}`));
+1 -3
View File
@@ -40,9 +40,7 @@ const workerId = parseInt(process.env.WORKER_ID ?? "0");
const log = logger.child({ comp: `w_${workerId}` });
const playlist = new MapPlaylist();
// TEMPORARY: Turnstile validation disabled while we diagnose intermittent
// invalid-input-response rejections in v31. Flip back to true to re-enable.
const TURNSTILE_ENABLED = false;
const TURNSTILE_ENABLED = true;
// Worker setup
export async function startWorker() {