Pages of Silent Mode projects can now sign the user in with their Theseus ID instead of a wallet phrase typed into the page. Theseus writes the sign-in message itself, takes the origin from the committed top frame, and signs as a project only on an origin that project's list includes, so a phishing page cannot get another project's signature and no page can use the ID key to sign anything else. - lib/theseus-id.cjs: the policy (first sign-in always asks and lets the user pick a private or One ID; Silent Mode projects are silent after that while the vault is open; per-site "always"; 10 silent signatures per minute per origin), the per-project record encrypted under a key derived from the vault, origin-list fetching with a 1 h cache and a 7-day stale fallback, and ID moves that send a proof signed by both keys and only finish once the project confirms. - A locked vault is unlocked only for a page the user just clicked or typed in: navigator.userActivation alone is true on load for pages opened with loadURL, which would let a page pop the vault prompt by itself. - Settings › Theseus ID: default mode, One ID, automatic sign-in toggle, signed-in projects (always, change ID, new ID, revoke) and a recovery key behind a fresh PIN / password check. - TheseusID/registry/projects.json is the first-party list (Hephaestus, Sirius, Pithos); it and TheseusID/lib ship as extraResources. - Token-aware cashaddrs (BNS owners) now decode for owner-signed lists. Verified on a scratch profile against a local test project whose server checks signatures with TheseusID/lib/verify.mjs: locked vault on load gives "locked" with no prompt, first sign-in prompt, silent second sign-in, a claimed foreign project refused without a prompt, an ID move that keeps the project's account, and the recovery key behind the confirm prompt.
111 lines
8 KiB
JavaScript
111 lines
8 KiB
JavaScript
const { contextBridge, ipcRenderer } = require("electron");
|
||
contextBridge.exposeInMainWorld("cfg", {
|
||
get: () => ipcRenderer.invoke("settings-get"),
|
||
set: (key, value) => ipcRenderer.invoke("settings-set", key, value),
|
||
engines: () => ipcRenderer.invoke("search-engines"),
|
||
addEngine: (eng) => ipcRenderer.invoke("add-engine", eng),
|
||
removeEngine: (id) => ipcRenderer.invoke("remove-engine", id),
|
||
setEngineEnabled: (id, on) => ipcRenderer.invoke("set-engine-enabled", id, on),
|
||
setEngineOrder: (ids) => ipcRenderer.invoke("set-engine-order", ids),
|
||
removeFromList: (id) => ipcRenderer.invoke("remove-from-list", id),
|
||
// 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),
|
||
// Quick-unlock PIN. pinSet proves the master password in main before
|
||
// wrapping it; pinUnlock opens Theseus's own PIN / password prompt.
|
||
pinStatus: () => ipcRenderer.invoke("vault-pin-status"),
|
||
pinSet: (pin, masterPassword) => ipcRenderer.invoke("vault-pin-set", { pin, masterPassword }),
|
||
pinClear: () => ipcRenderer.invoke("vault-pin-clear"),
|
||
pinCheckMaster: (masterPassword) => ipcRenderer.invoke("vault-check-master", masterPassword),
|
||
// Asks for the PIN or master password even while the vault is open.
|
||
pwConfirm: (reason) => ipcRenderer.invoke("vault-confirm", reason),
|
||
// Settings › Theseus ID. Each resolves { ok, result } or { ok: false, error: { code, message } }.
|
||
tidOverview: () => ipcRenderer.invoke("theseus-id-overview"),
|
||
tidSetDefaultMode: (mode) => ipcRenderer.invoke("theseus-id-set-default-mode", mode),
|
||
tidSetAuto: (on) => ipcRenderer.invoke("theseus-id-set-auto", !!on),
|
||
tidSetAlways: (projectId, on) => ipcRenderer.invoke("theseus-id-set-always", projectId, !!on),
|
||
tidRevoke: (projectId) => ipcRenderer.invoke("theseus-id-revoke", projectId),
|
||
tidMove: (projectId, to) => ipcRenderer.invoke("theseus-id-move", projectId, to),
|
||
tidCancelMove: (projectId) => ipcRenderer.invoke("theseus-id-cancel-move", projectId),
|
||
tidRotate: (projectId) => ipcRenderer.invoke("theseus-id-rotate", projectId),
|
||
tidUnlock: () => ipcRenderer.invoke("theseus-id-unlock"),
|
||
tidRecoveryKey: () => ipcRenderer.invoke("theseus-id-recovery-key"),
|
||
pinUnlock: () => ipcRenderer.invoke("vault-pin-unlock"),
|
||
// 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)),
|
||
// 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"),
|
||
// Blocklists: flagged names, the policy, and the "continue anyway" choices
|
||
blocklistState: () => ipcRenderer.invoke("blocklist-state"),
|
||
setBlocklistPolicy: (p) => ipcRenderer.invoke("blocklist-set-policy", p),
|
||
resetBlocklist: () => ipcRenderer.invoke("blocklist-reset"),
|
||
// 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),
|
||
// Delete a non-bundled extension's folder (Settings › Extensions › ⋯ › Remove).
|
||
removeAddon: (id) => ipcRenderer.invoke("addons-remove", id),
|
||
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"),
|
||
applyStagedAddons: (id) => ipcRenderer.invoke("addons-apply-staged", typeof id === "string" ? id : undefined),
|
||
// 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 || "")),
|
||
// 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"),
|
||
// 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"),
|
||
// 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),
|
||
// 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"),
|
||
});
|