What's Changed
- Widget: show error messages in the widget's language by @goastler in #3374
- Provider: tie admin JWTs to one provider and cap their lifetime by @goastler in #3383
- Provider: fix a slow-regex hang in domain wildcard matching by @goastler in #3387
- Util: fix embedData corrupting coordinates in long salts by @goastler in #3372
- Provider: protect /metrics by @goastler in #3388
- Datasets: make the dataset validation test the size its comment says by @goastler in #3401
- Demos: log the real widget id on explicit-render pages by @goastler in #3402
- CLI: treat the bundle test as an integration test by @goastler in #3394
- Load balancer: reject zero retry attempts clearly by @goastler in #3403
- Provider: check the unsolved captcha count in datasets by @goastler in #3407
- Dev setup: stop overwriting every demo page's site key by @goastler in #3412
- Util: make the async constructor no-args test assert something by @goastler in #3414
- Util: make at() match its types by @goastler in #3415
- Util-crypto: stop extra JWT claims overriding the standard ones by @goastler in #3416
- Widget: show failed captchas inline instead of with alert() by @goastler in #3375
- Provider Caddy: send security headers on every path by @goastler in #3385
- Provider: don't accept 128MB bodies before checking the admin token by @goastler in #3386
- Util-crypto: only accept JWTs signed with sr25519, in the plain format by @goastler in #3393
- Database: fix the misspelt timestamp in commitment updates by @goastler in #3399
- Server: test the authenticated (Web Bot Auth) verify path by @goastler in #3424
- Provider: return 400 for bad dapp signatures on verify by @goastler in #3411
- Widget: lay out right-to-left for Arabic and other RTL languages by @goastler in #3377
- Locales: add the error keys the code actually throws by @goastler in #3404
- Widget: tell the user their image answer was wrong by @goastler in #3376
- Datasets: make verifyProof check the proof against the real root by @goastler in #3382
- Widgets: clear expiry timers when a widget is destroyed by @goastler in #3378
- Datasets: an empty answer is never correct by @goastler in #3400
- Provider: return 400 for undecodable verify tokens by @goastler in #3422
- Widget: move hard-coded English strings to the locale files by @goastler in #3418
- Locale: type-check translation keys by @goastler in #3405
- Util-crypto: strictly check JWT time and payload claims by @goastler in #3421
- Widgets: stop old timers and late solves affecting a new challenge by @goastler in #3426
- Widget: translate the loading and reload labels by @goastler in #3417
- Provider: stop returning internal error objects to callers by @goastler in #3389
- Widget: say why the challenge closed when it runs out of time by @goastler in #3428
- Widget: announce errors to screen readers and theme the verified badge by @goastler in #3427
- Widget: open the challenge popup in the widget's text direction by @goastler in #3429
- Resolve the traffic-filter verdict before the frictionless short-circuits by @forgetso in #3464
- Pad the challenge only, not the frictionless session envelope by @forgetso in #3465
- Stream the tarpit padding with backpressure and spread it through the body by @forgetso in #3466
- Release v3.8.25 by @prosoponator-app[bot] in #3467
Full Changelog: v3.8.24...v3.8.25