Origin: code review of PR #45 (screen-lock app gate), finding #4 (was above-the-cut). The safe code-level fixes on the review branch shrink this bug's blast radius but do NOT fully resolve it; the real fix is architectural and needs a device-tested migration, so it is split out here.
Problem
AccountEntity and CredentialEntity live in the same libremail.db that SQLCipher encrypts under the auth-bound passphrase when app-lock + encrypted-cache are on. When that key is invalidated (a genuine biometric re-enrollment or lock removal/re-add), the whole file becomes undecryptable, so the "clear + re-sync" recovery wipes the user's accounts and stored credentials along with the mail cache — and the re-sync no-ops on an empty accounts table, dropping the user into onboarding. The credentials' own sealing key (the non-auth KeystoreCrypto master key) actually survives the invalidation; only the SQLCipher container they sit in is lost.
Already mitigated on the fix branch (not a substitute for the fix)
sealWithMaster() now deletes the orphaned auth key, and KeyInvalidationPolicy no longer wipes on a merely-lapsed auth window — so spurious wipes are gone. Only a genuine key invalidation now triggers the wipe, and it still destroys accounts.
Suggested fix
Move AccountEntity / CredentialEntity (and likely AccountSettingsEntity) into a separate small Room database that is NOT bound to the auth key — sealed by the surviving master key (or plaintext with the existing column-level master-key encryption for credentials) — so a cache-key invalidation wipes only the mail cache and the user stays signed in. Requires:
a new database + DAOs move + Hilt wiring,
a one-time data migration for existing installs (copy the account/credential tables out of libremail.db, then drop them), crash-safe and idempotent, handling the currently-encrypted case,
exported Room schemas + a migration test (per CLAUDE.md), and
on-device validation of the upgrade path (a botched migration would destroy real users' accounts — strictly worse than the current bug, which is why it was deliberately NOT attempted blind on the review branch).
Origin: code review of PR #45 (screen-lock app gate), finding #4 (was above-the-cut). The safe code-level fixes on the review branch shrink this bug's blast radius but do NOT fully resolve it; the real fix is architectural and needs a device-tested migration, so it is split out here.
## Problem
`AccountEntity` and `CredentialEntity` live in the same `libremail.db` that SQLCipher encrypts under the **auth-bound** passphrase when app-lock + encrypted-cache are on. When that key is invalidated (a genuine biometric re-enrollment or lock removal/re-add), the whole file becomes undecryptable, so the "clear + re-sync" recovery wipes the user's accounts and stored credentials along with the mail cache — and the re-sync no-ops on an empty accounts table, dropping the user into onboarding. The credentials' own sealing key (the non-auth `KeystoreCrypto` master key) actually survives the invalidation; only the SQLCipher container they sit in is lost.
## Already mitigated on the fix branch (not a substitute for the fix)
- `sealWithMaster()` now deletes the orphaned auth key, and `KeyInvalidationPolicy` no longer wipes on a merely-lapsed auth window — so **spurious** wipes are gone. Only a genuine key invalidation now triggers the wipe, and it still destroys accounts.
## Suggested fix
Move `AccountEntity` / `CredentialEntity` (and likely `AccountSettingsEntity`) into a separate small Room database that is NOT bound to the auth key — sealed by the surviving master key (or plaintext with the existing column-level master-key encryption for credentials) — so a cache-key invalidation wipes only the mail cache and the user stays signed in. Requires:
- a new database + DAOs move + Hilt wiring,
- a one-time data migration for existing installs (copy the account/credential tables out of `libremail.db`, then drop them), crash-safe and idempotent, handling the currently-encrypted case,
- exported Room schemas + a migration test (per CLAUDE.md), and
- on-device validation of the upgrade path (a botched migration would destroy real users' accounts — strictly worse than the current bug, which is why it was deliberately NOT attempted blind on the review branch).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Origin: code review of PR #45 (screen-lock app gate), finding #4 (was above-the-cut). The safe code-level fixes on the review branch shrink this bug's blast radius but do NOT fully resolve it; the real fix is architectural and needs a device-tested migration, so it is split out here.
Problem
AccountEntityandCredentialEntitylive in the samelibremail.dbthat SQLCipher encrypts under the auth-bound passphrase when app-lock + encrypted-cache are on. When that key is invalidated (a genuine biometric re-enrollment or lock removal/re-add), the whole file becomes undecryptable, so the "clear + re-sync" recovery wipes the user's accounts and stored credentials along with the mail cache — and the re-sync no-ops on an empty accounts table, dropping the user into onboarding. The credentials' own sealing key (the non-authKeystoreCryptomaster key) actually survives the invalidation; only the SQLCipher container they sit in is lost.Already mitigated on the fix branch (not a substitute for the fix)
sealWithMaster()now deletes the orphaned auth key, andKeyInvalidationPolicyno longer wipes on a merely-lapsed auth window — so spurious wipes are gone. Only a genuine key invalidation now triggers the wipe, and it still destroys accounts.Suggested fix
Move
AccountEntity/CredentialEntity(and likelyAccountSettingsEntity) into a separate small Room database that is NOT bound to the auth key — sealed by the surviving master key (or plaintext with the existing column-level master-key encryption for credentials) — so a cache-key invalidation wipes only the mail cache and the user stays signed in. Requires:libremail.db, then drop them), crash-safe and idempotent, handling the currently-encrypted case,