feat(desktop): optional wipe-on-close (Settings -> Sicherheit)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { isWipeOnCloseEnabled, setWipeOnClose } from '../lib/memoryWipeSettings';
|
||||
import {
|
||||
changePin,
|
||||
type LegacyMigrationReport,
|
||||
@@ -19,6 +20,7 @@ export function SecurityCenter({ userId }: Props) {
|
||||
const [msg, setMsg] = useState<string | null>(null);
|
||||
const [recovery, setRecovery] = useState<string | null>(null);
|
||||
const [migration, setMigration] = useState<LegacyMigrationReport | null>(null);
|
||||
const [wipeOnClose, setWipeOnCloseState] = useState<boolean>(() => isWipeOnCloseEnabled());
|
||||
|
||||
async function handleRetryMigration() {
|
||||
setBusy(true); setMsg(null); setMigration(null);
|
||||
@@ -126,6 +128,27 @@ export function SecurityCenter({ userId }: Props) {
|
||||
)}
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3 className="mb-2 text-xs font-medium uppercase tracking-wide text-fg-muted">
|
||||
Cache beim Schließen leeren
|
||||
</h3>
|
||||
<p className="mb-2 text-xs text-fg-muted">
|
||||
Beim Beenden der App werden alle entschlüsselten Caches gelöscht. Beim nächsten Start
|
||||
musst du wieder deine PIN eingeben. Empfohlen für gemeinsam genutzte Rechner.
|
||||
</p>
|
||||
<label className="inline-flex cursor-pointer items-center gap-2 text-sm">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={wipeOnClose}
|
||||
onChange={(e) => {
|
||||
setWipeOnClose(e.target.checked);
|
||||
setWipeOnCloseState(e.target.checked);
|
||||
}}
|
||||
/>
|
||||
<span>Aktivieren</span>
|
||||
</label>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3 className="mb-2 text-xs font-medium uppercase tracking-wide text-rose-400">Identität zurücksetzen</h3>
|
||||
<p className="mb-2 text-xs text-fg-muted">Erstellt einen neuen Schlüssel. Alle alten Chats werden unlesbar.</p>
|
||||
|
||||
@@ -21,6 +21,7 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { ensureInstallId } from '../lib/installId';
|
||||
import { wipeLocalState } from '../lib/memoryWipe';
|
||||
import { isWipeOnCloseEnabled } from '../lib/memoryWipeSettings';
|
||||
import { setSecretStoreUser } from '../lib/secretStore';
|
||||
import { supabase } from '../lib/supabase';
|
||||
import { cachedUserKey, ensureLegacyMigrated } from '../lib/userIdentity';
|
||||
@@ -195,6 +196,18 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
void registerWebPush(installId);
|
||||
}, [session]);
|
||||
|
||||
// Wipe-on-close: register a handler the main process pings on `before-quit`
|
||||
// when the user has enabled the Settings → Sicherheit toggle. No-op outside
|
||||
// Electron (web build has no preload bridge) or when the toggle is off.
|
||||
useEffect(() => {
|
||||
if (typeof window.electronAPI?.onWipeBeforeQuit !== 'function') return;
|
||||
const unsub = window.electronAPI.onWipeBeforeQuit(async () => {
|
||||
if (!isWipeOnCloseEnabled()) return;
|
||||
await wipeLocalState(session?.user.id ?? null);
|
||||
});
|
||||
return unsub;
|
||||
}, [session?.user.id]);
|
||||
|
||||
// Auto online/offline transition.
|
||||
//
|
||||
// - On mount with a session whose last persisted state is `offline`, flip
|
||||
|
||||
@@ -15,6 +15,7 @@ const PRESERVE_LOCAL_STORAGE = new Set([
|
||||
'chatapp.theme',
|
||||
'chatapp.locale',
|
||||
'chatapp.installId',
|
||||
'chatapp.wipeOnClose.v1',
|
||||
'i18nextLng',
|
||||
]);
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// Persisted toggle for the "wipe local caches on app close" feature.
|
||||
// Read by SecurityCenter (UI) and AuthContext (renderer-side IPC handler).
|
||||
//
|
||||
// Stored in localStorage so the preference survives sessions without
|
||||
// touching the secret-store or SQLite. The key is on the preserve
|
||||
// whitelist in lib/memoryWipe.ts so a sign-out wipe (or a closing wipe)
|
||||
// doesn't blow away the user's own preference.
|
||||
const KEY = 'chatapp.wipeOnClose.v1';
|
||||
|
||||
export function isWipeOnCloseEnabled(): boolean {
|
||||
try {
|
||||
return window.localStorage.getItem(KEY) === '1';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function setWipeOnClose(enabled: boolean): void {
|
||||
try {
|
||||
window.localStorage.setItem(KEY, enabled ? '1' : '0');
|
||||
} catch {
|
||||
/* ignored */
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user