Files
autofirmer-expanded/extension/README.md
T
Brandon LiandClaude Opus 5.5 769d96883f Vest: the relayed login binds itself to an unset Vest firm
A Vest firm's credential is the wallet of the login it trades. It no longer
has to be typed or clicked in: when the extension relays a Vest tab's
session and a Vest firm here has no credential, that wallet is saved as the
credential (lib/vest-wallet.ts), the client starts, and the backup is
pushed.

- A saved wallet is never replaced. When the tab is signed in to another
  login, the firm now says which one and how to switch: sign in as the
  saved wallet, or remove the credential.
- With two logins relayed at once nothing binds itself; the one-click form
  decides.
- Extension 0.17.1 re-posts the session every minute even when it hasn't
  changed. The dashboard holds it in memory only, so a restart there was
  unauthenticated until the tab's next renewal (up to ~15 min); now it is
  back within a minute, and a firm created later binds within a minute too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:42:01 -05:00

118 lines
5.7 KiB
Markdown

# 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 `<all_urls>`: 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=<tab host>--> dashboard
dashboard --GET <master>/api/otp?person=<instance_id>&host=<tab 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.
## Vest session relay
Vest signs people in with Google (through Privy) in the browser and renews the
session with a device key the browser will not export, so the dashboard cannot
log in to Vest by itself. The extension relays the browser's session instead:
```
vest-relay.js (Vest tab, MAIN world) keeps the access token the Vest app last renewed
background.js relayVestSession lifts it every 10s, posts it when it changes (and every minute)
dashboard POST /api/vest/session holds it in memory for the firm's Vest client,
and binds an unset Vest firm to the login's wallet
```
- The hook only reads the Vest app's own `/v3/auth/refresh` and `/register`
answers. It renews nothing and sends nothing; the session stays the app's,
so the bot never logs the tab out.
- The token lives ~15 minutes and the app renews it by itself while the tab is
open. The tab is marked not auto-discardable, since a discarded tab stops
renewing.
- When the dashboard has a Vest firm (its credential is the login's wallet)
and no Vest tab is open, the extension opens one in the background. The app
signs back in from its 30-day session. After that the person signs in again
in that tab.
- This is the one place the extension reads a tab you are not looking at. It
only reads `next.vestmarkets.com` tabs, and only that one value.
## 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.