Skip to content

Commit 6f6402f

Browse files
committed
chore(release): v6.1.0
1 parent bfceb1b commit 6f6402f

2 files changed

Lines changed: 6 additions & 56 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,13 @@
1-
## [6.1.0](https://github.com/mcodex/react-native-sensitive-info/compare/v6.0.0...v6.1.0) (2026-04-28)
2-
3-
### Added
4-
5-
* **biometric availability:** New `biometryStatus` field on `SecurityAvailability` (`'available' | 'notEnrolled' | 'notAvailable' | 'lockedOut' | 'unknown'`) disambiguates *hardware missing*, *hardware present but no enrollment*, and *currently usable*. The legacy `biometry` boolean stays as a backward-compatible alias for `biometryStatus === 'available'`. Mapped natively from `LAError` codes on iOS and `BiometricManager.canAuthenticate` results on Android.
6-
* **policy precheck:** New `canUseAccessControl(policy, levels?)` and `canUseAccessControlSync(policy, levels)` predict whether a given `AccessControl` policy will succeed on the current device. When a `SecurityAvailability` snapshot is supplied (the sync variant always requires one), they are a pure TS mapping with no native call; if `levels` is omitted from `canUseAccessControl`, it first fetches the current snapshot via `getSupportedSecurityLevels()`.
7-
* **foreground auto-refresh:** `useSecurityAvailability({ refreshOnForeground: true })` subscribes to `AppState` and refetches on `active` transitions (debounced ~500 ms, unsubscribes on unmount). Covers the *user leaves to enroll a fingerprint and returns* flow without manual `refetch()`.
8-
* **enrollment listener:** New `useBiometryStatusWatcher(onChange)` hook fires only on actual `BiometryStatus` transitions (not on every render or refetch). Lives in its own module for tree-shaking.
9-
10-
All additions are non-breaking; apps reading only the `biometry` boolean continue to work unchanged.
11-
12-
### Fixed
13-
14-
* **ios:** `getItem` no longer triggers a second Face ID / Touch ID prompt for biometry-protected entries. The lazy re-encryption path that runs after a successful authenticated read used to call `SecItemUpdate` against the same Keychain item to refresh its key-version metadata; iOS treats that as a separate authorization gate, prompting the user a second time. Biometric items now skip the lazy refresh entirely and are upgraded only by an explicit `setItem` (full overwrite, single user-initiated write) or by `rotateKeys({ reEncryptEagerly: true })`. Non-biometric items continue to be upgraded silently.
15-
* **android:** Same double-prompt regression on `getItem` for entries whose Keystore key was created with `setUserAuthenticationRequired(true)`. Lazy re-encryption inside `getItem` allocated a new key alias for the active version and `Cipher.init` on that fresh key required its own biometric authorization, surfacing as a second prompt right after the read. The lazy refresh now skips entries with `requiresAuthentication == true` (or any biometry-class access policy); explicit `setItem` and `rotateKeys({ reEncryptEagerly: true })` still upgrade them.
16-
* **ios:** `setItem` no longer returns `errSecDuplicateItem` ("The specified item already exists in the keychain") when the caller toggles `iosSynchronizable` between writes or when iCloud Keychain restores an entry between our delete and add. The internal upsert helper now wipes prior entries with `kSecAttrSynchronizableAny` and absorbs the iCloud-restore race with a single bounded retry. Bundle ID + access group already scope the partition, so the overwrite never crosses an app or sharing boundary.
17-
18-
### Docs
19-
20-
* Clarify `SecurityAvailability.secureEnclave` semantics: it now documents the cross-platform behaviour (Secure Enclave on iOS / mirrors `strongBox` on Android) so consumers can gate "hardware-backed key" UX without branching on `Platform.OS`.
21-
* Clarify that `canUseAccessControl(policy, levels?)` only skips the native call when a snapshot is supplied; if `levels` is omitted it fetches one via `getSupportedSecurityLevels()`.
22-
* Update the Android `requiresBiometricAuth` doc comment so it matches the actual classification (`devicePasscode` entries are auth-gated via `entry.requiresAuthentication` and are skipped by the lazy refresh).
23-
24-
## [6.0.0](https://github.com/mcodex/react-native-sensitive-info/compare/v6.0.0-rc.12...v6.0.0) (2026-04-28)
25-
26-
First stable release of the Nitro-based v6 line. Promotes `6.0.0-rc.12` to GA with no API changes — the release notes below summarize everything new since the v5 line.
1+
## [6.1.0](https://github.com/mcodex/react-native-sensitive-info/compare/v6.0.0-rc.12...v6.1.0) (2026-04-28)
272

283
### Features
294

30-
* **rotation:** Add versioned key rotation via `rotateKeys()` and `getKeyVersion()` with lazy re-encryption on read. New `useKeyRotation` hook exposes the same flow declaratively.
31-
* **security hardening:** Defense-in-depth pass — non-breaking, applied transparently to new writes and via lazy upgrade on rotation:
32-
- HMAC-SHA256 integrity tag bound to every entry's metadata + ciphertext, surfaced on `StorageMetadata.integrityTag`. Tampering with SharedPreferences/Keychain attributes now raises `IntegrityViolationError` (`E_INTEGRITY_VIOLATION`) before any biometric prompt is shown.
33-
- AES-GCM AAD on Android binds ciphertext to `service|key|v<version>`, defeating cross-entry swap attacks.
34-
- `setUnlockedDeviceRequired(true)` on every Android Keystore key (API 28+), mirroring iOS's `kSecAttrAccessibleWhenUnlocked` semantics.
35-
- Plaintext byte buffers are zeroized after use on both platforms.
36-
- Constant-time HMAC comparison via `MessageDigest.isEqual` / manual `UInt8` XOR fold.
37-
- Backwards compatible: entries written by earlier versions decode without verification and are upgraded on the next write or rotation.
38-
* **errors:** New typed error classes (`SensitiveInfoError`, `NotFoundError`, `AuthenticationCanceledError`, `IntegrityViolationError`, `KeyInvalidatedError`, `RotationFailedError`) with `code` discriminants and `instanceof` predicates. Importable from the `react-native-sensitive-info/errors` subpath.
39-
* **tree-shaking:** `"sideEffects": false` everywhere; the package now publishes three focused subpath entries (`.`, `/hooks`, `/errors`). The default export has been removed — import only the helpers you use.
40-
* **nitro 0.35:** Regenerated against `nitrogen@0.35.5` and `react-native-nitro-modules@0.35.5`.
41-
* **tooling:** Migrated linting/formatting from ESLint + Prettier to **Biome 2**. Single config at `biome.json`, faster CI runs.
42-
43-
### Refactor (KISS · DRY · SRP)
44-
45-
* Introduced `useAsyncQuery` (read-only hooks) and `useMutation` (mutation hooks) primitives. `useHasSecret`, `useSecretItem`, `useSecureOperation`, `useKeyRotation`, and `useSecureStorage` now compose the same lifecycle/abort/error-handling pipeline — no duplicated state machines.
46-
* `useSecureStorage` shrunk from ~230 LOC to ~180 LOC and reuses the shared abort + auth-cancel semantics; behaviour is unchanged.
47-
* Test fixtures consolidated in `src/__tests__/__mocks__/fixtures.ts` (`buildTestItem`, `buildTestMetadata`).
48-
* Removed redundant re-exports from `src/internal/errors.ts`.
49-
50-
### Breaking changes
5+
* add AccessControlCard and DiagnosticsCard components; remove unused components ([6701d84](https://github.com/mcodex/react-native-sensitive-info/commit/6701d84226b97cf587064c596f871e8395aa7250))
6+
* implement integrity hardening for sensitive data storage ([60b2cf5](https://github.com/mcodex/react-native-sensitive-info/commit/60b2cf5c8520cb40f917a698f326a239861e5d10))
517

52-
* The default export is gone. Use named imports: `import { setItem } from 'react-native-sensitive-info'`.
53-
* React hooks are no longer re-exported from the package root — import them from `react-native-sensitive-info/hooks`.
54-
55-
### Notes
56-
57-
* **iOS rotation** updates the Keychain metadata via `SecItemUpdate`, preserving the original access-control attributes while bumping `keyVersion`.
58-
* **Android rotation** mints a fresh per-entry Keystore alias (`SensitiveInfo_<hash>_v<version>`) during lazy or eager re-encryption and deletes the stale alias after a successful rewrite.
59-
* Version state lives in a non-secret registry (`SharedPreferences` on Android, `UserDefaults` on iOS). Delete the app's data to reset.
8+
### Bug Fixes
609

10+
* update module resolver alias to correctly map source directory for subpath imports ([106621e](https://github.com/mcodex/react-native-sensitive-info/commit/106621e8d4c0cba81987196054a971628b4a36d8))
6111
## [6.0.0-rc.12](https://github.com/mcodex/react-native-sensitive-info/compare/v6.0.0-rc.11...v6.0.0-rc.12) (2025-12-16)
6212

6313
### Features

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-sensitive-info",
3-
"version": "6.0.0",
3+
"version": "6.1.0",
44
"description": "🔐 React Native secure storage, rebuilt with Nitro Modules ⚡️ Biometric-ready, StrongBox-aware, and metadata-rich for modern mobile apps",
55
"main": "./lib/commonjs/index.js",
66
"module": "./lib/module/index.js",

0 commit comments

Comments
 (0)