fix(security): app-lock lifecycle consistency (grace across Back, passphrase eviction limits) #119

Merged
JMR-dev merged 2 commits from fix-applock-lifecycle into main 2026-07-02 08:50:15 +00:00
2 Commits
Author SHA1 Message Date
Jason Ross 18f52e1cb9 Merge branch 'main' into fix-applock-lifecycle 2026-07-02 03:40:26 -05:00
JMR-devandClaude Fable 5 c39f803c97 fix(security): app-lock grace survives activity recreation; clarify passphrase eviction
Two lifecycle-consistency fixes from PR #45's review (issue #101).

1. Grace across Back/recreation. The AppLockGate state machine was a field of
   the Activity-scoped AppLockViewModel, so Back on the task root (which finishes
   the Activity and clears its ViewModelStore on API 29/30) dropped the grace
   marker and re-armed a fresh LOCKED gate, demanding full re-auth on return —
   unlike leaving via Home. Provide AppLockGate as an application-scoped @Singleton
   (SecurityModule) and inject it into the ViewModel, so the same instance is
   reused across recreation and the 30s grace behaves identically for Back and
   Home. A genuine cold start (process death) still constructs a fresh, LOCKED gate.

2. PassphraseSession eviction. The KDoc promised the passphrase is "cleared on
   lock, timeout," but nothing re-locked it on grace expiry and full eviction is
   not achievable without a DB close/reopen (provideDatabase runs once per process;
   owned by #93 / #111). Correct the KDoc to state the process-lifetime limitation
   explicitly and add a code comment at the timeout re-lock deferring full eviction
   to #93 / #111. We deliberately do NOT call session.lock() on timeout: it is the
   only separately-held copy but also drives EncryptedCacheGuard, so clearing it
   while merely locked (not exited) would stall background sync/push even though the
   DB stays open — not a correct partial eviction. No DatabaseModule changes.

Tests (JVM): extend AppLockGateTest to cover grace surviving a reused-instance
recreation within and beyond the window, and a fresh gate starting LOCKED; add
AppLockViewModelTest asserting the gate is an injected dependency the ViewModel
delegates to (onBackground/onAuthError).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 03:28:52 -05:00