33 lines
1.2 KiB
TypeScript
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;
|
|
}
|
|
}
|