feat(P6B.T9): PIN-Idle-Auto-Lock setting + idle watcher
Adds opt-in (default OFF) auto-lock: after X minutes of no user input the app calls signOut() (full memory wipe + PIN re-entry on next open). Settings dropdown (Aus / 5 / 15 / 30 / 60 min) lives in SecurityCenter below the existing wipe-on-close toggle. The idle timer is mounted in AppShell via useIdleAutoLock; activity events are throttled to 1 Hz to avoid timer thrash on rapid mouse movement. The localStorage key is added to PRESERVE_LOCAL_STORAGE so a wipe never silently disables the feature. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import {
|
||||
type AutoLockMinutes,
|
||||
getAutoLockMinutes,
|
||||
notifyAutoLockChanged,
|
||||
setAutoLockMinutes,
|
||||
} from '../lib/autoLockSettings';
|
||||
import { isWipeOnCloseEnabled, setWipeOnClose } from '../lib/memoryWipeSettings';
|
||||
import {
|
||||
changePin,
|
||||
@@ -21,6 +27,7 @@ export function SecurityCenter({ userId }: Props) {
|
||||
const [recovery, setRecovery] = useState<string | null>(null);
|
||||
const [migration, setMigration] = useState<LegacyMigrationReport | null>(null);
|
||||
const [wipeOnClose, setWipeOnCloseState] = useState<boolean>(() => isWipeOnCloseEnabled());
|
||||
const [autoLockMinutes, setAutoLockMinutesState] = useState<AutoLockMinutes>(() => getAutoLockMinutes());
|
||||
|
||||
async function handleRetryMigration() {
|
||||
setBusy(true); setMsg(null); setMigration(null);
|
||||
@@ -149,6 +156,39 @@ export function SecurityCenter({ userId }: Props) {
|
||||
</label>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3 className="mb-2 text-xs font-medium uppercase tracking-wide text-fg-muted">
|
||||
Auto-Lock nach Inaktivität
|
||||
</h3>
|
||||
<p className="mb-2 text-xs text-fg-muted">
|
||||
Verlangt erneute PIN-Eingabe nach der gewählten Inaktivitätsdauer. Empfohlen für gemeinsam genutzte Rechner.
|
||||
</p>
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div>
|
||||
<div className="text-sm font-medium text-fg">Automatisch sperren</div>
|
||||
<div className="text-xs text-fg-muted">
|
||||
Verlangt erneute PIN-Eingabe nach X Minuten Inaktivität.
|
||||
</div>
|
||||
</div>
|
||||
<select
|
||||
value={autoLockMinutes}
|
||||
onChange={(e) => {
|
||||
const next = Number(e.target.value) as AutoLockMinutes;
|
||||
setAutoLockMinutes(next);
|
||||
notifyAutoLockChanged(next);
|
||||
setAutoLockMinutesState(next);
|
||||
}}
|
||||
className="cursor-pointer rounded-md border border-line bg-surface-2 px-3 py-1.5 text-sm text-fg focus:border-accent focus:outline-none focus:ring-1 focus:ring-accent/40"
|
||||
>
|
||||
<option value={0}>Aus</option>
|
||||
<option value={5}>5 min</option>
|
||||
<option value={15}>15 min</option>
|
||||
<option value={30}>30 min</option>
|
||||
<option value={60}>60 min</option>
|
||||
</select>
|
||||
</div>
|
||||
</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>
|
||||
|
||||
Reference in New Issue
Block a user