The PIN could only be six digits and was set from three bare inputs; the unlock prompt sat at the top of the page; and the password manager only filled when you found the key chip, never offered to save, and "Clear cookies on quit" signed you out of every site, including the ones whose login the vault already holds. - PINs are 6 to 8 digits. The PIN record stores its length so pads draw the right number of dots and submit on the last digit; a PIN of the wrong length is refused without a strike, so an older Aegis pad cannot burn the count against an 8-digit PIN. - Settings sets a PIN in steps: master password, choose the PIN on a pad (6/7/8), repeat it, done. The locked vault opens Theseus's own prompt, which is now centred, with the PIN pad or the master password field. - After a sign-in or sign-up form is sent and the page moves on, Theseus offers to save (or update) the login, with an optional "ask for my PIN or password before filling it". Focusing a login form offers the saved logins under it; on a locked vault it offers to unlock first. A failed login (the password field still showing) gets no offer. - "Keep sign-ins for sites in your vault" (on): the quit clear spares the cookies and site storage of sites with a saved login. Their hostnames are kept sealed with the OS keystore so the list is readable at quit while the vault is locked. Verified end to end on a scratch profile: signed in, restarted, still signed in; another site's cookie was cleared.
100 lines
7 KiB
JavaScript
100 lines
7 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),
|
||
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"),
|
||
});
|