You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+26Lines changed: 26 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,32 @@ 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.4.2/0.4.3 - 2026-03-05
8
+
9
+
### Fixed
10
+
11
+
- Fix crash on Android devices without biometric hardware — all biometric storage paths now catch initialization failures gracefully (non-biometric operations unaffected).
12
+
- Fix Android keystore corruption recovery incorrectly wiping data on a locked keystore — only `AEADBadTagException` now triggers wipe; all other init failures throw without touching stored data.
13
+
- Synchronize `AndroidStorageAdapter.invalidateSecureKeysCache()` under instance lock to close a race between concurrent reads and writes.
14
+
- Synchronize `setSecureBatch`/`deleteSecureBatch` under instance lock to prevent cache rebuild racing a mid-batch write.
15
+
- Propagate `SharedPreferences.commit()` failures out of `applySecureEditor` instead of swallowing them.
16
+
- Fix `IOSStorageAdapterCpp::clearDisk()` using `dictionaryRepresentation` (includes OS-injected keys) — switched to `persistentDomainForName:` scoped strictly to the app suite.
17
+
- Fix `clearSecure()`/`clearSecureBiometric()` clearing the in-memory key cache before confirming `SecItemDelete` succeeded — cache is now only updated after the deletion is confirmed.
18
+
- Fix potential unexpected biometric auth prompt in `getSecure()` — added `kSecUseAuthenticationUI = kSecUseAuthenticationUIFail` consistent with `hasSecure()`.
19
+
- Fix `setKeychainAccessGroup()` race where a concurrent `getAllKeysSecure()` could observe a stale cache between group update and cache invalidation — both are now updated atomically under both mutexes.
20
+
- Fix CFErrorRef leak in `SecAccessControlCreateWithFlags` error path.
21
+
- Fix `setSecureBiometricWithLevel()` incorrectly reporting "value restored" when backup restoration itself threw — now propagates the composite error.
22
+
- Mark `secureKeyCacheHydrated_` as `std::atomic<bool>` to satisfy the C++ memory model.
23
+
- Fix `HybridStorage::addOnChange()` unsubscribe lambda capturing `this` raw pointer — switched to `std::weak_ptr` capture to prevent use-after-free if `HybridStorage` is destroyed before the JS unsubscribe callback fires.
24
+
- Validate access control level in `setSecureAccessControl()` (must be 0–4) and biometric level in `setSecureBiometricWithLevel()` (must be 0–2) — invalid values now throw instead of being silently passed to the native adapter.
25
+
- Fix `clearSecureBiometric()` calling `onScopeClear` which unnecessarily evicted all secure keys from the index — now only marks the index stale for lazy re-hydration.
26
+
- Fix `fromJavaStringArray()` silently dropping null JNI array elements — null entries are now preserved as empty strings to maintain positional alignment.
27
+
- Extend `isKeychainLockedError()` to detect Android `KeyPermanentlyInvalidatedException` and `InvalidKeyException` in addition to existing iOS/Android patterns.
28
+
- Fix web `getAll()` performing O(n) individual reads — switched to `WebStorage.getBatch()`.
29
+
- Fix web `subscribe()` accumulating `window.addEventListener("storage", …)` calls — now reference-counted and removed when the last subscriber unsubscribes.
30
+
- Fix web `import()` for Secure scope skipping `flushSecureWrites()` and `setSecureAccessControl()` before writing.
31
+
- Expand ProGuard/R8 keep rules with explicit method-signature patterns so JNI-callable methods survive aggressive R8 shrinking in release builds.
These are synchronous and go directly to the native backend without any serialize/deserialize step.
530
+
531
+
---
532
+
533
+
### `isKeychainLockedError(err)`
534
+
535
+
Utility to detect iOS Keychain locked errors and Android key invalidation errors in secure storage operations. Returns `true` if the error was caused by a locked keychain (device locked, first unlock not yet performed, etc.) or an Android `KeyPermanentlyInvalidatedException` / `InvalidKeyException`. Always returns `false` on web.
0 commit comments