aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-08 11:53:10 -0700
committerAdam Soltys <[email protected]>2026-08-08 11:53:10 -0700
commit8b2c709ca1891668a2bbbf373f388fa6271a37a7 (patch)
tree1e6eb319ca0486d880eaf631b00f520509101f1b /src
parent14f7c6ddbe44fa07572e4e86b25605ae916f3271 (diff)
downloadcoinosv3-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
Diffstat (limited to 'src')
-rw-r--r--src/app.js9
-rw-r--r--src/features/messages.js1
2 files changed, 10 insertions, 0 deletions
diff --git a/src/app.js b/src/app.js
index abd73c6..531283e 100644
--- a/src/app.js
+++ b/src/app.js
@@ -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;
},