#!/usr/bin/env tsx /** * Deterministic Turnstile check using Cloudflare official testing sitekey. * * Usage: * pnpm run check:turnstile-testkey * pnpm run check:turnstile-testkey -- --headed */ import http from 'node:http'; import { BrowserManager } from '../src/browser.js'; const args = process.argv.slice(2); const headed = args.includes('--headed'); const waitMsRaw = args.includes('--wait-ms') ? args[args.indexOf('--wait-ms') + 1] : undefined; const waitMs = Number.isFinite(Number(waitMsRaw)) ? Number(waitMsRaw) : 9000; const html = ` agent-browser turnstile testkey

Turnstile Testkey Probe

`; function createServer(): Promise { const server = http.createServer((_, res) => { res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-store', }); res.end(html); }); return new Promise((resolve, reject) => { server.on('error', reject); server.listen(0, '127.0.0.1', () => resolve(server)); }); } function closeServer(server: http.Server): Promise { return new Promise((resolve) => server.close(() => resolve())); } async function main(): Promise { const server = await createServer(); const address = server.address(); if (!address || typeof address === 'string') { await closeServer(server); throw new Error('Unable to start local HTTP server for Turnstile probe'); } const localUrl = `http://127.0.0.1:${address.port}/`; const browser = new BrowserManager(); try { await browser.launch({ id: 'turnstile-testkey', action: 'launch', browser: 'chromium', stealth: true, headless: !headed, }); const page = browser.getPage(); await page.goto(localUrl, { waitUntil: 'domcontentloaded', timeout: 45_000 }); await page.waitForTimeout(waitMs); const result = await page.evaluate(() => { const hidden = document.querySelector('input[name="cf-turnstile-response"]') as | HTMLInputElement | null; const hiddenValue = hidden?.value || ''; const callbackValue = typeof (window as any).__turnstileToken === 'string' ? (window as any).__turnstileToken : ''; const token = hiddenValue || callbackValue || ''; return { url: location.href, title: document.title || '', tokenLength: token.length, tokenSample: token.slice(0, 40), isDummyToken: token.includes('DUMMY'), hiddenFieldLength: hiddenValue.length, callbackLength: callbackValue.length, widgetCount: document.querySelectorAll('.cf-turnstile').length, }; }); const report = { timestamp: new Date().toISOString(), headed, waitMs, ok: result.isDummyToken, result, }; console.log(JSON.stringify(report, null, 2)); process.exit(result.isDummyToken ? 0 : 1); } finally { await browser.close().catch(() => {}); await closeServer(server); } } main().catch((error) => { console.error(error instanceof Error ? error.message : String(error)); process.exit(1); });