Biometric auth by Claude#718
Open
softartdev wants to merge 11 commits intodevfrom
Open
Conversation
Adds biometric sign-in (Touch ID / Face ID on iOS, BiometricPrompt on Android) for unlocking the SQLCipher-encrypted database. Users enable it from Settings; on next launch the SignIn screen offers a "Use biometric" button that retrieves the password from OS-secured storage after a successful biometric prompt. Architecture: - Common: expect class BiometricInteractor with BiometricResult / DecryptedPasswordResult sealed types (mirrors LocaleInteractor's expect/actual pattern in core/presentation). - Android: BiometricPrompt + Android Keystore. Password is encrypted with an AES-GCM key marked setUserAuthenticationRequired(true) and setInvalidatedByBiometricEnrollment(true), then stored in plain SharedPreferences. Cipher is unlocked via BiometricPrompt.CryptoObject so decryption literally requires a fresh biometric scan. MainActivity attaches itself to a small BiometricActivityHolder for prompt access. - iOS: LAContext + Keychain Services with kSecAccessControlBiometryCurrentSet on a generic-password Keychain item. Item invalidates on biometric re-enrollment. - JVM/Web get no-op stubs so the multiplatform build stays green. Settings flow: a ChangeBiometric(true) action navigates to the new BiometricEnrollDialog where the user re-types the password, then encryptAndStorePassword runs the biometric prompt. Disabling clears the stored ciphertext. Whenever the DB password changes via Change/Enter/ Confirm ViewModels, any stored biometric password is cleared and a snackbar tells the user to re-enable in Settings. Tests: SignInViewModelTest gets two new biometric paths; existing ViewModel tests are updated to pass the new mock BiometricInteractor. https://claude.ai/code/session_01AHoV8HEQJ86WRccDv4i6hK
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…ntations - Refactor `BiometricInteractor` on iOS to improve type safety with explicit `CFTypeRef` and `OSStatus` handling, and simplify `memScoped` logic. - Update `BiometricInteractor` on Android to utilize `SharedPreferences.edit` KTX extension, add detailed logging for Keystore failures, and refactor cipher initialization. - Optimize `BiometricEnrollViewModel` state updates to use single `update` blocks and named arguments for better readability. - Simplify `SignInScreen` and `BiometricEnrollDialog` by resolving string resources directly within the UI components and streamlining action passing. - Switch iOS project configuration from manual to automatic code signing and remove platform-specific development team overrides. - Refactor Android Koin dependency injection to use `singleOf` for `BiometricInteractor`. - Add documentation/TODOs regarding the removal of Compose-specific `AutofillManager` dependencies from presentation ViewModels. - Clean up unused methods, such as `BiometricEnrollResult.hideError()`, and improve formatting across the presentation and UI modules. - Update iOS user interface state and workspace configuration.
- Refactor `BiometricInteractor` on Android to use `Application.ActivityLifecycleCallbacks` for automatic activity tracking, eliminating the manual `BiometricActivityHolder`. - Consolidate `SignInViewModel` UI state into a single `SignInResult` data class, replacing separate flows for result and visibility with atomic state updates. - Update `SignInScreen` and related tests to utilize the unified state model. - Downgrade `androidx.biometric` to `1.1.0` for stability and set `minSdk` to 23 in `CONTRIBUTING.md`. - Add `USE_FINGERPRINT` permission to `AndroidManifest.xml` and remove manual `configChanges` handling for `MainActivity`. - Expand `CONTRIBUTING.md` with detailed coding standards for named arguments, state management, and Composable patterns. - Switch iOS project configuration to use automatic code signing. - Ensure `BiometricInteractor` operations are explicitly dispatched to the main thread when interacting with UI components.
- Refactor `SignInResult` from a data class with an enum-based state to a sealed interface hierarchy for improved type safety and state handling. - Update `SignInViewModel` and `SignInScreen` to utilize the new sealed structure and implement a `setState` helper for atomic updates. - Extract `CurrentActivityProvider` into a standalone internal class, utilizing `WeakReference` to prevent potential memory leaks of the host `FragmentActivity`. - Enhance error handling in `BiometricEnrollViewModel` to extract and display specific error messages from `BiometricResult`. - Remove the deprecated `USE_FINGERPRINT` permission from the Android manifest. - Introduce a `dispose()` method in `BiometricInteractor` for explicit lifecycle management and cleaner test execution. - Update `SignInViewModelTest` to align assertions with the new sealed state model.
- Refactor `SignInResult` from a sealed interface to a data class containing a nested `State` interface. This separates the primary UI state (Form, Progress, Error) from the `biometricVisible` flag. - Update `SignInViewModel` to use `MutableStateFlow.update()` for state transitions, ensuring atomic updates to the sign-in state and biometric visibility. - Adjust `SignInScreen` and `SignInViewModelTest` to access the nested state property within the new `SignInResult` model. - Enhance `CurrentActivityProvider` to capture `FragmentActivity` references during `onActivityCreated` and `onActivityStarted`, in addition to `onActivityResumed`. - Modify `CurrentActivityProvider` to only clear the activity reference during `onActivityDestroyed`, ensuring a stable host for components like `BiometricPrompt` during transient lifecycle changes. - Remove the internal helper `setState` function in `SignInViewModel` in favor of standard `StateFlow` update patterns.
Move BiometricInteractor (expect/actuals), BiometricResult, DecryptedPasswordResult, and CurrentActivityProvider to feature:biometric:domain; move BiometricEnrollViewModel, BiometricEnrollResult, and BiometricEnrollAction to feature:biometric:presentation. Update core:presentation and core:ui build files and module READMEs accordingly. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…spend - Replace `SharedPreferences` with `androidx.datastore.preferences` in `BiometricInteractor.android.kt` for more robust data handling. - Update `hasStoredPassword()` and `clearStoredPassword()` to `suspend` functions across common and platform-specific implementations. - Add `androidx.datastore` dependency to `libs.versions.toml` and include it in the `biometric:domain` module. - Update `SettingsViewModelTest`, `ChangeViewModelTest`, `ConfirmViewModelTest`, and `EnterViewModelTest` to handle the new `suspend` method signatures. - Enhance error logging in `SignInViewModel` to capture specific `BiometricResult.Error` messages. - Update `SignInScreen` Compose preview to include the `biometricVisible` parameter.
- Replace `CurrentActivityProvider` with a Compose-friendly `BiometricPlatformWrapper` pattern to provide the Android host `FragmentActivity`. - Introduce `rememberBiometricPlatformWrapper()` expect/actual function to capture the platform host context from the UI layer. - Refactor `BiometricInteractor` to accept `BiometricPlatformWrapper` in encryption and decryption methods. - Introduce `BiometricCredentialsStore` on Android to encapsulate DataStore Preferences logic for storing encrypted credentials. - Refine `DecryptedPasswordResult` domain model to explicitly distinguish between `Cancelled`, `Unavailable`, and `Failure` states. - Update `SignInViewModel` and `BiometricEnrollViewModel` to handle the new platform wrapper and result states. - Refactor `SignInViewModel` to utilize `SnackbarInteractor` for displaying biometric authentication errors. - Update project documentation to reflect the new two-layer protection architecture (Android Keystore + DataStore) and the activity provider pattern. - Update unit tests for `SignInViewModel` to reflect dependency and action changes.
…ion handling - Update `SignInAction.OnBiometricClick` and `BiometricEnrollAction.OnEnrollClick` to require a non-nullable `BiometricPlatformWrapper`. - Remove redundant null checks and logging for `BiometricPlatformWrapper` in `SignInViewModel` and `BiometricEnrollViewModel`. - Refactor `SignInScreen` and `BiometricEnrollDialog` to instantiate the biometric wrapper locally and pass it directly through the UI action flow. - Simplify the Android implementation of `rememberBiometricPlatformWrapper` using a direct cast to `FragmentActivity`. - Clean up `onAction` lambda references in the UI layer by using function references where possible.
- Update `rememberBiometricPlatformWrapper` to use the `remember` composable across all platforms (Android, JVM, iOS, and WasmJs). - Prevent unnecessary re-instantiation of `BiometricPlatformWrapper` during recompositions. - Key the `remember` block on Android using the current `FragmentActivity` to ensure the wrapper stays in sync with the host activity.
- Add biometric authentication status to the platform feature compatibility table.
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
This Pull Request (PR) reorganizes and renames several modules and files in the project, introduces biometric authentication capabilities, adjusts resources for internationalization, and updates dependencies.
Main Changes
Module Renaming and Reorganization:
ui:shared renamed to core:ui.
ui:test renamed to core:test:ui.
ui:test-jvm renamed to core:test:jvm.
core:test renamed to core:test:common.
Biometric Authentication Implementation:
Added multiplatform support for biometric encryption and decryption.
Created platform-specific implementations for Android and iOS in the BiometricInteractor.
Integrated biometric sign-in into the app, including enabling/disabling biometric options in Settings and sign-in screens.
Code Refactoring:
Updated resources, test tags, and paths to match the renamed modules.
Adjusted Koin modules in uiModules to support the new biometric feature.
Resource Updates:
New strings for biometric-related features in English and Russian.
Adjustments to existing localized strings for usability.
Testing Enhancements:
Added test cases for biometric sign-in scenarios.
Updated multiplatform test structure to align with the renamed test modules.
Dependency Updates:
Minor version upgrades for several dependencies, including Kotlin and Compose-related libraries.
Introduced androidx.biometric to support biometric authentication.