Decouples bundled-add-on updates from Theseus releases. An add-on
whose addon.json declares an updateURL can be republished at any time
without shipping a new Theseus installer; existing installs pick it up
on the next boot's +30 s background check.
Client flow (main-process only, no UI touchpoints in this commit):
initAddons()
├── promoteStagedUpdates() # promote signed stage if newer
├── seedBundledAddons() # bundle wins over on-disk if newer
└── AddonHost.discoverAndActivate()
30 s later:
└── checkAndStageUpdates() # fetch, verify, download, stage
Signature: Ed25519 over
"silentmode.addon-update-v1|<id>|<version>|<tarball-sha256>",
verified against a hardcoded set of operator pubkeys living in
addon-update-pubkeys.js. Domain-separated so the operator key can't
be tricked into signing a message with a different purpose. Empty
pubkey array is the shipping default — checkAndStageUpdates() then
short-circuits and no outbound requests are made, which is the safe
posture until the operator ceremonies a key in.
Payload: gzipped tar, extracted with the system tar (present on
Win10 1803+, macOS, Linux). Path traversal defended by tar's default
refusal of `..` entries; the extracted manifest's id + version are
re-checked against the signed values before staging.
Staged updates go to <userData>/addons-updates-staged/<id>-<version>/.
Promotion into <userData>/addons/<id>/ reuses seedBundledAddons's
backup dance: existing folder moves to
<userData>/addons-backups/<id>-<oldver>-<timestamp>/ so any local
edits survive.
New files:
- addon-updater.js — client
- addon-update-pubkeys.js — hardcoded pubkeys (empty; edit + rebuild to rotate)
- scripts/generate-update-keypair.mjs — one-time keygen
- scripts/sign-addon-update.mjs — operator packager+signer
- docs/ADDON-UPDATES.md — operator brief + threat model
Wired into main.js at boot; screenshot add-on's addon.json advertises
the reference updateURL for when the endpoint goes live.
138 lines
3.5 KiB
JSON
138 lines
3.5 KiB
JSON
{
|
|
"name": "theseus-navigator",
|
|
"version": "0.3.16",
|
|
"description": "Theseus Navigator — a browser that follows the thread. By Silent Mode, a Deviant project.",
|
|
"author": "Silent Mode",
|
|
"main": "main.js",
|
|
"type": "commonjs",
|
|
"scripts": {
|
|
"start": "electron .",
|
|
"resolve-test": "node resolve-test.mjs",
|
|
"dist": "electron-builder --win nsis portable"
|
|
},
|
|
"dependencies": {
|
|
"@noble/curves": "^2.0.1",
|
|
"@noble/hashes": "^2.0.1",
|
|
"@scure/bip32": "^2.0.1",
|
|
"fetch-socks": "^1.3.3",
|
|
"nostr-tools": "^2.10.4",
|
|
"psl": "^1.15.0",
|
|
"socks-proxy-agent": "^10.1.0",
|
|
"ws": "^8.18.0"
|
|
},
|
|
"devDependencies": {
|
|
"electron": "^33.0.0",
|
|
"electron-builder": "^25.1.8"
|
|
},
|
|
"build": {
|
|
"appId": "st.silentmode.theseus",
|
|
"productName": "Theseus Navigator",
|
|
"artifactName": "TheseusNavigator-${version}-${arch}.${ext}",
|
|
"directories": {
|
|
"output": "dist-public"
|
|
},
|
|
"asar": true,
|
|
"files": [
|
|
"main.js",
|
|
"preload.js",
|
|
"chrome.html",
|
|
"home.html",
|
|
"settings.html",
|
|
"settings-preload.js",
|
|
"popover.html",
|
|
"popover-preload.js",
|
|
"engine-picker.html",
|
|
"engine-picker-preload.js",
|
|
"downloads.html",
|
|
"downloads-preload.js",
|
|
"address-picker.html",
|
|
"address-picker-preload.js",
|
|
"pw-fill.html",
|
|
"pw-fill-preload.js",
|
|
"home-preload.js",
|
|
"error.html",
|
|
"error-preload.js",
|
|
"sidebar-preload.js",
|
|
"approval-preload.js",
|
|
"approval.html",
|
|
"addon-inject-preload.js",
|
|
"addons-host.js",
|
|
"addon-updater.js",
|
|
"addon-update-pubkeys.js",
|
|
"link-status.html",
|
|
"link-status-preload.js",
|
|
"collision.html",
|
|
"collision-preload.js",
|
|
"messages.html",
|
|
"messages-preload.js",
|
|
"bcnr-preload.js",
|
|
"bcnr-origin.js",
|
|
"lib/**/*",
|
|
"package.json",
|
|
"node_modules/**/*",
|
|
"!**/*.md",
|
|
"!**/*.map",
|
|
"!tor${/*}",
|
|
"!dist-public${/*}",
|
|
"!resolve-test.mjs",
|
|
"!*PROMPT.md"
|
|
],
|
|
"extraResources": [
|
|
{
|
|
"from": "tor",
|
|
"to": "tor"
|
|
},
|
|
{
|
|
"from": "../Argus/src/lib/resolver-web.js",
|
|
"to": "resolver-web.mjs"
|
|
},
|
|
{
|
|
"from": "../Argus/src/lib/password-vault.js",
|
|
"to": "password-vault.mjs"
|
|
},
|
|
{
|
|
"from": "lib/hermes.js",
|
|
"to": "lib/hermes.mjs"
|
|
},
|
|
{
|
|
"from": "snapshots/bns-name-snapshot.json",
|
|
"to": "bns-name-snapshot.json"
|
|
},
|
|
{
|
|
"from": "build/AriadneResolver-Setup-0.1.0.exe",
|
|
"to": "AriadneResolver-Setup-0.1.0.exe"
|
|
},
|
|
{
|
|
"from": "bundled-addons",
|
|
"to": "bundled-addons"
|
|
},
|
|
{
|
|
"from": "build/icon.ico",
|
|
"to": "icon.ico"
|
|
}
|
|
],
|
|
"win": {
|
|
"icon": "build/icon.ico",
|
|
"target": [
|
|
"nsis",
|
|
"portable"
|
|
]
|
|
},
|
|
"nsis": {
|
|
"oneClick": false,
|
|
"perMachine": false,
|
|
"allowToChangeInstallationDirectory": true,
|
|
"artifactName": "TheseusNavigator-Setup-${version}.${ext}",
|
|
"include": "nsis/installer.nsh",
|
|
"installerIcon": "build/icon.ico",
|
|
"uninstallerIcon": "build/icon.ico",
|
|
"installerHeaderIcon": "build/icon.ico",
|
|
"installerSidebar": "build/installerSidebar.bmp",
|
|
"uninstallerSidebar": "build/uninstallerSidebar.bmp",
|
|
"installerHeader": "build/installerHeader.bmp"
|
|
},
|
|
"portable": {
|
|
"artifactName": "TheseusNavigator-${version}-portable.${ext}"
|
|
}
|
|
}
|
|
}
|