turnstiel

This commit is contained in:
evanpelle
2026-05-04 10:35:44 -06:00
parent 257fb9b38e
commit 222cb8a279
7 changed files with 23 additions and 68 deletions
-1
View File
@@ -25,7 +25,6 @@ export enum GameEnv {
export interface ServerConfig {
turnstileSiteKey(): string;
turnstileSecretKey(): string;
turnIntervalMs(): number;
gameCreationRate(): number;
numWorkers(): number;
-3
View File
@@ -43,9 +43,6 @@ const JwksSchema = z.object({
});
export abstract class DefaultServerConfig implements ServerConfig {
turnstileSecretKey(): string {
return Env.TURNSTILE_SECRET_KEY ?? "";
}
abstract turnstileSiteKey(): string;
allowedFlares(): string[] | undefined {
return;
-4
View File
@@ -8,10 +8,6 @@ export class DevServerConfig extends DefaultServerConfig {
return "1x00000000000000000000AA";
}
turnstileSecretKey(): string {
return "1x0000000000000000000000000000000AA";
}
adminToken(): string {
return "WARNING_DEV_ADMIN_KEY_DO_NOT_USE_IN_PRODUCTION";
}
-3
View File
@@ -62,9 +62,6 @@ export const Env = {
return getEnv("GAME_ENV") ?? "dev";
},
get TURNSTILE_SECRET_KEY() {
return getEnv("TURNSTILE_SECRET_KEY");
},
get STRIPE_PUBLISHABLE_KEY() {
return getEnv("STRIPE_PUBLISHABLE_KEY");
},
+21 -45
View File
@@ -1,68 +1,44 @@
import { ServerConfig } from "../core/configuration/Config";
type TurnstileResponse =
| { status: "approved" }
| { status: "rejected"; reason: string }
| { status: "error"; reason: string };
export async function verifyTurnstileToken(
ip: string,
turnstileToken: string | null,
turnstileSecret: string,
): Promise<
| { status: "approved" }
| { status: "rejected"; reason: string }
| { status: "error"; reason: string }
> {
if (!turnstileToken) {
return { status: "rejected", reason: "No turnstile token provided" };
}
config: ServerConfig,
): Promise<TurnstileResponse> {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000);
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetch(
"https://challenges.cloudflare.com/turnstile/v0/siteverify",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
secret: turnstileSecret,
response: turnstileToken,
remoteip: ip,
}),
signal: controller.signal,
const response = await fetch(`${config.jwtIssuer()}/turnstile`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": config.apiKey(),
},
);
body: JSON.stringify({ ip, token: turnstileToken }),
signal: controller.signal,
});
clearTimeout(timeoutId);
if (!response.ok) {
return {
status: "error",
reason: `Turnstile API returned ${response.status}`,
reason: `api-worker returned ${response.status}`,
};
}
const result = (await response.json()) as {
success: boolean;
challenge_ts?: string;
hostname?: string;
"error-codes"?: string[];
action?: string;
cdata?: string;
};
if (!result.success) {
const codes = result["error-codes"]?.join(", ") ?? "unknown";
return {
status: "rejected",
reason: `Turnstile token validation failed: ${codes}`,
};
}
return { status: "approved" };
return (await response.json()) as TurnstileResponse;
} catch (e) {
if (e instanceof Error && e.name === "AbortError") {
return {
status: "error",
reason: "Turnstile token validation timed out after 3 seconds",
reason: "Turnstile token validation timed out after 5 seconds",
};
}
return {
+2 -9
View File
@@ -40,10 +40,6 @@ 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;
// Worker setup
export async function startWorker() {
log.info(`Worker starting...`);
@@ -432,14 +428,11 @@ export async function startWorker() {
return;
}
// TEMPORARY: Turnstile validation disabled while we diagnose
// intermittent invalid-input-response rejections in v31.
// Re-enable by flipping TURNSTILE_ENABLED back to true.
if (TURNSTILE_ENABLED && config.env() !== GameEnv.Dev) {
if (config.env() !== GameEnv.Dev) {
const turnstileResult = await verifyTurnstileToken(
ip,
clientMsg.turnstileToken,
config.turnstileSecretKey(),
config,
);
switch (turnstileResult.status) {
case "approved":
-3
View File
@@ -7,9 +7,6 @@ export class TestServerConfig implements ServerConfig {
turnstileSiteKey(): string {
throw new Error("Method not implemented.");
}
turnstileSecretKey(): string {
throw new Error("Method not implemented.");
}
apiKey(): string {
throw new Error("Method not implemented.");
}