Skip to content

Commit 2f75415

Browse files
committed
Refactor Android biometric storage and update types
Major refactor of Android secure storage module: removes Nitro module view components, updates biometric authentication flow, and improves documentation for all core classes. Updates type definitions for AccessControl and SecurityLevel, revises tests to match new types, and adds src/types.ts. Cleans up README and .gitignore, and updates example usage and configuration. This prepares the codebase for new architecture and clarifies API usage for developers.
1 parent 1f0fb62 commit 2f75415

24 files changed

Lines changed: 2061 additions & 1371 deletions

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ lib/
8282
ios/generated
8383
android/generated
8484

85-
# React Native Nitro Modules
86-
nitrogen/
85+
8786

8887
# Coverage
8988
coverage/

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@ npm install react-native-sensitive-info@5.6.0
4242

4343
# Old Architecture (RN <0.73)
4444
npm install react-native-sensitive-info@5.5.x
45-
46-
# Bleeding edge (Nitro Modules, v6)
47-
npm install github:mCodex/react-native-sensitive-info#master
4845
```
4946

5047
---

__tests__/comprehensive.test.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ describe('SensitiveInfo API - Complete Coverage', () => {
4242
describe('Error Types', () => {
4343
it('should define all error codes', () => {
4444
const codes: ErrorCode[] = [
45+
ErrorCode.NOT_FOUND,
4546
ErrorCode.AUTH_FAILED,
4647
ErrorCode.AUTH_CANCELED,
47-
ErrorCode.AUTH_TIMEOUT,
4848
ErrorCode.BIOMETRY_LOCKOUT,
4949
ErrorCode.KEY_INVALIDATED,
5050
ErrorCode.DECRYPTION_FAILED,
@@ -53,7 +53,7 @@ describe('SensitiveInfo API - Complete Coverage', () => {
5353
ErrorCode.MIGRATION_FAILED,
5454
];
5555

56-
expect(codes).toHaveLength(10);
56+
expect(codes).toHaveLength(9);
5757
codes.forEach((code) => {
5858
expect(code).toMatch(/^E_/);
5959
});
@@ -81,13 +81,14 @@ describe('SensitiveInfo API - Complete Coverage', () => {
8181
describe('Type Definitions', () => {
8282
it('should support all AccessControl types', () => {
8383
const controls: AccessControl[] = [
84-
'devicePasscode',
85-
'biometryOrDevicePasscode',
86-
'biometryAndDevicePasscode',
84+
'secureEnclaveBiometry',
8785
'biometryCurrentSet',
86+
'biometryAny',
87+
'devicePasscode',
88+
'none',
8889
];
8990

90-
expect(controls).toHaveLength(4);
91+
expect(controls).toHaveLength(5);
9192
controls.forEach((control) => {
9293
expect(typeof control).toBe('string');
9394
});
@@ -97,13 +98,12 @@ describe('SensitiveInfo API - Complete Coverage', () => {
9798
const levels: SecurityLevel[] = [
9899
'secureEnclave',
99100
'strongBox',
100-
'hardwareBacked',
101-
'biometricProtected',
102-
'passcodeProtected',
101+
'biometry',
102+
'deviceCredential',
103103
'software',
104104
];
105105

106-
expect(levels).toHaveLength(6);
106+
expect(levels).toHaveLength(5);
107107
levels.forEach((level) => {
108108
expect(typeof level).toBe('string');
109109
});
@@ -250,8 +250,8 @@ describe('SensitiveInfo API - Complete Coverage', () => {
250250
});
251251

252252
it('should define default access control level', () => {
253-
const defaultControl = 'biometryOrDevicePasscode' as AccessControl;
254-
expect(defaultControl).toBe('biometryOrDevicePasscode');
253+
const defaultControl = 'secureEnclaveBiometry' as AccessControl;
254+
expect(defaultControl).toBe('secureEnclaveBiometry');
255255
});
256256

257257
it('should define keychain service constants', () => {
@@ -366,7 +366,7 @@ describe('SensitiveInfo API - Complete Coverage', () => {
366366
metadata: {
367367
timestamp: Date.now(),
368368
securityLevel: 'secureEnclave' as SecurityLevel,
369-
accessControl: 'biometryOrDevicePasscode' as AccessControl,
369+
accessControl: 'secureEnclaveBiometry' as AccessControl,
370370
migratedFromV5: false,
371371
},
372372
};
@@ -420,15 +420,15 @@ describe('SensitiveInfo API - Complete Coverage', () => {
420420
const code = async () => {
421421
// const secret = await SensitiveInfo.getItem('password', {
422422
// keychainService: 'myapp',
423-
// accessControl: 'biometryOrDevicePasscode',
423+
// accessControl: 'secureEnclaveBiometry',
424424
// prompt: {
425425
// title: 'Unlock Your Account',
426426
// subtitle: 'Authenticate with Face ID or Touch ID'
427427
// }
428428
// });
429429
return {
430430
keychainService: 'myapp',
431-
accessControl: 'biometryOrDevicePasscode' as const,
431+
accessControl: 'secureEnclaveBiometry' as const,
432432
prompt: {
433433
title: 'Unlock Your Account',
434434
subtitle: 'Authenticate with Face ID or Touch ID',
@@ -438,7 +438,7 @@ describe('SensitiveInfo API - Complete Coverage', () => {
438438

439439
const result = await code();
440440
expect(result.keychainService).toBe('myapp');
441-
expect(result.accessControl).toBe('biometryOrDevicePasscode');
441+
expect(result.accessControl).toBe('secureEnclaveBiometry');
442442
});
443443

444444
it('Example 3: Detect capabilities', async () => {

__tests__/index.test.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* on real devices/simulators.
77
*/
88

9+
import type { AccessControl, SecurityLevel } from '../src/index';
910
import {
1011
SensitiveInfo,
1112
SensitiveInfoError,
@@ -56,7 +57,7 @@ describe('SensitiveInfo API', () => {
5657
it('should accept valid setItem options', () => {
5758
const options = {
5859
keychainService: 'com.example.app',
59-
accessControl: 'biometryOrDevicePasscode' as const,
60+
accessControl: 'secureEnclaveBiometry' as const,
6061
};
6162
expect(options.keychainService).toBe('com.example.app');
6263
});
@@ -73,28 +74,28 @@ describe('SensitiveInfo API', () => {
7374
});
7475

7576
it('should support all access control types', () => {
76-
const controls = [
77-
'devicePasscode' as const,
78-
'biometryOrDevicePasscode' as const,
79-
'biometryAndDevicePasscode' as const,
80-
'biometryCurrentSet' as const,
77+
const controls: AccessControl[] = [
78+
'secureEnclaveBiometry',
79+
'biometryCurrentSet',
80+
'biometryAny',
81+
'devicePasscode',
82+
'none',
8183
];
8284

83-
expect(controls).toHaveLength(4);
85+
expect(controls).toHaveLength(5);
8486
expect(controls.every((c) => typeof c === 'string')).toBe(true);
8587
});
8688

8789
it('should support all security levels', () => {
88-
const levels = [
90+
const levels: SecurityLevel[] = [
8991
'secureEnclave',
9092
'strongBox',
91-
'hardwareBacked',
92-
'biometricProtected',
93-
'passcodeProtected',
93+
'biometry',
94+
'deviceCredential',
9495
'software',
9596
];
9697

97-
expect(levels).toHaveLength(6);
98+
expect(levels).toHaveLength(5);
9899
});
99100
});
100101

@@ -181,7 +182,7 @@ describe('SensitiveInfo API', () => {
181182
const expectedCode = async () => {
182183
const options = {
183184
keychainService: 'com.myapp',
184-
accessControl: 'biometryOrDevicePasscode' as const,
185+
accessControl: 'secureEnclaveBiometry' as const,
185186
prompt: {
186187
title: 'Authenticate',
187188
subtitle: 'Verify your identity',
@@ -192,7 +193,7 @@ describe('SensitiveInfo API', () => {
192193
};
193194

194195
const result = await expectedCode();
195-
expect(result.accessControl).toBe('biometryOrDevicePasscode');
196+
expect(result.accessControl).toBe('secureEnclaveBiometry');
196197
expect(result.prompt.title).toBe('Authenticate');
197198
});
198199

android/build.gradle

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,51 @@ repositories {
7272
def kotlin_version = getExtOrDefault("kotlinVersion")
7373

7474
dependencies {
75+
// React Native - Core library for bridging JavaScript and Native code
76+
// Version: From parent gradle configuration
77+
// Purpose: React Native bridge, component registry, etc.
7578
implementation "com.facebook.react:react-android"
79+
80+
// Kotlin Standard Library - Runtime for Kotlin code
81+
// Version: Configured in project gradle.properties
82+
// Purpose: Core Kotlin stdlib functions, collections, etc.
7683
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
7784

78-
// Biometric authentication (Face ID, Fingerprint, etc)
85+
// AndroidX Biometric - Modern biometric authentication API
86+
// Version: 1.1.0 (stable)
87+
// Purpose: Face ID, Fingerprint, Iris recognition
88+
// Minimum API: 14 (works on API 28+)
89+
// Docs: https://developer.android.com/reference/androidx/biometric/BiometricPrompt
90+
// Security: Handles authentication state, error codes, callbacks
91+
// Performance: Async-first design, non-blocking UI
92+
// Features:
93+
// - BiometricPrompt: System-level biometric UI
94+
// - BiometricManager: Check device capabilities
95+
// - Device credential fallback (PIN/Pattern/Password)
96+
// - Biometric template invalidation tracking
97+
// - Crypto object wrapping for cipher authentication
7998
implementation "androidx.biometric:biometric:1.1.0"
8099

81-
// Fragment support (required by BiometricPrompt)
100+
// AndroidX Fragment - Lifecycle-aware fragments for BiometricPrompt
101+
// Version: 1.6.2 (stable)
102+
// Purpose: FragmentActivity support for BiometricPrompt UI rendering
103+
// Why needed: BiometricPrompt requires FragmentActivity context
104+
// Performance: Lightweight, no overhead if not using fragments directly
105+
// Security: Integrates with fragment lifecycle for proper cleanup
82106
implementation "androidx.fragment:fragment-ktx:1.6.2"
83107

84-
// Coroutines support for suspend functions
108+
// Kotlin Coroutines - Async/suspend functions for non-blocking operations
109+
// Core library (1.7.3):
110+
// - Purpose: Suspend functions, async context switching
111+
// - Security: Thread-safe continuation handling
112+
// - Performance: Efficient, minimal allocations vs callbacks
113+
// Android library (1.7.3):
114+
// - Purpose: Dispatcher.Main for UI operations
115+
// - Performance: Integrates with main thread event loop
116+
// - Usage in this library: All setItem/getItem are suspend functions
117+
// Example:
118+
// suspend fun setItem(...): StorageResult
119+
// // Called from coroutineScope.launch { setItem(...) }
85120
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
86121
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3"
87122
}

0 commit comments

Comments
 (0)