2026-07-29 13:54:34 +02:00
|
|
|
|
const { contextBridge, ipcRenderer } = require("electron");
|
|
|
|
|
|
contextBridge.exposeInMainWorld("cfg", {
|
|
|
|
|
|
get: () => ipcRenderer.invoke("settings-get"),
|
|
|
|
|
|
set: (key, value) => ipcRenderer.invoke("settings-set", key, value),
|
2026-07-30 19:29:32 +02:00
|
|
|
|
engines: () => ipcRenderer.invoke("search-engines"),
|
2026-07-30 20:58:45 +02:00
|
|
|
|
addEngine: (eng) => ipcRenderer.invoke("add-engine", eng),
|
|
|
|
|
|
removeEngine: (id) => ipcRenderer.invoke("remove-engine", id),
|
2026-07-30 22:55:52 +02:00
|
|
|
|
setEngineEnabled: (id, on) => ipcRenderer.invoke("set-engine-enabled", id, on),
|
2026-07-30 23:26:00 +02:00
|
|
|
|
setEngineOrder: (ids) => ipcRenderer.invoke("set-engine-order", ids),
|
2026-08-06 01:41:31 +02:00
|
|
|
|
removeFromList: (id) => ipcRenderer.invoke("remove-from-list", id),
|
Snapshot in-progress work: Ariadne mobile, Theseus password manager, Hephaestus
Several concurrent workstreams committed together as a checkpoint:
- Ariadne mobile resolver — BchFetcher/Bns/MainActivity resolution logic,
AndroidManifest + build.ps1
- Theseus password manager — settings.html/chrome.html/settings-preload.js UI +
main.js wiring + package.json resource; Argus password-vault.js, record-picker.js
(+ tests) and resolver-web.d.ts
- Hephaestus — new BCH-wallet OIDC auth-proxy + Forgejo docker-compose and
restic/S3 scripts (secrets referenced via env only; Hephaestus/.env is gitignored)
- Argus public-gateway.mjs updates
- Docs — root README, Email README/RUNBOOK, VPS access runbooks (Checkers/Deviant),
site/hermes, WebsiteDev registry + faster-blocks, Failures/ AAAA-mangle writeup,
Decentralized Storage map, coordination notes
- .gitignore — exclude /.keys/ and Hephaestus/.env
2026-08-14 23:17:18 +02:00
|
|
|
|
// Storage: wipe browsing data on demand. Pass any subset of
|
|
|
|
|
|
// { cookies, cache, storage, history }.
|
|
|
|
|
|
clearBrowsingData: (opts) => ipcRenderer.invoke("clear-browsing-data", opts),
|
|
|
|
|
|
// Password vault. All calls return { ok, ... } | { ok: false, err }.
|
|
|
|
|
|
// Renderers never see the seed / vault key / master password past setup/
|
|
|
|
|
|
// unlock; get() returns plaintext only in explicit response to a user click.
|
|
|
|
|
|
pwStatus: () => ipcRenderer.invoke("password-status"),
|
|
|
|
|
|
pwSetup: (masterPassword, seedSource) => ipcRenderer.invoke("password-setup", { masterPassword, seedSource }),
|
|
|
|
|
|
pwUnlock: (masterPassword) => ipcRenderer.invoke("password-unlock", masterPassword),
|
|
|
|
|
|
pwLock: () => ipcRenderer.invoke("password-lock"),
|
|
|
|
|
|
pwList: () => ipcRenderer.invoke("password-list"),
|
|
|
|
|
|
pwGet: (id) => ipcRenderer.invoke("password-get", id),
|
|
|
|
|
|
pwAdd: (entry) => ipcRenderer.invoke("password-add", entry),
|
|
|
|
|
|
pwUpdate: (id, patch) => ipcRenderer.invoke("password-update", id, patch),
|
|
|
|
|
|
pwRemove: (id) => ipcRenderer.invoke("password-remove", id),
|
|
|
|
|
|
pwGenerate: (spec) => ipcRenderer.invoke("password-generate", spec),
|
2026-08-06 01:41:31 +02:00
|
|
|
|
// Main asks settings to jump to a specific sidebar section (e.g. from the
|
|
|
|
|
|
// engine picker's "Search settings…" click). Emits the section id string.
|
|
|
|
|
|
onFocusSection: (cb) => ipcRenderer.on("focus-section", (_e, section) => cb(section)),
|
2026-08-02 11:39:00 +02:00
|
|
|
|
// Collision-mode: BCNR/ICANN policy + per-name/per-TLD overrides
|
|
|
|
|
|
collisionState: () => ipcRenderer.invoke("collision-state"),
|
|
|
|
|
|
setCollisionPolicy: (p) => ipcRenderer.invoke("collision-set-policy", p),
|
|
|
|
|
|
resetCollisions: () => ipcRenderer.invoke("collision-reset"),
|
Theseus: add-on framework MVP + Notepad reference add-on
New subsystem for extending Theseus with folders on disk. Each add-on
lives at <userData>/addons/<id>/ with an addon.json manifest and a
CommonJS entry that exports activate(api). Nothing about a private
add-on ships in the public installer - drop the folder, restart, it's
live. Bundled reference add-ons ride in the packaged app under
resources/bundled-addons/ and are seeded into <userData>/addons/ on
first boot; the framework treats seeded and drop-in add-ons the same.
Files:
- addons-host.js Loader + api.registerSidebarPanel() + per-
addon storage on <userData>/addons-data/.
Kept at the CommonJS-scoped top level (lib/
is ESM-scoped via its own package.json).
- sidebar-preload.js Runs in every sidebar panel. Exposes
window.silentmode.storage.{get,set,all} +
onVisibility. Main-side handlers derive the
add-on id from the sender file:// URL, so a
panel can only touch its own store.
- bundled-addons/notepad/ Reference add-on: addon.json, index.js,
note.html. Autosaving textarea with char /
word count.
main.js:
- Extension point: sidebar-panel. One right-anchored WebContentsView
(SIDEBAR_W=340) hosts the current panel; layout() shrinks the tab
views by the sidebar width when visible. First registered panel
wins for MVP; picker for multiple panels lands later.
- initAddons() at app.whenReady(): seedBundledAddons, then
AddonHost.discoverAndActivate.
- IPC surface: sidebar-toggle / sidebar-open / sidebar-close /
sidebar-state, addons-list / addons-set-enabled / addons-reveal /
addons-open-dir / addons-reload, and origin-gated
addon-storage-get/set/all.
- Settings gains `disabledAddons: []` — off-toggled ids persist and
the loader honours them without a restart (discoverAndActivate
runs again on toggle).
chrome.html: toolbar sidebar-toggle button, hidden until at least one
add-on has registered a sidebar panel.
settings.html: new "Add-ons" section under privacy. Lists installed
add-ons with icon / name / version / description / capabilities;
per-add-on enable/disable toggle + Show folder button; page-level
Reload and Open add-ons folder buttons; warning note about the trust
model.
package.json: build.files gains sidebar-preload.js + addons-host.js.
extraResources gains bundled-addons/ so the packaged app carries the
reference notepad for the first-boot seed.
Verified: `npm start` boots, addons-host discovers the notepad,
activates it, registers one sidebar panel. Log confirms
"1 installed, 1 enabled, 1 sidebar panels". Actual sidebar rendering
+ notepad UI need clicked-through validation on a real install.
Not shipped yet - deploy still blocked on the fail2ban VPS SSH ban.
Ships as 0.2.0 once SSH clears (this is a new subsystem, not a fix).
2026-08-31 13:51:08 +02:00
|
|
|
|
// Add-ons management (Settings > Add-ons tab).
|
|
|
|
|
|
listAddons: () => ipcRenderer.invoke("addons-list"),
|
|
|
|
|
|
setAddonEnabled: (id, enabled) => ipcRenderer.invoke("addons-set-enabled", id, !!enabled),
|
|
|
|
|
|
revealAddon: (folder) => ipcRenderer.invoke("addons-reveal", folder),
|
feat(theseus/settings): Extensions as compact rows with a detail view
The Extensions list was a stack of tall cards — description, author,
capabilities and buttons on every one — so seven add-ons filled the
page before the user found the toggle. Rows are now one line each,
Firefox-style: icon, name, built-in badge, version, a short update
status, the on/off switch and a ⋯ menu, grouped Enabled / Disabled /
Failed to load. Clicking a row opens the detail view in place: back
arrow, description, update status, author, version, type, folder with
Show folder, and a Permissions block that explains each declared
capability in plain words. The ⋯ menu (and right-click) offers Turn
on/off, Details, Show folder and, for non-bundled extensions, Remove —
a new addons-remove IPC that deletes the folder under the extensions
directory, refuses bundled add-ons (they would only be reseeded), and
clears the dock prefs it left behind.
2026-09-22 20:43:50 +02:00
|
|
|
|
// Delete a non-bundled extension's folder (Settings › Extensions › ⋯ › Remove).
|
|
|
|
|
|
removeAddon: (id) => ipcRenderer.invoke("addons-remove", id),
|
2026-09-30 02:16:11 +02:00
|
|
|
|
openAddonsDir: () => ipcRenderer.invoke("addons-open-dir"),
|
|
|
|
|
|
reloadAddons: () => ipcRenderer.invoke("addons-reload"),
|
|
|
|
|
|
// Add-on update flow. checkAddonUpdates hits the release manifest and
|
|
|
|
|
|
// stages any newer signed version; listStagedAddonUpdates reports what's
|
|
|
|
|
|
// waiting; applyStagedAddons promotes staged → active and reactivates the
|
|
|
|
|
|
// addon host so the new bytes load without a full Theseus restart.
|
|
|
|
|
|
// Community extensions from theseus.x/extensions: the catalog (with what
|
|
|
|
|
|
// is installed already) and a verified install/update of one entry.
|
|
|
|
|
|
communityCatalog: () => ipcRenderer.invoke("addons-community-catalog"),
|
|
|
|
|
|
installCommunity: (id) => ipcRenderer.invoke("addons-install-community", id),
|
|
|
|
|
|
checkAddonUpdates: () => ipcRenderer.invoke("addons-check-updates"),
|
|
|
|
|
|
listStagedAddonUpdates: () => ipcRenderer.invoke("addons-list-staged"),
|
fix(theseus): extension updates re-check, announce and install in place
Updates published after launch never showed: the add-on channel was
checked once, 30 s after boot, and staged copies only applied on the
next launch with nothing telling the user. On 2026-09-22 Aegis 0.8.3
and VPN 0.1.3 landed minutes after the app's only check and stayed
invisible through manual scans made earlier and a restart made before
they were published.
Now: the check repeats every 4 hours; every check (boot, timer, manual,
add-on-driven) reports what is staged to the chrome, which shows a chip
for staged extensions; clicking it, or the "Update to vX" button that
appears on the extension's row and detail in Settings, promotes the
staged folder over the installed one and rebuilds the add-on host, so
the new version runs without a restart. Plug-ins (Aegis) are excluded
from the chip and the hot swap — a wallet updates from its own panel
and applies on the next launch.
Also from the same review: the new-tab button follows the last tab and
parks after the scroll arrow only when the strip overflows; Tor sits
left of the Aegis chip; plug-ins no longer appear in Settings ›
Extensions (they have Plug-ins); the extension detail view has a
labelled Back button, a close button and a Check now button; the
promotion helper returns what it promoted and accepts a filter.
2026-09-22 21:25:33 +02:00
|
|
|
|
applyStagedAddons: (id) => ipcRenderer.invoke("addons-apply-staged", typeof id === "string" ? id : undefined),
|
2026-09-27 20:37:30 +02:00
|
|
|
|
// Settings › Performance › Protections: talk to an add-on's own message
|
|
|
|
|
|
// handlers (Shield, Cookie Pop-ups) and open its panel for the details.
|
|
|
|
|
|
addonInvoke: (id, msg, payload) => ipcRenderer.invoke("addon-invoke", String(id || ""), String(msg || ""), payload),
|
|
|
|
|
|
openPanel: (panelId) => ipcRenderer.invoke("settings-open-panel", String(panelId || "")),
|
2026-09-27 22:01:28 +02:00
|
|
|
|
// Which page is showing (the address bar follows), Tor state + toggle for Privacy › Network.
|
|
|
|
|
|
reportSection: (slug) => ipcRenderer.invoke("settings-section", String(slug || "")),
|
|
|
|
|
|
torState: () => ipcRenderer.invoke("tor-state"),
|
|
|
|
|
|
toggleTor: () => ipcRenderer.invoke("toggle-tor"),
|
2026-09-30 02:16:11 +02:00
|
|
|
|
// OS locale — used by the Website-language row to label "Automatic (OS: …)".
|
|
|
|
|
|
systemLocale: () => ipcRenderer.invoke("system-locale"),
|
|
|
|
|
|
// Live settings updates — the toolbar chip, this page's Website-language
|
|
|
|
|
|
// row, and the Anti-fingerprinting Language row all edit the same setting;
|
|
|
|
|
|
// any of them writing pushes a "settings-update" the others react to.
|
|
|
|
|
|
onSettingsUpdate: (cb) => ipcRenderer.on("settings-update", (_e, d) => cb(d)),
|
|
|
|
|
|
// Ariadne's Thread plug-in (system-wide resolver). The state getter returns
|
|
|
|
|
|
// { state:"running"|"stopped"|"not-installed", installedVersion, bundledVersion,
|
|
|
|
|
|
// canUpdate, hasUninstaller }; the mutators prompt UAC for admin.
|
|
|
|
|
|
ariadneState: () => ipcRenderer.invoke("ariadne-state"),
|
|
|
|
|
|
ariadneToggle: (on) => ipcRenderer.invoke("ariadne-toggle", !!on),
|
|
|
|
|
|
ariadneInstall: () => ipcRenderer.invoke("ariadne-install"),
|
|
|
|
|
|
ariadneUpdate: () => ipcRenderer.invoke("ariadne-update"),
|
|
|
|
|
|
ariadneUninstall: () => ipcRenderer.invoke("ariadne-uninstall"),
|
feat(theseus/ariadne): settings panel — policy + per-source toggles + status report
Ariadne 0.1.13 exposed /api/status and per-source enable flags in
policy.json. Theseus's Plug-ins > Ariadne's Thread sub-page now wires those
into a full UI, no daemon restart, no UAC.
Added to the plugins-ariadne sub-page (after Status, before Remove):
Collision policy -- radio group (BCNR-first / ICANN-first) writes
C:\ProgramData\Ariadne\policy.json.policy; hot-reloaded
by the daemon within 5 s.
Sources -- 3-column grid, one row per source (snapshotHttps,
electrumWss, perQueryLookup, diskCache, localApi):
enable checkbox + last-state summary
(last success / last error / hit-miss counters /
disk-cache size+mtime). Toggle writes
policy.json.sources.<name>.enabled and re-polls after
the 5-s hot-reload tick so the state text catches up.
Status report -- <pre> JSON dump of GET http://127.0.0.1/api/status
with Copy report + Refresh report buttons. This is
the paste-me-into-support artefact for any diagnosis.
IPC wiring:
main.js
ariadne-get-status -> GET http://127.0.0.1/api/status ({ok, status|error})
ariadne-get-policy -> read C:\ProgramData\Ariadne\policy.json (or {})
ariadne-set-policy -> merge {policy}, write back (validates enum)
ariadne-set-source -> merge {sources.<name>.enabled}, write back
(validates against the known 5 names)
settings-preload.js
ariadneGetStatus, ariadneGetPolicy, ariadneSetPolicy, ariadneSetSource
All four handlers write policy.json as the local user; no UAC. Works because
install.ps1 grants BUILTIN\Users Modify on the file (0.1.7+).
Sub-page auto-refreshes state every time it opens (listens on the existing
'section' custom event dispatched by showSection).
Not building/shipping Theseus here -- this rides the next Theseus release.
Panel gracefully handles: daemon down (shows 'Daemon unreachable' with a
pointer to the Status toggle), localApi disabled (daemon returns 503, panel
shows the error), missing policy.json (all sources default to true).
2026-10-01 00:51:50 +02:00
|
|
|
|
// Local BNS daemon settings + status (0.1.13+). All read/write against
|
|
|
|
|
|
// C:\ProgramData\Ariadne\policy.json (user-writable ACL) and the daemon's
|
|
|
|
|
|
// own /api/status endpoint on 127.0.0.1. No UAC required for any of these.
|
|
|
|
|
|
ariadneGetStatus: () => ipcRenderer.invoke("ariadne-get-status"),
|
|
|
|
|
|
ariadneGetPolicy: () => ipcRenderer.invoke("ariadne-get-policy"),
|
|
|
|
|
|
ariadneSetPolicy: (policy) => ipcRenderer.invoke("ariadne-set-policy", String(policy || "")),
|
|
|
|
|
|
ariadneSetSource: (name, enabled) => ipcRenderer.invoke("ariadne-set-source", String(name || ""), !!enabled),
|
2026-09-30 02:16:11 +02:00
|
|
|
|
// Manual "Check for updates" — un-dismisses any existing chip and re-
|
|
|
|
|
|
// fetches the release manifest. Returns { updateAvailable, currentVersion }.
|
|
|
|
|
|
recheckUpdate: () => ipcRenderer.invoke("recheck-update"),
|
|
|
|
|
|
appVersion: () => ipcRenderer.invoke("app-version"),
|
|
|
|
|
|
restartApp: () => ipcRenderer.invoke("app-restart"),
|
2026-07-29 13:54:34 +02:00
|
|
|
|
});
|