v0.7.0 — Proof of work + pending placeholder
What's new
Proof of work (opt-in)
Before this release, /captcha/init was free: a bot could harvest valid tokens and random field names at will, then forge a plausible behavioral log. The new PoW layer changes the economics — every token now costs CPU time first.
Enable it with pow => true in your Config. The init endpoint becomes two-phase on the same route: without a valid solution it returns an HMAC-signed challenge; with a valid solution it issues the token. Stateless, no extra storage required.
PoWChallengeGenerator— signed challenge (nonce + difficulty + expiry)PoWVerifier— shape → signature → expiry → difficulty → replay (consumes nonces via the existingTokenStoreInterfacewhenanti_replayis on)pow_difficulty(default 18 bits, ~100–500 ms on desktop) andpow_challenge_ttl(default 90s) config options
Client-side solver
PoWSolver— inline SHA-256 inside a Blob-based Web Worker (no separate file to serve), with a chunked main-thread fallback when workers are blocked by CSPAjaxFetcherhandles the two-phase init transparently and re-solves a fresh challenge on every TTL refresh
Pending placeholder
The widget now appears immediately at page load as a dimmed, non-interactive placeholder — same dimensions as the final captcha (zero layout shift), and nothing scrapable (no field name, no token, no hidden inputs). It announces the verification step upfront and shows a spinner while the PoW resolves before upgrading in place.
Other changes
AbstractEndpoint::handleInit()now accepts the decoded JSON request body (required whenpowis enabled, harmless otherwise)- Behavioral event collection starts at the first interaction signal — the trajectory during PoW solving is now captured
- Token auto-refresh failures are caught instead of raising unhandled rejections
See the README for the configuration guide and the CHANGELOG for the full diff.