Root cause of 'two users can't chat': all accounts on one browser shared a single IndexedDB, so the second registration overwrote the first's Signal identity keys, corrupting both. Verified via two-isolated-client integration test (real crypto.js + store.js) that the protocol itself is correct. - store.js: useAccount(username) namespaces IndexedDB as cipher:<username>; keys generated at registration now persist under the right account - accounts.js: localStorage-backed account registry + active pointer - app.js: multi-account boot/activate, account-switch/add/logout menu, error toasts on send/decrypt failures (no more silent failures) - login guards against missing on-device keys (multi-device linking still TODO) - SW cache v2->v3 + precache accounts.js Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
39 lines
1.1 KiB
JavaScript
39 lines
1.1 KiB
JavaScript
// Account registry, stored in localStorage (global to the origin, unlike the
|
|
// per-account IndexedDB). Tracks which accounts have signed in on this browser
|
|
// and which one is currently active. Tokens live here; private keys never do.
|
|
|
|
const KEY = "cipher.accounts";
|
|
const ACTIVE = "cipher.activeUser";
|
|
|
|
export function list() {
|
|
try {
|
|
return JSON.parse(localStorage.getItem(KEY) || "[]");
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export function save(acct) {
|
|
// acct: { userId, deviceId, username, displayName, token }
|
|
const others = list().filter((a) => a.username !== acct.username);
|
|
others.push(acct);
|
|
localStorage.setItem(KEY, JSON.stringify(others));
|
|
}
|
|
|
|
export function remove(username) {
|
|
localStorage.setItem(KEY, JSON.stringify(list().filter((a) => a.username !== username)));
|
|
if (getActiveUsername() === username) localStorage.removeItem(ACTIVE);
|
|
}
|
|
|
|
export function setActive(username) {
|
|
localStorage.setItem(ACTIVE, username);
|
|
}
|
|
|
|
export function getActiveUsername() {
|
|
return localStorage.getItem(ACTIVE);
|
|
}
|
|
|
|
export function getActive() {
|
|
const u = getActiveUsername();
|
|
return u ? list().find((a) => a.username === u) || null : null;
|
|
}
|