Files
website/src/lib/server/worldtodo/turnstile.ts

33 lines
1.2 KiB
TypeScript

import { TURNSTILE_SECRET_KEY } from '$app/env/private';
import { PUBLIC_TURNSTILE_SITE_KEY } from '$app/env/public';
// Cloudflare Turnstile on the request form, checked server-side through Siteverify.
// Widget "stanrunge.dev worldwide todo list" (managed mode, domain stanrunge.dev).
// Without both keys, request submission is switched off and the form says so.
const SITEVERIFY = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
export const turnstileSiteKey = () => PUBLIC_TURNSTILE_SITE_KEY || '';
export const turnstileConfigured = () => !!(TURNSTILE_SECRET_KEY && PUBLIC_TURNSTILE_SITE_KEY);
export async function verifyTurnstile(
token: string,
fetcher: typeof fetch = fetch
): Promise<boolean> {
if (!turnstileConfigured() || !token || token.length > 2048) return false;
try {
const body = new URLSearchParams({ secret: TURNSTILE_SECRET_KEY, response: token });
const res = await fetcher(SITEVERIFY, {
method: 'POST',
body,
signal: AbortSignal.timeout(8000)
});
if (!res.ok) return false;
const data = (await res.json()) as { success?: boolean };
return data.success === true;
} catch (e) {
console.error('[worldtodo] turnstile siteverify failed', (e as Error).message);
return false;
}
}