They are Chromium: same CRX, same update manifest, same policy — only the registry vendor key differs. The script now defaults to every one of the three it finds installed, which is what the Linux counterpart already did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
114 lines
4.9 KiB
Markdown
114 lines
4.9 KiB
Markdown
# The extension update server
|
|
|
|
Chrome has no update channel for an unpacked extension: it reads the folder off
|
|
disk once and never looks again. This is the supported alternative — the
|
|
extension is signed into a CRX, an update manifest is published next to it, and
|
|
Chrome installs and updates it from there like any other extension.
|
|
|
|
```
|
|
droplet 159.223.129.19 Windows box
|
|
key.pem ──signs──> autofirmer.crx ──HTTPS──> Chrome (policy install)
|
|
updates.xml <──polls───
|
|
```
|
|
|
|
Nothing here serves the dashboard. That still runs on the trading machine, next
|
|
to the clicker, exactly as before.
|
|
|
|
## The pieces
|
|
|
|
| | |
|
|
|---|---|
|
|
| `/opt/autofirmer-updates/key.pem` | The signing key. **The extension's identity.** |
|
|
| `/opt/autofirmer-updates/public/` | `autofirmer.crx` and `updates.xml`, served as-is |
|
|
| `deploy/pack-extension.sh` | Signs `extension/` and writes both files |
|
|
| `deploy/docker-compose.yml` | An `nginx:alpine` that serves that folder and nothing else |
|
|
| `deploy/nginx/ext.conf.template` | Rendered into the autotrader stack's `conf.d` |
|
|
| `scripts/install-extension-policy.ps1` | The Windows side: one registry entry |
|
|
|
|
Extension id: `lkjbblagjjbldlkeaaffhiopdlhniaan`, derived from the public half of
|
|
the signing key and repeated in three places that must agree — `key` in
|
|
`extension/manifest.json`, `appid` in `updates.xml`, and the forcelist entry in
|
|
the policy script. `pack-extension.sh` refuses to publish when the first two
|
|
have drifted apart, because the failure otherwise is silent: Chrome simply never
|
|
sees an update that applies to it.
|
|
|
|
**Losing `key.pem` means losing the extension.** A new key is a new id, which
|
|
means a new policy entry on every machine and a fresh install rather than an
|
|
update. It exists in one place, deliberately — it is not in the repo, and a
|
|
compromised copy would let someone else publish an extension your browsers
|
|
would trust and install.
|
|
|
|
## Ingress
|
|
|
|
This stack owns no ingress. The droplet already runs one nginx on 80/443 for
|
|
`master.juicerroom.com` and `git.juicerroom.com`, from `/opt/autotrader/deploy`;
|
|
this joins that network, and `deploy.sh` renders a server block into that
|
|
stack's `nginx/conf.d`. Two consequences:
|
|
|
|
- The rendered `ext.conf` is untracked in the autotrader repo. It survives that
|
|
stack's pulls and deploys, but not its `bootstrap-tls.sh`, which clears
|
|
`conf.d` — re-run `./deploy.sh` here if that ever happens.
|
|
- `deploy.sh` reloads the shared nginx, so a mistake in the template would be a
|
|
mistake in front of the autotrader dashboard too. It runs `nginx -t` first and
|
|
refuses to reload on a bad config, and will not install the TLS server block
|
|
until the certificate actually exists.
|
|
|
|
## First run
|
|
|
|
```bash
|
|
cp .env.example .env # set EXT_HOST
|
|
./bootstrap-tls.sh # DNS check, certificate, then deploy.sh
|
|
```
|
|
|
|
`bootstrap-tls.sh` borrows the autotrader stack's certbot container and Let's
|
|
Encrypt account, reading `ACME_EMAIL` from its `.env` rather than keeping a
|
|
second copy. The A record has to point at the droplet first.
|
|
|
|
## Publishing a release
|
|
|
|
```bash
|
|
git pull && ./deploy/deploy.sh
|
|
```
|
|
|
|
`deploy.sh` packs whatever is in `extension/` at the version its `manifest.json`
|
|
declares, so **bump that version or nothing updates** — Chrome compares versions
|
|
and ignores a CRX that is not newer than what it has.
|
|
|
|
The browsers pick it up on Chrome's own schedule, roughly every five hours. They
|
|
also pick it up within seconds if the dashboard is running, because the
|
|
extension asks Chrome for a check as soon as the dashboard reports a newer
|
|
version than the one it is running.
|
|
|
|
## Installing it on a machine
|
|
|
|
`setup-windows.bat` and `setup-linux.sh` both offer this as their last step, so
|
|
a fresh instance needs nothing extra. To do it by hand, or on a machine that was
|
|
set up before this existed:
|
|
|
|
```powershell
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\install-extension-policy.ps1
|
|
```
|
|
|
|
```bash
|
|
sudo scripts/install-extension-policy.sh
|
|
```
|
|
|
|
Both configure every Chromium-family browser they find — Chrome, Edge and Brave
|
|
take the same CRX, the same update manifest and the same policy, differing only
|
|
in where that policy is written. Narrow it with `-Browser Edge` if you would
|
|
rather not.
|
|
|
|
The Windows script writes to the current user's policy hive and needs no
|
|
elevation; `-Scope Machine` covers every account on the box and does need an
|
|
elevated shell. Linux has no per-user equivalent — Chrome only reads managed
|
|
policy from `/etc` — so that one is root-only and machine-wide. Both take
|
|
`-Remove` / `--remove`.
|
|
|
|
Afterwards, remove the unpacked copy from `chrome://extensions` — it now has the
|
|
same id, and Chrome will not load both — and restart the browser.
|
|
|
|
Development still works the old way: load `extension/` unpacked on a machine
|
|
with no policy entry. It keeps the same id (that is what `key` in the manifest
|
|
is for), and there it reloads itself from disk rather than asking Chrome for an
|
|
update.
|