Skip to content

feat(security): re-sync biometric enabled state from SecureStore on foreground#725

Merged
RUKAYAT-CODER merged 1 commit into
rinafcode:mainfrom
No-bodyq:security/biometric-sync
Jun 28, 2026
Merged

feat(security): re-sync biometric enabled state from SecureStore on foreground#725
RUKAYAT-CODER merged 1 commit into
rinafcode:mainfrom
No-bodyq:security/biometric-sync

Conversation

@No-bodyq

Copy link
Copy Markdown
Contributor

Summary

  • Added biometricEnabled and setBiometricEnabled to useDeviceStore as a runtime cache (no persistence — SecureStore remains the sole source of truth)
  • useBiometricAuth now calls isBiometricEnabled() from secureStorage.ts on mount and on every background → active foreground transition; if SecureStore no longer holds the entry, the cached value is reset to false regardless of what Zustand held
  • isLoading: true is returned until the first sync completes so biometric UI cannot render against stale state
  • isEnabled requires both !isDeviceCompromised and biometricEnabled — either gate being false blocks the prompt
  • Unit tests cover: mount sync, isLoading lifecycle, foreground re-sync, divergence reset (SecureStore cleared while Zustand cached true), compromised-device override, no spurious sync on background-only transition

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Chore / Refactor (no functional changes)

Testing Done

  • Unit Tests
  • Integration Tests
  • Manual Verification (e.g., iOS/Android UI checks)

Security Considerations

  • Does this store user data securely (e.g., avoiding plain AsyncStorage for sensitive data)? — Biometric preference stays in SecureStore (Keychain/Keystore); Zustand holds only a runtime copy that is always re-validated on foreground
  • Is token handling secure (no token exposure in logs or UI)? — N/A to this change
  • Are all user inputs validated? — N/A to this change
  • Is deep link handling safe from malicious payloads? — N/A to this change

Performance Considerations

  • Are React hooks (useCallback, useMemo) used appropriately to prevent unnecessary renders? — syncWithSecureStore is wrapped in useCallback; AppState subscription is cleaned up on unmount
  • Is FlatList optimized (e.g., using getItemLayout, keyExtractor)? — N/A to this change
  • Are asynchronous patterns handled correctly (e.g., useEffect cleanup to avoid memory leaks)? — AppState.addEventListener subscription is removed in the useEffect cleanup; isSyncing is always cleared in a finally block
  • Have bundle size impacts been considered? — No new dependencies; AppState is already part of React Native core

Checklist

  • I have read the CONTRIBUTING guide.
  • My code follows the style guidelines of this project.
  • I have updated the documentation accordingly. — N/A; no public API surface changed
  • Are there architectural changes? If so, is there an Architectural Decision Record (ADR)? — No architectural changes; SecureStore remains the source of truth, Zustand is a runtime cache only

Closes #590

…oreground

Stale Zustand state could show biometricEnabled: true after an OS update,
reinstall, or external process cleared the SecureStore entry while the app
was backgrounded. useBiometricAuth now re-reads isBiometricEnabled() on
every active foreground transition and resets to false on divergence.
isLoading blocks biometric UI until the initial sync completes.
@drips-wave

drips-wave Bot commented Jun 28, 2026

Copy link
Copy Markdown

@No-bodyq Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@RUKAYAT-CODER

Copy link
Copy Markdown
Contributor

Thank you for contributing to the project.

@RUKAYAT-CODER RUKAYAT-CODER merged commit bb3d4f1 into rinafcode:main Jun 28, 2026
2 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Security] Biometric auth disabled state can diverge from secure storage — auth bypass possible

2 participants