fix(android): drop setUnlockedDeviceRequired from rootkey wrapper key#57
Merged
gmaclennan merged 2 commits intomainfrom May 7, 2026
Merged
fix(android): drop setUnlockedDeviceRequired from rootkey wrapper key#57gmaclennan merged 2 commits intomainfrom
gmaclennan merged 2 commits intomainfrom
Conversation
`setUnlockedDeviceRequired(true)` requires a configured secure lock screen at key generation and permanently invalidates the key if the user later disables their lock screen — even briefly, with no recovery path. For CoMapeo the rootkey IS the user's identity in every project they participate in, so either failure mode is identity loss; the marginal at-rest gain over baseline AndroidKeyStore hardware-backed AES-GCM doesn't justify it. Matches the trade-off expo-secure-store makes for the same reason. Existing wrapper keys keep working unchanged; this only affects fresh generations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…d gate Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
gmaclennan
added a commit
that referenced
this pull request
May 7, 2026
Reduces the production-code touch points exposed for non-production consumers (the bench app being the only one) down to a single override on each platform plus the existing nodejs-mobile stdout-redirect gate. - Drop `comapeoBackendArgs` (Gradle property + BuildConfig field + Kotlin parsing on Android; Info.plist key + Swift parsing on iOS). Was speculative surface for future telemetry-sink overrides; nothing in this PR populates it. The `--device=<tag>` argv injection the native loader does unconditionally is unaffected — production backend ignores unknown flags and Sentry tagging will read it. - Rename `comapeoBackendDir` → `comapeoEntryFile`. Override is now a filename inside `nodejs-project/` rather than a sibling directory. Bench plugin drops the bench entry into the consumer's `nodejs-project/` and lets AGP's asset merge (Android) / a Run Script Phase (iOS) co-locate it with the production bundle's `index.mjs`. Bench bundle's rollup output is renamed to `index.bench.mjs` and no longer ships a `package.json` (the production bundle's already does, in the same directory). - Drop `comapeoStubRootKey` end-to-end now that #57 (drop setUnlockedDeviceRequired from rootkey wrapper key) has landed on main. The stub existed only to work around BrowserStack stock no-screen-lock devices failing key generation; the real keystore path now succeeds for them, the bench backend's relaxed init handler ignores the rootkey bytes it receives, and the production branch in the FGS loader simplifies back to a single RootKeyStore.loadOrInitialize() call. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
setUnlockedDeviceRequired(true)from the AndroidKeyStore-backed rootkey wrapper key generated byRootKeyStore.Why
setUnlockedDeviceRequired(true)has two failure modes that are unacceptable for a key whose loss equals identity loss:rootkeyerror. Many CoMapeo users — community/conservation contexts, often on shared or no-lock devices — would simply not be able to use the app.KeyPermanentlyInvalidatedExceptionand OWASP MASTG-KNOW-0043, keys are "permanently and irreversibly invalidated once the secure lock screen is disabled". Re-adding the lock screen does not recover the key. A user who briefly disables their PIN loses their CoMapeo identity in every project they participate in.What we keep
The wrapper key remains:
The only attack surface gained: code execution as our app while the device sits in the post-boot, pre-first-unlock state could decrypt the rootkey envelope. There is no practical path for that on current Android even without the gate, and it's a vanishing concern relative to the identity-loss failure modes above.
Prior art
expo-secure-store— the de-facto standard secret store on Expo/RN Android — makes the same trade and omits this flag. Its default-case wrapper key uses onlysetUserAuthenticationRequired(false); no lock-screen-tied attributes.Test plan
RootKeyStoreTestinstrumented tests still pass on a device with a configured screen lock (no behavior change for that path).STARTED, wrapper key generates, rootkey persists, second launch returns the same bytes.