theseus/settings-preload.js
Local Dev 3243add70e Theseus ID in Theseus: window.theseusId.signIn and Settings › Theseus ID
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.
2026-10-04 20:48:07 +02:00

111 lines
8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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"),
});