diff options
| author | Adam Soltys <[email protected]> | 2026-08-08 11:53:10 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-08-08 11:53:10 -0700 |
| commit | 8b2c709ca1891668a2bbbf373f388fa6271a37a7 (patch) | |
| tree | 1e6eb319ca0486d880eaf631b00f520509101f1b | |
| parent | 14f7c6ddbe44fa07572e4e86b25605ae916f3271 (diff) | |
| download | coinosv3-8b2c709ca1891668a2bbbf373f388fa6271a37a7.tar.gz coinosv3-8b2c709ca1891668a2bbbf373f388fa6271a37a7.zip | |
Switching accounts hangs up first: feature runtimes stop on lock and activate, so no one inherits another wallet's chats or steals its inbox
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01DbA53PJA8fgSvMcEzfuw22
| -rw-r--r-- | src/app.js | 9 | ||||
| -rw-r--r-- | src/features/messages.js | 1 |
2 files changed, 10 insertions, 0 deletions
@@ -857,6 +857,12 @@ async function enterWallet(mnemonic, passphrase, opts = {}) { // Load an account into the wallet and start scanning. Full-account seeds are // kept in sessionStorage (ephemeral); a refresh restores the open account. async function activateAccount(acc, opts = {}) { + // Tear down the previous account's feature runtime BEFORE the wallet + // switches identity: live relay subscriptions and in-memory state (chat + // threads, decrypted DMs) belong to the old keys, and surviving into this + // account they'd both leak the old account's messages on screen and block + // the new account's own subscriptions from ever starting. + for (const f of FEATURES) { try { f.stop && f.stop(); } catch {} } activeId = acc.id; // A gift link generates this wallet only to claim into. Keep it provisional // until the user commits (claims, or chooses to keep it / enters the wallet), @@ -1437,6 +1443,9 @@ function applyBootAutoLogout() { function lock({ offerPassword = false } = {}) { wallet.stopRealtime(); + // A locked session must not keep listening as the account that just left — + // and whatever logs in next must not inherit its threads or subscriptions. + for (const f of FEATURES) { try { f.stop && f.stop(); } catch {} } clearAccounts(); vaultPassword = null; wallet.load({ mnemonic: '', passphrase: '', netName: getNetwork(), offline: false }); diff --git a/src/features/messages.js b/src/features/messages.js index ab2e900..598e661 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -1892,6 +1892,7 @@ export function messagesFeature(ctx) { rooms.clear(); threads.clear(); pendingDirect.clear(); + seenWraps.clear(); // the next account must decrypt wraps this one couldn't dmStarted = false; listsSynced = false; }, |
