cpns / packages /api /src /lib /turnstile.ts
pramudya-yb
Rename project from Labas to Pram
2b62b0c
Raw
History Blame Contribute Delete
1.46 kB
import { TRPCError } from "@trpc/server";
import { env } from "@pram/env/server";
import { logger } from "@pram/api/logger";
/**
* Validates a Cloudflare Turnstile token server-side.
* No-ops when CLOUDFLARE_TURNSTILE_SECRET_KEY is not configured.
* Throws BAD_REQUEST if the token is missing or invalid when the key is set.
*/
export async function validateTurnstileToken(token: string | undefined): Promise<void> {
const secretKey = env.CLOUDFLARE_TURNSTILE_SECRET_KEY;
if (!secretKey) return;
if (!token) {
throw new TRPCError({ code: "BAD_REQUEST", message: "CAPTCHA verification is required." });
}
try {
const res = await fetch("https://challenges.cloudflare.com/turnstile/v1/siteverify", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ secret: secretKey, response: token }),
});
const data = (await res.json()) as { success: boolean; "error-codes"?: string[] };
if (!data.success) {
logger.warn("[TURNSTILE] Token verification failed", { errorCodes: data["error-codes"] });
throw new TRPCError({ code: "BAD_REQUEST", message: "CAPTCHA verification failed. Please try again." });
}
} catch (err) {
if (err instanceof TRPCError) throw err;
// Fail open if the Cloudflare API is unreachable — don't block legitimate users
logger.error("[TURNSTILE] Siteverify request failed, skipping", { error: (err as Error).message });
}
}