feat(desktop): wipe local crypto + caches on sign-out

This commit is contained in:
byGalax
2026-05-16 17:09:01 +02:00
parent 41359816f1
commit 50bfb5b137
2 changed files with 58 additions and 1 deletions
+54
View File
@@ -0,0 +1,54 @@
import { clearConvKeyCache } from '@chat-app/shared/chat';
import { devLocalSecretStore } from './secretStore';
// Aggressively scrub local crypto + chat caches on sign-out (and on
// app-close if the user opted in). Preserves things that aren't sensitive
// and would be annoying to lose (theme, locale, install-id).
//
// We can't enumerate IndexedDB names without async + the indexedDB API,
// so we list the ones we know about explicitly. Adding a new local store
// later? Append to LOCAL_DBS.
const LOCAL_DBS = ['soundboard', 'message-cache', 'chatapp-attachments'];
const PRESERVE_LOCAL_STORAGE = new Set([
'chatapp.theme',
'chatapp.locale',
'chatapp.installId',
'i18nextLng',
]);
export async function wipeLocalState(userId: string | null): Promise<void> {
// 1. Per-conversation key cache (in-memory).
try { clearConvKeyCache(); } catch { /* never throws but be defensive */ }
// 2. Stronghold / secret-store: drop the user-priv blob for this user.
if (userId) {
try { await devLocalSecretStore.removeSecret('chatapp.userpriv.' + userId); }
catch (err) { console.warn('[wipe] userpriv remove failed', err); }
}
// 3. localStorage — preserve only the explicit whitelist.
try {
const keysToDrop: string[] = [];
for (let i = 0; i < window.localStorage.length; i++) {
const k = window.localStorage.key(i);
if (k && !PRESERVE_LOCAL_STORAGE.has(k)) keysToDrop.push(k);
}
for (const k of keysToDrop) window.localStorage.removeItem(k);
} catch (err) { console.warn('[wipe] localStorage clear failed', err); }
// 4. sessionStorage — always full.
try { window.sessionStorage.clear(); } catch { /* ignored */ }
// 5. IndexedDB — delete known databases. Resolves even when blocked so
// we don't hang sign-out forever.
await Promise.allSettled(LOCAL_DBS.map((name) => new Promise<void>((resolve) => {
try {
const req = window.indexedDB.deleteDatabase(name);
req.onsuccess = () => resolve();
req.onerror = () => resolve();
req.onblocked = () => resolve();
} catch { resolve(); }
})));
}