redflagdeals.com now fronts every page on both hosts with a home-grown
SHA-256 proof-of-work gate served as a clean HTTP 202 whose body is one
inline script. detect_challenge returned None for it: the generic-JS arm
would have caught the small script-only body, but that arm is gated to
403/429 and this site never sends either. Callers got the script page as
success, stripped it to an empty document, and read that as "the site is
JavaScript-gated". Filed by fetchaller with live measurements.
Add ChallengeType.POW with status-agnostic, structural detection: body
under 50 KB, the POW_CHALLENGE_DATA object opened inside a <script>
element, and the pow_bypass cookie name. A page that merely quotes the
script (a bug report, docs/ref-pow.md itself, an HTML-rendered doc with
escaped tags) is not the gate; the tests feed all three as negative
controls.
solve_pow mirrors the page script exactly: nonce + issued_at + counter
with no separator, counter as decimal text from 1, lower-case hex SHA-256,
prefix comparison, five-field cookie with no trailing signals field. Every
field the page controls is validated and bounded (hex lengths, difficulty
capped at 5 nibbles against the script's own 1e7 ceiling, cookie lifetime
defaulted and clamped), the Domain attribute is refused at or above the
host's registrable domain because wreq's jar accepts Domain=co.uk, the
hash loop honours the request deadline, and the regexes do bounded work
per start position so a hostile body cannot buy CPU with size. Both
sessions add the cookie, persist it with the page's one-hour expiry so a
cache_dir survives restarts, and replay; the async session runs the loop
in a worker thread.
Verified live: cold sync and async requests return the thread as 200 with
one inline solve, the www front page loads on the same jar with no
re-solve, a fresh session hydrated from the cache passes without ever
holding pow_trace, feeds and robots.txt are correctly not detected, and a
gate that keeps re-serving the puzzle raises ChallengeDetected("pow")
after 14 requests.