Skip to content

fix(extension): mint reCAPTCHA via hidden widget — unblocks generate after the 2026-09-22 build - #62

Merged
crisng95 merged 1 commit into
crisng95:mainfrom
Matro81:fix/captcha-mint-from-flowbridge2
Sep 24, 2026
Merged

crisng95 merged 1 commit into
crisng95:mainfrom
Matro81:fix/captcha-mint-from-flowbridge2

Conversation

@Matro81

@Matro81 Matro81 commented Sep 24, 2026

Copy link
Copy Markdown

Problem

Since frontend build boq_labs-ai-sandbox-frontend_20260922.00_p0 (deployed ~2026-09-22 16:45–17:52 UTC), every generate RPC this extension submits fails with PUBLIC_ERROR_UNUSUAL_ACTIVITY (grpc 7) — while clicking Generate in the Flow UI on the same tab still works. This is the break reported in #58.

The conclusion in #58 ("self-minted tokens are now rejected regardless") is not quite right: the constraint moved into how the token is minted, not into self-minting as such. A token obtained by calling grecaptcha.enterprise.execute(SITE_KEY, {action}) directly — the way injected.js did it — is now rejected. A token minted the way the page's own code does it (render a widget, execute the widget id) still passes.

Evidence (A/B, same account, same build, same project, 2026-09-24)

Path Mint method Result
FlowKit main (0.3.2) execute(SITE_KEY, {action}) ❌ UNUSUAL_ACTIVITY, 3/3 requests (each byte-compared against UI: sitekey/action/payload/headers identical)
Independent bridge (this PR's source) ready() → render(hiddenDiv, {sitekey, size:'invisible'}) → execute(widgetId, {action}) ✅ image completed, media_id e2f6fd77-02ff-4e7b-889e-403e370537b2
FlowKit + this patch (0.3.4) same as above ✅ direct generate 4209e716-4155-45d8-8d89-c2392d333b6c; full pipeline (POST /api/requests → worker → scene row) 3bd7ff3b-ab16-461a-8194-e6fe267210d7, JPEG bytes verified from flow-content.google

What changed

extension/injected.js

  • mintCaptcha() rewritten: resolveSitekey() reads the real sitekey off ___grecaptcha_cfg (hardcoded key kept as fallback) → enterprise.ready() → render an invisible widget into a hidden div → execute(widgetId, {action}), with retry. Mints stay serialized as before.

extension/content.js + 2 new bundled files

  • flow.google.com no longer ships grecaptcha at page load, and its Trusted-Types CSP blocks <script src="https://www.google.com/…"> from the page. The only exempt route is the extension's own chrome-extension:// URL, so content.js preloads recaptcha_enterprise.js + recaptcha__en.js (same bundles as the reference bridge, byte-identical) into the MAIN world.
  • Without this step the mint fails earlier with grecaptcha not available (hit exactly that while landing this fix).
  • All injected script URLs carry ?v=<manifest.version> — Chrome was observed reusing a stale injected.js after a plain reload otherwise.

extension/manifest.json

  • version 0.3.2 → 0.3.4 (forces a clean script fetch), both bundles added to web_accessible_resources.

Notes

Refs #58

… bundles

The 2026-09-22 frontend build (boq_labs-ai-sandbox-frontend_20260922.00_p0)
started rejecting tokens obtained by calling
grecaptcha.enterprise.execute(SITE_KEY, {action}) directly — every generate
RPC answers PUBLIC_ERROR_UNUSUAL_ACTIVITY, while clicking Generate in the
Flow UI still works. Sitekey, action, payload and headers were verified
byte-for-byte identical to the UI, so the constraint moved into the mint
mechanism itself.

Fix ported from FlowBridge2's mint, which passes on the same build (A/B
tested with the same account/project, 2026-09-24):
- resolveSitekey(): read the real sitekey off ___grecaptcha_cfg (fallback
  to the hardcoded one)
- grecaptcha.enterprise.ready() -> render an invisible widget in a hidden
  div -> execute(widgetId, {action}) with retry, mint serialized
- content.js now preloads recaptcha_enterprise.js + recaptcha__en.js
  (bundled from the reCAPTCHA CDN) into the MAIN world: flow.google.com no
  longer ships grecaptcha at page load and its Trusted-Types CSP blocks
  <script src=google.com/...>, so the only exible route is the extension's
  own chrome-extension:// URL
- cache-buster ?v=<manifest.version> on all injected scripts (Chrome has
  been observed to reuse a stale injected.js after reload otherwise)
- bump extension to 0.3.4, add both bundles to web_accessible_resources

Verified end to end: direct generate (ogiZ0b) COMPLETED + image bytes
served from flow-content.google; the full pipeline (POST /api/requests ->
worker queue -> generate -> media_id/url persisted) COMPLETED. Rejection
before the fix was 100% reproducible on three independent requests.

Refs crisng95#58
@biziroyce

Copy link
Copy Markdown

@Matro81 it did work for a few hours, then, it does not work anymore. At this time of commenting, it does not work for me.

@crisng95
crisng95 merged commit d8bc87a into crisng95:main Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants