fix(tiers): escalate JS-shell challenge pages from Tier 1 to browser

This commit is contained in:
germondai
2026-07-08 19:40:38 +02:00
parent 16499ce2fc
commit 4dfe5be680
+16 -1
View File
@@ -1,6 +1,6 @@
import { FINGERPRINT } from "@trawl/browser"
import type { TierResult } from "@trawl/types"
import { isBlocked, isCloudflarePage } from "./detect"
import { hasHcaptcha, hasRecaptcha, hasTurnstile, isBlocked, isCloudflarePage } from "./detect"
import { normalizeHtml } from "./html"
export interface Tier1Result extends TierResult {
@@ -42,6 +42,21 @@ export async function runTier1(
return { tier: 1, status: "needs-js", durationMs: Date.now() - start, reason: "cloudflare-challenge" }
}
// JS-only challenges: the page's static HTML is just a shell that loads the
// captcha widget via <script src="...api.js">. Plain fetch sees the shell and
// would otherwise report success — but the real content (including the widget)
// only renders after JS executes. Escalate so Tier 3 runs the page in a browser,
// executes JS, and the solver can engage the actual widget.
if (hasHcaptcha(html)) {
return { tier: 1, status: "needs-js", durationMs: Date.now() - start, reason: "hcaptcha-shell" }
}
if (hasRecaptcha(html)) {
return { tier: 1, status: "needs-js", durationMs: Date.now() - start, reason: "recaptcha-shell" }
}
if (hasTurnstile(html)) {
return { tier: 1, status: "needs-js", durationMs: Date.now() - start, reason: "turnstile-shell" }
}
if (isBlocked(res.status, html)) {
return { tier: 1, status: "blocked", durationMs: Date.now() - start, reason: `http-${res.status}` }
}