react-native-nitro-storage 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +22 -9
  3. package/android/src/main/java/com/nitrostorage/AndroidStorageAdapter.kt +225 -76
  4. package/app.plugin.js +2 -0
  5. package/cpp/bindings/HybridStorage.cpp +4 -12
  6. package/docs/secure-storage.md +4 -0
  7. package/lib/commonjs/index.js.map +1 -1
  8. package/lib/commonjs/index.web.js.map +1 -1
  9. package/lib/commonjs/indexeddb-backend.js.map +1 -1
  10. package/lib/commonjs/internal.js.map +1 -1
  11. package/lib/commonjs/storage-core.js.map +1 -1
  12. package/lib/commonjs/storage-events.js.map +1 -1
  13. package/lib/module/index.js.map +1 -1
  14. package/lib/module/index.web.js.map +1 -1
  15. package/lib/module/indexeddb-backend.js.map +1 -1
  16. package/lib/module/internal.js.map +1 -1
  17. package/lib/module/storage-core.js.map +1 -1
  18. package/lib/module/storage-events.js.map +1 -1
  19. package/lib/typescript/index.d.ts +6 -1
  20. package/lib/typescript/index.d.ts.map +1 -1
  21. package/lib/typescript/index.web.d.ts +6 -1
  22. package/lib/typescript/index.web.d.ts.map +1 -1
  23. package/lib/typescript/indexeddb-backend.d.ts.map +1 -1
  24. package/lib/typescript/storage-core.d.ts +11 -1
  25. package/lib/typescript/storage-core.d.ts.map +1 -1
  26. package/lib/typescript/storage-events.d.ts.map +1 -1
  27. package/lib/typescript/testing.d.ts +12 -2
  28. package/lib/typescript/testing.d.ts.map +1 -1
  29. package/package.json +5 -6
  30. package/src/index.ts +1 -2
  31. package/src/index.web.ts +1 -2
  32. package/src/indexeddb-backend.ts +1 -2
  33. package/src/internal.ts +1 -1
  34. package/src/storage-core.ts +19 -2
  35. package/src/storage-events.ts +1 -2
package/CHANGELOG.md CHANGED
@@ -4,6 +4,17 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  The format follows Keep a Changelog and the project adheres to SemVer.
6
6
 
7
+ ## 0.7.0 - 2026-07-30
8
+
9
+ ### Changes
10
+
11
+ - **Breaking change:** Android secure key discovery, existence checks, and cleanup now surface locked, unavailable, or invalidated biometric-store errors instead of treating inaccessible protected values as absent. Catch storage errors around these operations and use `isKeychainLockedError()` when retrying after device authentication is appropriate.
12
+ - Upgrade the validated package baseline to Expo SDK 57, React Native 0.86.2, and Nitro Modules/Nitrogen 0.36.4.
13
+ - Preserve each item/value relationship in heterogeneous `setBatch()` calls so TypeScript rejects values assigned to the wrong storage item.
14
+ - Serialize native key-index hydration with concurrent mutations so `has`, `size`, and key queries cannot remain stale after a racing write.
15
+ - Enforce Android biometric policy levels with distinct Keystore keys, propagate locked or invalidated biometric failures, and keep secure preference files excluded from backup.
16
+ - Preflight biometric store access before aggregate secure mutations and surface native commit or corruption-recovery failures.
17
+
7
18
  ## 0.6.0 - 2026-06-15
8
19
 
9
20
  ### Added
package/README.md CHANGED
@@ -5,8 +5,8 @@
5
5
  [![CI](https://github.com/JoaoPauloCMarra/react-native-nitro-storage/actions/workflows/ci.yml/badge.svg)](https://github.com/JoaoPauloCMarra/react-native-nitro-storage/actions/workflows/ci.yml)
6
6
  [![license](https://img.shields.io/npm/l/react-native-nitro-storage?color=007ec6)](https://github.com/JoaoPauloCMarra/react-native-nitro-storage/blob/main/LICENSE)
7
7
  [![React Native](https://img.shields.io/badge/react--native-%3E%3D0.75-61dafb)](https://reactnative.dev/)
8
- [![Expo](https://img.shields.io/badge/expo-SDK%2056-000020)](https://docs.expo.dev/)
9
- [![Nitro Modules](https://img.shields.io/badge/nitro--modules-%3E%3D0.35.7-black)](https://nitro.margelo.com/)
8
+ [![Expo](https://img.shields.io/badge/expo-SDK%2057-000020)](https://docs.expo.dev/versions/latest/)
9
+ [![Nitro Modules](https://img.shields.io/badge/nitro--modules-0.36.x-black)](https://nitro.margelo.com/)
10
10
  [![TypeScript](https://img.shields.io/badge/typescript-6.0-3178c6)](https://www.typescriptlang.org/)
11
11
 
12
12
  Synchronous Memory, Disk, and Secure storage for React Native, Expo development
@@ -53,13 +53,16 @@ bun add react-native-nitro-storage react-native-nitro-modules
53
53
 
54
54
  Peer dependencies:
55
55
 
56
- | Package | Version |
57
- | ---------------------------- | ---------- |
58
- | `react` | `>=18.2.0` |
59
- | `react-native` | `>=0.75.0` |
60
- | `react-native-nitro-modules` | `>=0.35.7` |
56
+ | Package | Version |
57
+ | ---------------------------- | ------------------ |
58
+ | `react` | `>=18.2.0` |
59
+ | `react-native` | `>=0.75.0` |
60
+ | `react-native-nitro-modules` | `>=0.36.4 <0.37.0` |
61
61
 
62
- Nitro peer requirement: `react-native-nitro-modules >=0.35.7`.
62
+ Nitro peer requirement: `react-native-nitro-modules >=0.36.4 <0.37.0`.
63
+
64
+ Validated example baseline: Expo SDK 57, React Native 0.86.2, React 19.2.3,
65
+ and Nitro Modules 0.36.4.
63
66
 
64
67
  For Expo development builds:
65
68
 
@@ -371,10 +374,20 @@ exporting secure values unless you are intentionally doing a short-lived
371
374
  in-memory migration. `storage.export(StorageScope.Secure)` throws unless you
372
375
  explicitly opt into `{ includeSecureValues: true }`.
373
376
 
377
+ On Android 11 and newer, `BiometricLevel.BiometryOnly` and
378
+ `BiometricLevel.BiometryOrPasscode` use separate Keystore policies. Android 10
379
+ and older support `BiometryOrPasscode`; `BiometryOnly` throws
380
+ `biometric_unavailable` because those releases cannot safely enforce the
381
+ biometric-only distinction. Secure existence, discovery, and cleanup operations
382
+ can also throw when a protected store is locked or its key is invalidated. Catch
383
+ those failures and use `isKeychainLockedError()` when authentication-aware retry
384
+ behavior is appropriate.
385
+
374
386
  ## Batch Operations
375
387
 
376
388
  `getBatch()` preserves tuple value types, so IDEs infer each result from the
377
- matching item.
389
+ matching item. `setBatch()` validates every item/value pair independently,
390
+ including heterogeneous batches.
378
391
 
379
392
  ```ts
380
393
  import { getBatch, removeBatch, setBatch } from "react-native-nitro-storage";
@@ -3,7 +3,10 @@
3
3
  package com.nitrostorage
4
4
 
5
5
  import android.content.Context
6
+ import android.os.Build
7
+ import android.security.keystore.KeyGenParameterSpec
6
8
  import android.security.keystore.KeyPermanentlyInvalidatedException
9
+ import android.security.keystore.KeyProperties
7
10
  import android.security.keystore.UserNotAuthenticatedException
8
11
  import android.content.SharedPreferences
9
12
  import androidx.security.crypto.EncryptedSharedPreferences
@@ -60,33 +63,113 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
60
63
  throw RuntimeException("NitroStorage: Cannot create encryption key. Device may not support AES256-GCM.", e)
61
64
  }
62
65
 
63
- private val encryptedPreferences: SharedPreferences = initializeEncryptedPreferences("NitroStorageSecure", masterKey)
66
+ private val encryptedPreferences: SharedPreferences = initializeEncryptedPreferences(
67
+ "NitroStorageSecure",
68
+ masterKey,
69
+ masterKeyAlias,
70
+ ::createDefaultMasterKey,
71
+ )
64
72
 
65
73
  private val biometricMasterKeyAlias = "${context.packageName}.nitro_storage.biometric_key"
74
+ private val biometricOrPasscodeMasterKeyAlias =
75
+ "${context.packageName}.nitro_storage.biometric_or_passcode_key"
76
+ private val biometricOnlyMasterKeyAlias =
77
+ "${context.packageName}.nitro_storage.biometric_only_key"
78
+
79
+ private val legacyBiometricPreferences: SharedPreferences by lazy {
80
+ createBiometricPreferences(
81
+ "NitroStorageBiometric",
82
+ biometricMasterKeyAlias,
83
+ 1,
84
+ )
85
+ }
66
86
 
67
- private val biometricPreferences: SharedPreferences by lazy {
68
- try {
69
- val bioKey = MasterKey.Builder(context, biometricMasterKeyAlias)
70
- .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
71
- .setUserAuthenticationRequired(true, 30)
87
+ private val biometricOrPasscodePreferences: SharedPreferences by lazy {
88
+ createBiometricPreferences(
89
+ "NitroStorageBiometricOrPasscode",
90
+ biometricOrPasscodeMasterKeyAlias,
91
+ 1,
92
+ )
93
+ }
94
+
95
+ private val biometricOnlyPreferences: SharedPreferences by lazy {
96
+ createBiometricPreferences(
97
+ "NitroStorageBiometricOnly",
98
+ biometricOnlyMasterKeyAlias,
99
+ 2,
100
+ )
101
+ }
102
+
103
+ @Volatile
104
+ private var secureWritesAsync = false
105
+
106
+ @Volatile
107
+ private var secureKeysCache: Array<String>? = null
108
+
109
+ private fun createDefaultMasterKey(): MasterKey {
110
+ return MasterKey.Builder(context, masterKeyAlias)
111
+ .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
112
+ .build()
113
+ }
114
+
115
+ private fun createBiometricMasterKey(alias: String, level: Int): MasterKey {
116
+ if (level == 2 && Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
117
+ throw RuntimeException(
118
+ "[nitro-error:biometric_unavailable] NitroStorage: BiometryOnly requires Android 11 or newer.",
119
+ )
120
+ }
121
+
122
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
123
+ val authenticationTypes = if (level == 1) {
124
+ KeyProperties.AUTH_BIOMETRIC_STRONG or KeyProperties.AUTH_DEVICE_CREDENTIAL
125
+ } else {
126
+ KeyProperties.AUTH_BIOMETRIC_STRONG
127
+ }
128
+ val keySpec = KeyGenParameterSpec.Builder(
129
+ alias,
130
+ KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT,
131
+ )
132
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
133
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
134
+ .setKeySize(256)
135
+ .setUserAuthenticationRequired(true)
136
+ .setUserAuthenticationParameters(30, authenticationTypes)
137
+ .setInvalidatedByBiometricEnrollment(level == 2)
138
+ .build()
139
+ return MasterKey.Builder(context, alias)
140
+ .setKeyGenParameterSpec(keySpec)
72
141
  .build()
73
- initializeEncryptedPreferences("NitroStorageBiometric", bioKey)
142
+ }
143
+
144
+ return MasterKey.Builder(context, alias)
145
+ .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
146
+ .setUserAuthenticationRequired(true, 30)
147
+ .build()
148
+ }
149
+
150
+ private fun createBiometricPreferences(
151
+ name: String,
152
+ alias: String,
153
+ level: Int,
154
+ ): SharedPreferences {
155
+ return try {
156
+ val keyFactory = { createBiometricMasterKey(alias, level) }
157
+ initializeEncryptedPreferences(name, keyFactory(), alias, keyFactory)
74
158
  } catch (e: Exception) {
75
159
  throw e.wrapStorageException(
76
160
  "NitroStorage: Biometric storage is not available on this device. " +
77
- "Ensure biometric hardware is present and credentials are enrolled.",
161
+ "Ensure supported authentication is enrolled.",
78
162
  defaultCode = "biometric_unavailable",
79
163
  )
80
164
  }
81
165
  }
82
166
 
83
- @Volatile
84
- private var secureWritesAsync = false
85
-
86
- @Volatile
87
- private var secureKeysCache: Array<String>? = null
88
-
89
- private fun initializeEncryptedPreferences(name: String, key: MasterKey): SharedPreferences {
167
+ private fun initializeEncryptedPreferences(
168
+ name: String,
169
+ key: MasterKey,
170
+ alias: String,
171
+ keyFactory: () -> MasterKey,
172
+ ): SharedPreferences {
90
173
  return try {
91
174
  EncryptedSharedPreferences.create(
92
175
  context, name, key,
@@ -96,16 +179,8 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
96
179
  } catch (e: Exception) {
97
180
  when {
98
181
  e.hasCause(AEADBadTagException::class.java) -> {
99
- clearCorruptedStorage(name, key)
100
- val freshAlias = if (name == "NitroStorageBiometric") biometricMasterKeyAlias else masterKeyAlias
101
- val freshKey = MasterKey.Builder(context, freshAlias)
102
- .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
103
- .apply {
104
- if (name == "NitroStorageBiometric") {
105
- setUserAuthenticationRequired(true, 30)
106
- }
107
- }
108
- .build()
182
+ clearCorruptedStorage(name, alias)
183
+ val freshKey = keyFactory()
109
184
  try {
110
185
  EncryptedSharedPreferences.create(
111
186
  context, name, freshKey,
@@ -120,7 +195,6 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
120
195
  }
121
196
  }
122
197
  else -> {
123
- // Don't wipe on non-corruption failures (e.g., locked keystore)
124
198
  throw e.wrapStorageException(
125
199
  "NitroStorage: Failed to initialize $name (${e::class.simpleName}). " +
126
200
  "This may be a temporary keystore issue. If it persists, clear app data.",
@@ -130,18 +204,58 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
130
204
  }
131
205
  }
132
206
 
133
- private fun clearCorruptedStorage(name: String, key: MasterKey) {
134
- try {
135
- context.deleteSharedPreferences(name)
136
- val keyStore = KeyStore.getInstance("AndroidKeyStore")
137
- keyStore.load(null)
138
- val alias = when {
139
- name == "NitroStorageSecure" -> masterKeyAlias
140
- name == "NitroStorageBiometric" -> biometricMasterKeyAlias
141
- else -> masterKeyAlias
142
- }
143
- keyStore.deleteEntry(alias)
144
- } catch (_: Exception) {
207
+ private fun clearCorruptedStorage(name: String, alias: String) {
208
+ context.deleteSharedPreferences(name)
209
+ val keyStore = KeyStore.getInstance("AndroidKeyStore")
210
+ keyStore.load(null)
211
+ keyStore.deleteEntry(alias)
212
+ }
213
+
214
+ private fun preferencesFileExists(name: String): Boolean {
215
+ return context.getSharedPreferences(name, Context.MODE_PRIVATE).all.isNotEmpty()
216
+ }
217
+
218
+ private fun existingBiometricPreferences(): List<SharedPreferences> {
219
+ val stores = mutableListOf<SharedPreferences>()
220
+ if (preferencesFileExists("NitroStorageBiometricOnly")) {
221
+ stores.add(biometricOnlyPreferences)
222
+ }
223
+ if (preferencesFileExists("NitroStorageBiometricOrPasscode")) {
224
+ stores.add(biometricOrPasscodePreferences)
225
+ }
226
+ if (preferencesFileExists("NitroStorageBiometric")) {
227
+ stores.add(legacyBiometricPreferences)
228
+ }
229
+ for (preferences in stores) {
230
+ preferences.all
231
+ }
232
+ return stores
233
+ }
234
+
235
+ private fun biometricPreferencesForLevel(level: Int): SharedPreferences {
236
+ return when (level) {
237
+ 1 -> biometricOrPasscodePreferences
238
+ 2 -> biometricOnlyPreferences
239
+ else -> throw IllegalArgumentException(
240
+ "NitroStorage: Invalid biometric level. Expected 0, 1, or 2.",
241
+ )
242
+ }
243
+ }
244
+
245
+ private fun removeBiometricKey(
246
+ key: String,
247
+ preferencesList: List<SharedPreferences> = existingBiometricPreferences(),
248
+ ) {
249
+ for (preferences in preferencesList) {
250
+ applySecureEditor(preferences.edit().remove(key))
251
+ }
252
+ }
253
+
254
+ private fun clearBiometricStores(
255
+ preferencesList: List<SharedPreferences> = existingBiometricPreferences(),
256
+ ) {
257
+ for (preferences in preferencesList) {
258
+ applySecureEditor(preferences.edit().clear())
145
259
  }
146
260
  }
147
261
 
@@ -162,8 +276,8 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
162
276
  try {
163
277
  if (secureWritesAsync) {
164
278
  editor.apply()
165
- } else {
166
- editor.commit()
279
+ } else if (!editor.commit()) {
280
+ throw IllegalStateException("SharedPreferences commit returned false")
167
281
  }
168
282
  } catch (e: Exception) {
169
283
  throw e.wrapStorageException(
@@ -192,9 +306,8 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
192
306
  val INTERNAL_PREFIX = "__androidx_security_crypto_encrypted_prefs_"
193
307
  val keys = linkedSetOf<String>()
194
308
  keys.addAll(encryptedPreferences.all.keys.filter { !it.startsWith(INTERNAL_PREFIX) })
195
- try {
196
- keys.addAll(biometricPreferences.all.keys.filter { !it.startsWith(INTERNAL_PREFIX) })
197
- } catch (_: Exception) {
309
+ for (preferences in existingBiometricPreferences()) {
310
+ keys.addAll(preferences.all.keys.filter { !it.startsWith(INTERNAL_PREFIX) })
198
311
  }
199
312
  val built = keys.toTypedArray()
200
313
  secureKeysCache = built
@@ -361,11 +474,9 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
361
474
  fun deleteSecure(key: String) {
362
475
  val inst = getInstanceOrThrow()
363
476
  synchronized(inst) {
477
+ val biometricPreferences = inst.existingBiometricPreferences()
364
478
  inst.applySecureEditor(inst.encryptedPreferences.edit().remove(key))
365
- try {
366
- inst.applySecureEditor(inst.biometricPreferences.edit().remove(key))
367
- } catch (_: Exception) {
368
- }
479
+ inst.removeBiometricKey(key, biometricPreferences)
369
480
  inst.invalidateSecureKeysCache()
370
481
  }
371
482
  }
@@ -374,18 +485,18 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
374
485
  fun deleteSecureBatch(keys: Array<String>) {
375
486
  val inst = getInstanceOrThrow()
376
487
  synchronized(inst) {
488
+ val biometricPreferences = inst.existingBiometricPreferences()
377
489
  val editor = inst.encryptedPreferences.edit()
378
490
  for (key in keys) {
379
491
  editor.remove(key)
380
492
  }
381
493
  inst.applySecureEditor(editor)
382
- try {
383
- val biometricEditor = inst.biometricPreferences.edit()
494
+ for (preferences in biometricPreferences) {
495
+ val biometricEditor = preferences.edit()
384
496
  for (key in keys) {
385
497
  biometricEditor.remove(key)
386
498
  }
387
499
  inst.applySecureEditor(biometricEditor)
388
- } catch (_: Exception) {
389
500
  }
390
501
  inst.invalidateSecureKeysCache()
391
502
  }
@@ -394,13 +505,10 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
394
505
  @JvmStatic
395
506
  fun hasSecure(key: String): Boolean {
396
507
  val inst = getInstanceOrThrow()
397
- val hasInEncrypted = inst.encryptedPreferences.contains(key)
398
- val hasInBiometric = try {
399
- inst.biometricPreferences.contains(key)
400
- } catch (_: Exception) {
401
- false
508
+ if (inst.encryptedPreferences.contains(key)) {
509
+ return true
402
510
  }
403
- return hasInEncrypted || hasInBiometric
511
+ return inst.existingBiometricPreferences().any { it.contains(key) }
404
512
  }
405
513
 
406
514
  @JvmStatic
@@ -422,12 +530,12 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
422
530
  @JvmStatic
423
531
  fun clearSecure() {
424
532
  val inst = getInstanceOrThrow()
425
- inst.applySecureEditor(inst.encryptedPreferences.edit().clear())
426
- try {
427
- inst.applySecureEditor(inst.biometricPreferences.edit().clear())
428
- } catch (_: Exception) {
533
+ synchronized(inst) {
534
+ val biometricPreferences = inst.existingBiometricPreferences()
535
+ inst.applySecureEditor(inst.encryptedPreferences.edit().clear())
536
+ inst.clearBiometricStores(biometricPreferences)
537
+ inst.invalidateSecureKeysCache()
429
538
  }
430
- inst.invalidateSecureKeysCache()
431
539
  }
432
540
 
433
541
  // --- Biometric (separate encrypted store, requires recent biometric auth on Android) ---
@@ -438,12 +546,32 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
438
546
  }
439
547
 
440
548
  @JvmStatic
441
- fun setSecureBiometricWithLevel(key: String, value: String, @Suppress("UNUSED_PARAMETER") level: Int) {
549
+ fun setSecureBiometricWithLevel(key: String, value: String, level: Int) {
442
550
  val inst = getInstanceOrThrow()
443
551
  try {
444
- val editor = inst.biometricPreferences.edit().putString(key, value)
445
- inst.applySecureEditor(editor)
446
- inst.invalidateSecureKeysCache()
552
+ synchronized(inst) {
553
+ val biometricPreferences = inst.existingBiometricPreferences()
554
+ if (level == 0) {
555
+ inst.removeBiometricKey(key, biometricPreferences)
556
+ inst.applySecureEditor(
557
+ inst.encryptedPreferences.edit().putString(key, value),
558
+ )
559
+ } else {
560
+ val targetPreferences = inst.biometricPreferencesForLevel(level)
561
+ inst.applySecureEditor(
562
+ targetPreferences.edit().putString(key, value),
563
+ )
564
+ inst.applySecureEditor(
565
+ inst.encryptedPreferences.edit().remove(key),
566
+ )
567
+ for (preferences in biometricPreferences) {
568
+ if (preferences !== targetPreferences) {
569
+ inst.applySecureEditor(preferences.edit().remove(key))
570
+ }
571
+ }
572
+ }
573
+ inst.invalidateSecureKeysCache()
574
+ }
447
575
  } catch (e: Exception) {
448
576
  throw e.wrapStorageException(
449
577
  "NitroStorage: Biometric storage unavailable on this device",
@@ -456,9 +584,17 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
456
584
  fun getSecureBiometric(key: String): String? {
457
585
  val inst = getInstanceOrThrow()
458
586
  return try {
459
- inst.getSecureSafe(inst.biometricPreferences, key)
460
- } catch (_: Exception) {
587
+ for (preferences in inst.existingBiometricPreferences()) {
588
+ val value = inst.getSecureSafe(preferences, key)
589
+ if (value != null) {
590
+ return value
591
+ }
592
+ }
461
593
  null
594
+ } catch (e: Exception) {
595
+ throw e.wrapStorageException(
596
+ "NitroStorage: Failed to read biometric storage: ${e.message}",
597
+ )
462
598
  }
463
599
  }
464
600
 
@@ -466,18 +602,26 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
466
602
  fun deleteSecureBiometric(key: String) {
467
603
  val inst = getInstanceOrThrow()
468
604
  try {
469
- inst.applySecureEditor(inst.biometricPreferences.edit().remove(key))
470
- inst.invalidateSecureKeysCache()
471
- } catch (_: Exception) {
605
+ synchronized(inst) {
606
+ inst.removeBiometricKey(key)
607
+ inst.invalidateSecureKeysCache()
608
+ }
609
+ } catch (e: Exception) {
610
+ throw e.wrapStorageException(
611
+ "NitroStorage: Failed to delete biometric storage: ${e.message}",
612
+ )
472
613
  }
473
614
  }
474
615
 
475
616
  @JvmStatic
476
617
  fun hasSecureBiometric(key: String): Boolean {
618
+ val inst = getInstanceOrThrow()
477
619
  return try {
478
- getInstanceOrThrow().biometricPreferences.contains(key)
479
- } catch (_: Exception) {
480
- false
620
+ inst.existingBiometricPreferences().any { it.contains(key) }
621
+ } catch (e: Exception) {
622
+ throw e.wrapStorageException(
623
+ "NitroStorage: Failed to inspect biometric storage: ${e.message}",
624
+ )
481
625
  }
482
626
  }
483
627
 
@@ -485,9 +629,14 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
485
629
  fun clearSecureBiometric() {
486
630
  val inst = getInstanceOrThrow()
487
631
  try {
488
- inst.applySecureEditor(inst.biometricPreferences.edit().clear())
489
- inst.invalidateSecureKeysCache()
490
- } catch (_: Exception) {
632
+ synchronized(inst) {
633
+ inst.clearBiometricStores()
634
+ inst.invalidateSecureKeysCache()
635
+ }
636
+ } catch (e: Exception) {
637
+ throw e.wrapStorageException(
638
+ "NitroStorage: Failed to clear biometric storage: ${e.message}",
639
+ )
491
640
  }
492
641
  }
493
642
  }
package/app.plugin.js CHANGED
@@ -15,6 +15,8 @@ const FULL_BACKUP_CONTENT_RESOURCE = "@xml/nitro_storage_full_backup_content";
15
15
  const secureSharedPrefs = [
16
16
  "NitroStorageSecure.xml",
17
17
  "NitroStorageBiometric.xml",
18
+ "NitroStorageBiometricOrPasscode.xml",
19
+ "NitroStorageBiometricOnly.xml",
18
20
  ];
19
21
 
20
22
  function sharedPrefsExcludes(indent = " ") {
@@ -672,12 +672,10 @@ void HybridStorage::ensureKeyIndexHydrated(int scope) {
672
672
  return;
673
673
  }
674
674
 
675
- {
676
- std::lock_guard<std::mutex> lock(keyIndexMutex_);
677
- auto hydratedIt = keyIndexHydrated_.find(scope);
678
- if (hydratedIt != keyIndexHydrated_.end() && hydratedIt->second) {
679
- return;
680
- }
675
+ std::lock_guard<std::mutex> lock(keyIndexMutex_);
676
+ auto hydratedIt = keyIndexHydrated_.find(scope);
677
+ if (hydratedIt != keyIndexHydrated_.end() && hydratedIt->second) {
678
+ return;
681
679
  }
682
680
 
683
681
  ensureAdapter();
@@ -694,12 +692,6 @@ void HybridStorage::ensureKeyIndexHydrated(int scope) {
694
692
  throw std::runtime_error("NitroStorage: Key index hydration failed (unknown error)");
695
693
  }
696
694
 
697
- std::lock_guard<std::mutex> lock(keyIndexMutex_);
698
- // Double-check: another thread may have hydrated while we fetched
699
- auto hydratedIt = keyIndexHydrated_.find(scope);
700
- if (hydratedIt != keyIndexHydrated_.end() && hydratedIt->second) {
701
- return; // discard our results
702
- }
703
695
  auto& index = keyIndex_[scope];
704
696
  index.clear();
705
697
  for (const auto& key : keys) {
@@ -47,6 +47,8 @@ export const recoveryCodeItem = createStorageItem<string>({
47
47
 
48
48
  `BiometricLevel.BiometryOnly` does not allow passcode fallback. Use `BiometricLevel.BiometryOrPasscode` when passcode fallback is acceptable.
49
49
 
50
+ On Android 11 and newer, the two levels use separate Android Keystore keys with distinct allowed authenticators. Android 10 and older support `BiometryOrPasscode`; `BiometryOnly` reports `biometric_unavailable` because the older Keystore API cannot enforce that distinction safely for this storage backend. Android authorization remains valid for a 30-second window after successful authentication.
51
+
50
52
  ## Access Control
51
53
 
52
54
  `accessControl` maps to platform accessibility rules where available.
@@ -141,6 +143,8 @@ Android secure storage uses encrypted SharedPreferences. Restored encrypted pref
141
143
 
142
144
  - `NitroStorageSecure.xml`
143
145
  - `NitroStorageBiometric.xml`
146
+ - `NitroStorageBiometricOrPasscode.xml`
147
+ - `NitroStorageBiometricOnly.xml`
144
148
 
145
149
  If you disable `configureAndroidBackup` or maintain custom Android backup XML, add equivalent exclusions for both cloud backup and device transfer.
146
150
 
@@ -1 +1 @@
1
- {"version":3,"names":["_shared","require","_reactNativeNitroModules","_Storage","_internal","_storageCore","_migration","_storageRuntime","_storageHooks","_indexeddbBackend","_storageModule","getStorageModule","NitroModules","createHybridObject","nativeSecureBackend","nativeBackend","get","key","scope","set","value","remove","clear","has","getAllKeys","getKeysByPrefix","prefix","size","setBatch","keys","values","getBatch","map","decodeNativeBatchValue","removeBatch","removeByPrefix","setSecureAccessControl","level","getSecureBiometric","setSecureBiometricWithLevel","deleteSecureBiometric","hasSecureBiometric","clearSecureBiometric","buildNativeAdapter","internals","scopedUnsubscribers","Map","suppressedNativeEvents","StorageScope","Disk","Secure","suppressNativeEvent","suppressedEvents","consumeSuppressedNativeEvent","count","undefined","delete","ensureNativeScopeSubscription","unsubscribe","addOnChange","clearAllPendingDiskWrites","clearPendingDiskWrite","clearAllPendingSecureWrites","clearPendingSecureWrite","clearScopeRawCache","notifyAllListeners","getScopedListeners","oldValue","readCachedRawValue","cacheRawValue","notifyKeyListeners","emitKeyChange","maybeCleanupNativeScopeSubscription","listeners","hasScopeEventListeners","hasEventObserver","backend","changeSource","applyAccessControlOnSecureRawWrite","flushDiskWritesOnImport","ensureScopeSubscription","maybeCleanupScopeSubscription","onWillEmitChanges","operation","source","Memory","forEach","getSecureMetadataProfile","encrypted","hardwareBacked","core","createStorageCore","storage","exports","setAccessControl","measureOperation","assertAccessControlLevel","setSecureDefaultAccessControl","setSecureWritesAsync","enabled","setKeychainAccessGroup","group","getCapabilities","platform","disk","secure","writeBuffering","errorClassification","getSecurityCapabilities","secureStorage","accessControl","keychainAccessGroup","biometric","prompt","biometryOnly","biometryOrPasscode","metadata","perKey","listsWithoutValues","persistsTimestamps","createStorageItem","memoryItem","diskItem","secureItem","createSetItem","registerMigration","migrateToLatest","runTransaction","createSecureAuthStorage","setWebSecureStorageBackend","_backend","getWebSecureStorageBackend","setWebDiskStorageBackend","getWebDiskStorageBackend","flushWebStorageBackends"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_shared","require","_reactNativeNitroModules","_Storage","_internal","_storageCore","_migration","_storageRuntime","_storageHooks","_indexeddbBackend","_storageModule","getStorageModule","NitroModules","createHybridObject","nativeSecureBackend","nativeBackend","get","key","scope","set","value","remove","clear","has","getAllKeys","getKeysByPrefix","prefix","size","setBatch","keys","values","getBatch","map","decodeNativeBatchValue","removeBatch","removeByPrefix","setSecureAccessControl","level","getSecureBiometric","setSecureBiometricWithLevel","deleteSecureBiometric","hasSecureBiometric","clearSecureBiometric","buildNativeAdapter","internals","scopedUnsubscribers","Map","suppressedNativeEvents","StorageScope","Disk","Secure","suppressNativeEvent","suppressedEvents","consumeSuppressedNativeEvent","count","undefined","delete","ensureNativeScopeSubscription","unsubscribe","addOnChange","clearAllPendingDiskWrites","clearPendingDiskWrite","clearAllPendingSecureWrites","clearPendingSecureWrite","clearScopeRawCache","notifyAllListeners","getScopedListeners","oldValue","readCachedRawValue","cacheRawValue","notifyKeyListeners","emitKeyChange","maybeCleanupNativeScopeSubscription","listeners","hasScopeEventListeners","hasEventObserver","backend","changeSource","applyAccessControlOnSecureRawWrite","flushDiskWritesOnImport","ensureScopeSubscription","maybeCleanupScopeSubscription","onWillEmitChanges","operation","source","Memory","forEach","getSecureMetadataProfile","encrypted","hardwareBacked","core","createStorageCore","storage","exports","setAccessControl","measureOperation","assertAccessControlLevel","setSecureDefaultAccessControl","setSecureWritesAsync","enabled","setKeychainAccessGroup","group","getCapabilities","platform","disk","secure","writeBuffering","errorClassification","getSecurityCapabilities","secureStorage","accessControl","keychainAccessGroup","biometric","prompt","biometryOnly","biometryOrPasscode","metadata","perKey","listsWithoutValues","persistsTimestamps","createStorageItem","memoryItem","diskItem","secureItem","createSetItem","registerMigration","migrateToLatest","runTransaction","createSecureAuthStorage","setWebSecureStorageBackend","_backend","getWebSecureStorageBackend","setWebDiskStorageBackend","getWebDiskStorageBackend","flushWebStorageBackends"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}