A preload belongs to the WebContents, not the page: a website loaded into the Settings tab kept window.cfg and could read every vault password, flip settings and install extensions without consent. Settings and add-on tabs now never load web content, and the channels behind settings-preload check their sender. `navigate` no longer accepts calls from web pages. Add-on updates trusted any publisherSig, whatever name it carried, even for bundled add-ons. The trust root is now the installed addon.json (publisher, or the operator key when there is none); versions must be plain dotted numbers; a community install can't take over a bundled or foreign id. Also: - autofill matches and fills against the live URL, not a stale prov.host - bns:// forwards the raw request path (..%2F escaped the name's bucket) - clipboard-read denied, openExternal asks; forged collision choices ignored - web pages can't window.open file:/chrome:/theseus:; data:/blob: no longer go to the search engine; the quick-links panel loses home-preload - clear-history-on-quit is awaited and removes history.json too - update helper takes its paths from the environment (non-ASCII profiles) - electrum poll has a deadline; misses wait at most 2.5 s - p records go through Tor; add-on proxy credentials are actually used - whole-folder require-cache bust on add-on version change; failed activate() no longer leaks its request filter - approvals released when the window closes; web-app ids stay on-origin
6.2 KiB
Theseus gotchas
Non-obvious things sessions keep re-deriving. If you found this file because something broke in a way that felt spooky, the answer is probably here.
build.files in package.json is EXPLICIT
electron-builder ships only what's listed in build.files. Every runtime-
loaded HTML/preload/module MUST be there. A missing entry causes the
loadFile("foo.html") in a WebContentsView to silently open blank in the
packaged app — visually indistinguishable from "the button does nothing".
npm start (dev) never catches this because it reads from the source tree
directly. Only a real npm run dist + install exposes it.
Every time you add a new WebContentsView or loadFile, add its HTML and
preload to the files array. Sanity check after building:
node -e "const b = require('fs').readFileSync('dist-public/win-unpacked/resources/app.asar'); for (const n of ['engine-picker.html','popover.html','downloads.html','engine-picker-preload.js','popover-preload.js','downloads-preload.js']) console.log(n, b.indexOf(Buffer.from(n)) >= 0 ? 'OK' : 'MISSING');"
This has bit us once (search-picker dropdown, shipped 6bbccf9c, blank
picker). Do not let it bite twice.
Building — admin terminal the first time
npm run dist needs an admin terminal on the machine's first Theseus
build so electron-builder's winCodeSign package can extract its
darwin/ symlinks (requires SeCreateSymbolicLink). Subsequent builds
reuse the cache under $LOCALAPPDATA/electron-builder/Cache/winCodeSign/
and don't need admin.
If DNS is misbehaving on the machine, pin these hosts in
C:\Windows\System32\drivers\etc\hosts before building so electron-builder
can fetch: github.com, codeload.github.com,
objects.githubusercontent.com, release-assets.githubusercontent.com.
Strip them after.
Reproducible builds
Set both before npm run dist:
SOURCE_DATE_EPOCH— freezes timestamps so a rebuild with no content changes produces the same hash. Bump per release, not per rebuild.CSC_IDENTITY_AUTO_DISCOVERY=false— stops electron-builder searching for a signing cert (we don't sign; SECURITY.md rule 2).
Native <select> popup theme
Chromium's native <select> popup uses the page's color-scheme. When it's
"light dark" (both accepted), Chromium picks by the OS scheme — so a
dark-themed app on a light OS shows a light popup and vice versa.
Fix, currently in settings.html:
:root { color-scheme: dark; }
@media (prefers-color-scheme: light) { :root { color-scheme: light; } }
nativeTheme.themeSource (driven by settings.theme) sets
prefers-color-scheme, so this stays in sync automatically. Do not remove.
Chromium also respects select option { background; color } in the popup
on Windows — a belt-and-braces override alongside color-scheme.
A preload belongs to the WebContents, not the page
A view's preload runs for every document that view ever loads. Navigating
a Settings tab to a website used to hand that site window.cfg, which
covers the vault (pwGet), settings and extension installs. Two rules
follow:
- Settings and add-on-file tabs never load anything else.
navigateTabandwill-navigateopen the target in a fresh tab instead. - A new IPC channel exposed through
settings-preload.jsmust be added toSETTINGS_ONLY(orSETTINGS_SHAREDif the toolbar'spreload.jscalls it too) in main.js. The wrapper aroundipcMain.handleonly checks the sender for the channels in those sets. Any other channel is callable by whatever page ends up in the view.
The same applies to home-preload.js, which is in every tab. Handlers
behind it check isHomePageSender / isErrorPageSender, which compare
the sender against the exact shipped file:// URL.
The resolver in Theseus is resolver-web.mjs, not .js
Packaged builds ship Argus/src/lib/resolver-web.js as resolver-web.mjs
(see extraResources in package.json). Renamed because
resources/ has no adjacent package.json so a .js gets treated as
CommonJS and its exports fail. Dev reads the engine copy directly (Argus
is type: module so .js works there).
The resolver's electrum WS directIP fallback
main.js passes directIP: true to resolveHost so the engine
can dial the chipnet electrum servers by pinned IP if system DNS is dead.
Do not remove — this is what keeps .bch resolution working when the
adapter DNS is broken (a real failure mode we've hit).
Publishing new hashes end-to-end
- Build (see above).
- Update
../site/releases-manifest.jsonAND../site/tools/index.htmlAND../site/releases/index.htmlwith the fresh SHA-256s + release date. All three must match. - Deploy:
scp dist-public/*.exe ../site/releases-manifest.json silentmode:/opt/silent-mode/dl/ cd ../Argus && node src/lib/sia-upload.js ../site bns/silentmode - On-chain (wallet spend, user's action):
releases.silentmode.bchcurrently publishes{"u":"https://dl.silentmode.st/releases-manifest.json"}— a compacturecord because on-chain hashes wouldn't fit the 200-byte OP_RETURN. Only re-publish if the URL changes or if we ever put full hashes on-chain.
Sia upload from this machine fails without a hosts pin
node src/lib/sia-upload.js fails with getaddrinfo EAI_FAIL coinspectrum.duckdns.org unless the host is pinned in
C:\Windows\System32\drivers\etc\hosts:
195.184.247.106 coinspectrum.duckdns.org. This is a DNS quirk of the
machine, not a code bug — related to the strict-resolver behavior the
Ariadne daemon's EDNS fix addresses.
Deploy directory quirks
/opt/silent-mode/dl/is served asdl.silentmode.st— installers + manifest live here.silentmode.stproxies to Sia (bns/silentmode/) — the HTML pages live there.- The
bnsgateway does NOT auto-index directories.silentmode.st/apps/is a 404 (NoSuchKey); users must hit/apps/index.html. Fix upstream inbnsd.jsif it ever matters.
Firefox needs a restart after Ariadne CA install/rotation
Firefox only reads root CAs at startup. The Ariadne installer offers a
-CloseFirefox task by default when Firefox is running so this doesn't
bite. Chrome/Edge pick up the new root immediately.