Ship the extension as a signed CRX from our own update server
The dashboard-hosting stack from the previous commit is gone; it was answering a question nobody asked. What was actually needed is Chrome's real update channel, which an unpacked extension does not have and cannot be given. So the extension is now signed into a CRX with an update manifest beside it, served from the droplet, and installed on the trading machines by policy (ExtensionInstallForcelist). From there Chrome installs it, updates it on its own schedule, and puts it back if it goes missing. The manifest gained the `key` that fixes the extension id, so an unpacked development load keeps the same identity as the published build. The self-update check now branches on how it was installed: policy installs ask Chrome to check the update server now rather than waiting out its five-hour cycle, and unpacked loads keep the reload-from-disk path. chrome.management .getSelf() tells the two apart and needs no permission to do it. The signing key lives at /opt/autofirmer-updates/key.pem on the droplet and nowhere else. It is the extension's identity: a different key is a different extension, and no browser would take it as an update. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ece6aab9cf
commit
035f93d220
@@ -131,11 +131,19 @@ pick it up from the server.
|
||||
`chrome://extensions` → enable **Developer mode** → **Load unpacked** →
|
||||
select the `extension` folder.
|
||||
|
||||
Chrome does **not** reload an unpacked extension when its files change, and it
|
||||
has no update channel for one either. The extension therefore checks the version
|
||||
the dashboard ships on every poll and reloads *itself* when it is behind, which
|
||||
re-reads the folder from disk. Clicking the reload icon on its card still works
|
||||
and is the thing to try when something looks stuck.
|
||||
That is the development install. On a machine that just runs trades, install it
|
||||
from our own update server instead — one elevated command, and Chrome then keeps
|
||||
it updated by itself:
|
||||
|
||||
```powershell
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\install-extension-policy.ps1
|
||||
```
|
||||
|
||||
See [deploy/README.md](deploy/README.md). Either way the extension notices when
|
||||
the dashboard is running newer code than it is: a policy install asks Chrome to
|
||||
fetch the new CRX, an unpacked one reloads itself from disk. Clicking the reload
|
||||
icon on its card still works and is the thing to try when something looks
|
||||
stuck.
|
||||
|
||||
Adding a new firm also means adding its host to `host_permissions` in
|
||||
`extension/manifest.json` and reloading. Without it the extension cannot read
|
||||
@@ -282,22 +290,20 @@ New-NetFirewallRule -DisplayName "AutoFirmer" -Direction Inbound -Protocol TCP -
|
||||
|
||||
---
|
||||
|
||||
## Hosting the dashboard on a server
|
||||
## Publishing extension updates
|
||||
|
||||
The dashboard can run on the droplet instead of on the trading machine, with the
|
||||
clicker and the extension pointing at it over HTTPS. The clicker and the
|
||||
extension cannot move — one needs a desktop to send real input to, the other is
|
||||
your browser.
|
||||
The extension is signed and served from the droplet, which is what lets Chrome
|
||||
update it on its own. Everything else — the dashboard, the clicker — stays on
|
||||
the trading machine.
|
||||
|
||||
```bash
|
||||
cp deploy/.env.example deploy/.env # set FIRMER_HOST
|
||||
./deploy/bootstrap-tls.sh # first run: certificate, then deploy
|
||||
./deploy/deploy.sh # every run after that
|
||||
# on the droplet, in /opt/autofirmer
|
||||
git pull && ./deploy/deploy.sh
|
||||
```
|
||||
|
||||
It shares the droplet's existing nginx and certbot rather than standing up its
|
||||
own, and the database lives on a Docker volume. There is no login on it. See
|
||||
[deploy/README.md](deploy/README.md) before opening it to the internet.
|
||||
That packs `extension/` at the version in its `manifest.json` — **bump it or
|
||||
nothing updates** — signs it, and publishes the CRX and update manifest. See
|
||||
[deploy/README.md](deploy/README.md).
|
||||
|
||||
---
|
||||
|
||||
@@ -341,12 +347,13 @@ node scripts\update-check.mjs
|
||||
|
||||
### What reloads itself, and what does not
|
||||
|
||||
- **The extension** reloads itself now. `/api/autobuyer/status` reports the
|
||||
version the dashboard's own checkout ships; when the running build is older,
|
||||
the extension calls `chrome.runtime.reload()` and comes back on the files the
|
||||
update check pulled. It only ever runs code already on disk, so if it reloads
|
||||
before the pull lands it says so in the popup and waits rather than restarting
|
||||
in a loop. Clicking reload on its card is still the manual fallback.
|
||||
- **The extension** updates itself now. `/api/autobuyer/status` reports the
|
||||
version the dashboard's own checkout ships, and when the running build is
|
||||
older the extension acts on it: a policy install asks Chrome to fetch the new
|
||||
CRX from the update server, an unpacked one calls `chrome.runtime.reload()`
|
||||
and comes back on the files the update check pulled. The unpacked path can
|
||||
only run code already on disk, so if it reloads before the pull lands it says
|
||||
so in the popup and waits rather than restarting in a loop.
|
||||
- **The scheduler is fine now.** It persists to the settings table and resumes
|
||||
after a restart, so an update no longer silently stops automated trading.
|
||||
- **The runner** does not. It is a long-lived Python process; the update check
|
||||
|
||||
Reference in New Issue
Block a user