# AutoFirmer Capture (Chromium extension) Scrapes the firm tab you are looking at and posts its HTML back to the dashboard. There is no on/off switch for that — see **Scope** below for what limits it instead. ## Install (unpacked) 1. Start the dashboard (`npm run dev`) so `http://localhost:3000` is up. 2. Open `chrome://extensions`, enable **Developer mode** (top right). 3. **Load unpacked** → select this `extension/` folder. 4. Click the extension icon to open the popup and set: - **Dashboard URL** — default `http://localhost:3000`. Use the VPS IP if the dashboard runs elsewhere. - **Poll interval** — seconds between status checks (default 3). - **Element selector** — optional CSS selector; matching elements get their on-screen position measured alongside the HTML. The badge shows `!` (red) if the dashboard is unreachable, and nothing otherwise — blank is the working state. Open the popup for what the last tick actually did. ## Flow ``` extension --GET /api/autobuyer/status--> { pendingLocate } extension --POST /api/autobuyer/capture-> html + viewport + element rects AutoBuyer page --GET /api/autobuyer/capture-> renders the HTML ``` Nothing in that loop is switchable. Every tick serves any queued clicks and then captures the tab you are on. ## Scope Capture has no switch, so scope is what keeps it honest. Three limits, all enforced by Chrome rather than by this code: 1. **`host_permissions` is deliberately narrow** — the firm sites plus localhost for the dashboard. The extension is *technically incapable* of reading any other site, so an accidental capture of your bank or mail tab cannot happen however the logic here is changed. 2. **Only the tab you are on.** `pickTab()` asks for the active tab of the last-focused window *and* a host_permissions match. A firm tab sitting in the background is not captured, and neither is anything else. Switch away and capture simply stops until you switch back. 3. **One content script, same hosts.** `captcha-hook.js` runs at document_start on the firm sites only. It wraps `turnstile.render` / `grecaptcha.render` / `hcaptcha.render` and remembers what the page passed them — the sitekey, and above all the callback a solved token has to be handed to, which a programmatically rendered widget puts nowhere else. It reads nothing else and sends nothing anywhere; the remembered arguments stay in the page's own world until a `solveCaptcha` step comes to collect them. To automate a different broker, add its pattern to `host_permissions` in `manifest.json` and reload the extension — that alone scopes capture to it. Avoid going back to ``: it would put every tab you visit in reach, and limit 1 is the only thing standing between this and scraping your whole browser. A new firm needs its host in *both* lists — `host_permissions` and the `content_scripts` matches — or captchas on that site will have no callback to fire. ## 2FA codes On a firm site, the extension shows the machine's person's authenticator code for that site in a small chip in the bottom-right corner, with a Copy button (minimise it to a "2FA" pill; that sticks for the tab's session). ``` extension --GET /api/autobuyer/otp?host=--> dashboard dashboard --GET /api/otp?person=&host=--> master ``` The master holds the secrets and matches the host against each firm's **Site** link (Firms page), then returns the codes assigned to this person and that firm (Codes page). The chip only needs a code to be assigned — it doesn't wait for a code field. It stays hidden for a minute after the runner last located something, so automated clicks never land on it. A new 2FA site needs its host in `host_permissions` (not the captcha `content_scripts` list), a Site link on its firm on the master, and its codes assigned on the master's Codes page. ## Notes - The extension never captures the dashboard's own pages — otherwise it would just mirror its own output back. - `chrome://`, `about:` and Web Store pages cannot be scripted by any extension; they're skipped. - MV3 service workers are torn down when idle. Each poll makes an extension API call, which keeps the worker alive; a 30-second alarm revives it if Chrome kills it anyway. So worst-case cadence is 30s, normal cadence is the poll interval.