Six user-visible improvements + supporting infra, all uncommitted from
the earlier session-in-progress state. Ships together in one release.
Chrome / tabs
- Same-size tabs: flex 1 1 0 with max 200px, min 60px. Container gets
overflow: hidden so many tabs shrink evenly instead of scrolling out.
- Drag-and-drop tab reordering. HTML5 drag events on each .tab; drop
side chosen by pointer x within target (Chrome UX). New move-tab IPC
splices the tabs array + re-emits.
Address bar
- Persistent history at userData/history.json capped at 500 LRU. Ranked
by host-prefix > url-prefix > contains > title-contains > recency.
- Floating suggestions dropdown (addressPicker WebContentsView) anchored
under the URL bar. Debounced 80ms input; ArrowUp/Down forward to the
picker via address-cursor IPC; Enter fires goURL; blur closes after
160ms so click-through registers. New files address-picker.html +
address-picker-preload.js. Cleared by existing clearHistoryOnQuit.
Password autofill (A.2 MVP)
- Green key chip in the address bar appears when the vault is UNLOCKED
and the active tab's host has matching credentials (exact hostname
match for phase 1; eTLD+1 upgrade queued as A.2.5).
- Click chip → floating picker of usernames. Click a match → main.js
runs a small script in the active tab: finds first visible
input[type=password]:not([disabled]), walks the same form for a
visible text/email/tel/url/search input whose name/id/autocomplete
matches /username|user|email|login|account|id/, fills both via the
native value setter + dispatches input/change so React/Vue-controlled
inputs update. New files pw-fill.html + pw-fill-preload.js.
- emitPwAvailability fires from pushNav + vault setup/unlock/lock so
the chip's visibility + count stays accurate.
Bookmarks bar
- Right-click context menu on the favorites bar. On empty area:
"Add current page" (or "Remove current page" if already saved). On a
specific bookmark: "Open", "Edit title…" (prompt), "Remove", plus
the add/remove-current entry. Uses a shared .ctxmenu style mirroring
the settings ctxmenu (dark/light aware).
- Empty-state text updated to mention right-click.
Home page
- Larger responsive card grid: auto-fill minmax(260-280px, 1fr) with
breakpoints at 600/900/1200. Cards have a subtitle line, a colored
badge (on-chain / Sia / server / custom), and edit affordances that
reveal only in Edit mode.
- User-editable set: Edit toggle reveals per-card ✎/✕ + a dashed "+ Add
card" tile. Modal for add/edit with title / URL / subtitle / badge.
Reset-to-defaults button.
- Persisted at userData/home-cards.json. New home-preload.js exposes
window.home = { getCards, setCards, resetCards, navigate }. IPC
handlers in main.js validate sender.getURL() matches our own
home.html — third-party pages see the API shape via the preload but
can't act on the user's local cards.
- Fallback set of 2 cards renders when window.home is unavailable
(e.g. opening home.html directly outside Electron for preview) so
the grid is never blank.
Docs
- TheseusNavigator/ROADMAP-identity-wallet.md — the phased plan for
the two independent strands (password manager A.2/3, browser wallet
B.1-6). Committed earlier this session; re-listed here for context.
- TheseusNavigator/SESSION-PROMPT-identity-wallet.md — pastable
kickoff for the next session picking up either strand.
Files added to build.files: address-picker.html,
address-picker-preload.js, pw-fill.html, pw-fill-preload.js,
home-preload.js.
9.2 KiB
Identity + wallet roadmap
Two independent strands, both rooted in the same BCH-style seed-with-hardened- derivation model. Order them however makes sense to the session picking this up; strands don't block each other.
Strand A — Password manager. Local-first vault, deterministic derivation per site+username, optional Sia backup for cross-device. Strand B — Browser-integrated BCH wallet. MetaMask-style provider so Silent Mode pages (and any BCH-native dApp) can request signatures, payments, and BCNR name operations from the user's wallet.
Both use the SAME seed via distinct hardened purpose subtrees so one compromise can't leak the other:
m / 44' / 145' BCH wallet (SLIP-44) ← wallet already ships
m / 1381' / 0' passwords ← phase 1 shipped
m / 1414' / 0' messenger (Nostr etc.) ← future
Same seed, three purposes, no cross-derivation. See DESIGN-password-manager.md for the discipline.
Strand A — Password manager
A.1 — SHIPPED (0.0.3, 9c09955e)
- Local encrypted vault at
<userData>/passwords.vault - AES-256-GCM under PBKDF2 (200k iters, SHA-256) master-password key
- BIP39 mnemonic → seed → HKDF purpose root
- Deterministic derivation per (domain, username, version, rules)
- Settings UI: setup / locked / unlocked panels, add/edit/reveal/copy/delete
- IPC surface: pwStatus/Setup/Unlock/Lock/List/Get/Add/Update/Remove/Generate
- 12 crypto unit tests, all passing
A.2 — Autofill (~ 1 week)
The user-visible next step. Right now users must copy from Settings.
- ContentScript injected on every page (Electron
session.defaultSession.setPreloadsOR per-webContents preload extension) - Watch
input[type=password]+ adjacent username field on load AND on DOM mutation (SPAs). Debounce. - Origin binding via eTLD+1 using the public suffix list. Ship a
bundled snapshot of https://publicsuffix.org/list/public_suffix_list.dat
under
Argus/data/soevil-google.comcan't fillgoogle.com. - Toolbar affordance: a key icon in the address bar OR the shield's overlay grows a "Passwords" chip when entries exist for the current origin. Click → pick which credential to fill.
- Keyboard shortcut: Ctrl+Shift+L to fill the current form.
- Save prompt: when a form submit yields a password field the vault hasn't seen, prompt "Save this password? (Generate strong one instead?)"
- Per-origin permission cached: sites that were already refused don't re-prompt.
- Tests: origin-binding table (eTLD+1 for suffix corner cases —
*.co.uk,*.compute.amazonaws.com, IDN), autofill DOM injection vector coverage.
A.3 — Sia backup / cross-device restore (~ 3-5 days)
Opt-in cloud sync of the encrypted vault blob.
- New setting: "Sync vault to Sia". Off by default.
- User provides their own Sia S3 endpoint + credentials (like the operator's
sia-s3.json), OR opts to use the operator's public relay atsia://silentmode.st/vault/<vaultId>(metadata leaks: only "this vaultId exists", nothing else — vault is encrypted end-to-end). - On save: upload the encrypted-blob bytes to
bucket/vault-<id>.bin. Include an integrity hash in the local vault header. - On new-device setup: user picks "Restore from Sia" → enters vaultId + master password → download blob → decrypt.
- Explicit non-goal: no operational sync (last-write-wins across devices, no merge). Phase A.3 is "clone the vault to another laptop", not "keep two laptops perfectly in step". Multi-device concurrent-edit is A.4 if we ever want it.
A.4 — Nice-to-haves
Order these however makes sense; each is small and independent.
- Import from Bitwarden JSON / KeePass CSV / Firefox CSV
- Export to same
- Password strength meter on the paste-a-password entry
- Auto-lock after N minutes of Theseus idle
- Password-history per entry (previous versions kept, so a rotation doesn't lose the old password until the user confirms it's no longer needed anywhere)
- Compromised-password check via HIBP k-anonymity API (opt-in, sends a 5-char SHA-1 prefix only)
- Password-strength / composition rules from the site's
passwordrulesattribute (WICG spec) so generated passwords satisfy site policy
Strand B — Browser-integrated BCH wallet
MetaMask-style window.bcnr (or window.bch) provider that lets a page
request signatures, payments, and name operations from the user's wallet.
The wallet already exists in site/js/ for the registrar flow; this
strand generalises it to a per-origin API for any page.
B.1 — Design (start here) (~ 2-3 days)
Ship the doc before writing code. Two hard problems to nail:
-
Permission model. Chrome dapp providers have taught us how easily this becomes malware infrastructure. The doc must lock down:
- Permission granularity: per-origin, per-method, per-amount
- First-use always shows a modal (never auto-approves)
- Persistent permissions revocable in Settings > Wallet > Sites
- "You're on a BCNR name backed by an on-chain contract" vs "You're on random-site.com" — trust badges the user can see before signing
- Anti-phishing: display the recipient's cash address in the confirmation dialog with a big warning if the address changes mid-session
-
API surface. Match existing convention where possible so BCH dApp developers don't learn a Silent Mode-only dialect:
bcnr.getAccounts()— returns cash addresses the user has approved for this originbcnr.requestAccount()— first-use modalbcnr.signMessage({message, address})— BIP-137 style, used for BCNR name registration and auth flowsbcnr.sendPayment({to, amount, memo})— modal-confirmed BCH sendbcnr.resolveName(name)— no permission needed; BCNR lookupbcnr.registerName({name, records}),bcnr.updateName(name, records)— modal-confirmed; ties into the site/register.html flow
Deliverable: TheseusNavigator/DESIGN-integrated-wallet.md in the same
shape as DESIGN-password-manager.md.
B.2 — Injection scaffold + read-only APIs (~ 1 week)
- ContentScript that injects
window.bcnron every page load. Isolated world (Electron'scontextIsolation: truealready enforces this) so page JS can't tamper with the provider. - Provider is an event-emitting object that speaks JSON-RPC over postMessage to the preload, which forwards to main via IPC.
- Read-only methods (no permission needed):
resolveName,getBcnrTlds,isRegistered,getRecordVersion. - Tests: page-script → provider → main round trip; provider surface matches the spec.
B.3 — Signature + payment APIs (~ 2-3 weeks)
- Permission-gated:
requestAccount,signMessage,sendPayment. - Reuse the existing wallet in
site/js/(libauth-based) as the signing core; wrap it in a main-process handler that reads the wallet'swallets.json(already encrypted with the wallet passphrase). - Modal confirmations rendered as a new WebContentsView overlay (same pattern as popover/engine-picker/downloads).
- Site permissions persisted in
userData/wallet-permissions.json. - Settings → Wallet section: list connected sites, revoke per-site or per-method.
B.4 — BCNR name operations (~ 1 week)
registerName,updateName— thin wrappers over the existingArgus/src/register.js/update.jsflows.- Sanity: same modal-first pattern; show the exact record payload before signing (users need to see what's going on-chain permanently).
B.5 — Nostr messenger integration (~ 2-3 weeks)
Bring the messenger strand in as a parallel purpose. Same seed under
m/1414'/0', so users who set up passwords in strand A already have
messenger keys.
- Derive Nostr keys (secp256k1, npub/nsec encoding) from the messenger purpose root
window.nostrNIP-07 provider (widely-supported protocol, dozens of compatible clients)- Chrome integration: address bar chip when a Nostr-native site connects
- Threat model: Nostr keys don't hold funds, but do bind identity — compromise = impersonation. Same modal-first permission model.
B.6 — Advanced: connect-wallet UX
- QR-pairing so a mobile Ariadne can act as a hardware-wallet-like signer for a desktop Theseus
- Multisig confirmations (2-of-3 with a hardware wallet + Theseus + Nostr-relayed remote signer)
Cross-strand dependencies
- Both strands rely on the crypto module at
Argus/src/lib/password-vault.js. Extractbip39ToSeed+seedToPurposeRootinto aseed-derive.jsmodule the wallet strand can also import cleanly. - Both strands should share the master-password unlock. If a user has the vault unlocked and the wallet locked (or vice versa), the second unlock should not re-prompt.
Non-goals
- No third-party cloud sync. Sia is the only sync target we bless.
- No Chromium password-manager UI reuse. Ergonomics don't fit our threat model (Google Sync-shaped).
- No Ethereum / Solana / other-chain support in Strand B. This is BCH- specific; multi-chain is a separate future decision.
- No hardware-wallet abstraction layer in phase 1. Ledger/Trezor integration is a phase 4 conversation.
- No autofill for credit cards, addresses, or contact forms. Each has security nuances that deserve their own design pass. Password-only.