Skip to content

Feat/nitro35 support#586

Merged
mCodex merged 17 commits into
masterfrom
feat/nitro35Support
Apr 27, 2026
Merged

Feat/nitro35 support#586
mCodex merged 17 commits into
masterfrom
feat/nitro35Support

Conversation

@mCodex

@mCodex mCodex commented Apr 27, 2026

Copy link
Copy Markdown
Owner

This pull request introduces a major release candidate (6.0.0-rc.13) with significant new features, security hardening, and developer experience improvements. The most important changes include the addition of versioned key rotation with lazy re-encryption, a comprehensive defense-in-depth pass (including per-entry HMAC integrity tags and AES-GCM AAD binding), new typed error classes, and a migration from Prettier/ESLint to Biome for formatting and linting. The documentation and API surface have also been updated to reflect these changes, including the removal of the default export and improved tree-shaking support.

Key management and security enhancements:

  • Added support for versioned master key rotation via rotateKeys() and getKeyVersion(), with lazy or eager re-encryption. A new useKeyRotation React hook exposes this flow declaratively. (CHANGELOG.md [1] README.md [2] [3] android/src/main/java/com/sensitiveinfo/internal/storage/KeyVersionRegistry.kt [4] android/src/main/java/com/sensitiveinfo/internal/storage/PersistedEntry.kt [5] [6] [7]
  • Introduced per-entry HMAC-SHA256 integrity tags bound to all metadata and ciphertext, with verification before any biometric prompt. Tampering raises an IntegrityViolationError. (CHANGELOG.md [1] README.md [2] android/src/main/java/com/sensitiveinfo/internal/crypto/MetadataIntegrity.kt [3] android/src/main/java/com/sensitiveinfo/internal/storage/PersistedEntry.kt [4] [5] [6]
  • On Android, AES-GCM AAD now binds ciphertext to service|key|v<version>, preventing cross-entry swap attacks. Device-unlocked state is required for all Keystore keys (API 28+), mirroring iOS semantics. (CHANGELOG.md [1] android/src/main/java/com/sensitiveinfo/internal/crypto/CryptoManager.kt [2] [3] [4] [5] [6]

API and error handling improvements:

  • Added new typed error classes (SensitiveInfoError, NotFoundError, AuthenticationCanceledError, IntegrityViolationError, KeyInvalidatedError, RotationFailedError) with discriminant codes and instanceof predicates, available from the /errors subpath. (CHANGELOG.md [1] README.md [2]
  • Removed the default export; all helpers must now be imported by name. React hooks are no longer re-exported from the root and must be imported from /hooks. (CHANGELOG.md [1] README.md [2] [3]

Developer experience and documentation:

  • Migrated linting/formatting from ESLint + Prettier to Biome 2, consolidating configuration and improving CI speed. The .prettierrc.js file was removed. (CHANGELOG.md [1] .prettierrc.js [2]
  • Expanded documentation in README.md to cover key rotation, the security model, tree-shaking, and the new hook architecture. (README.md [1] [2] [3]

These changes collectively advance the security, usability, and maintainability of the package, preparing it for a stable 6.0 release.

mCodex and others added 8 commits April 24, 2026 08:17
Add biome.json and migrate lint/format tooling from ESLint/Prettier to Biome (remove eslint/prettier configs and eslint.config.mts). Update package.json scripts to use biome (lint, lint:ci, format) and add Biome-related dev deps. Bump example and root package dependency versions (including react-native, react-native-nitro-modules, nitrogen, Babel and related tooling), add nkf to example/Gemfile, and update Android Gradle wrapper to 9.3.1 while simplifying gradle wrapper scripts (remove CLASSPATH handling).
Introduce a typed error surface and refactor async/hooks/storage plumbing for better safety and tree-shaking.

Key changes:
- Add src/errors.ts: typed SensitiveInfoError subclasses, ErrorCode constants, adapters (toSensitiveInfoError) and predicate helpers.
- Wrap native calls in src/core/storage.ts to throw/return typed errors, and add rotateKeys and getKeyVersion; expose a SensitiveInfo namespace and named exports for tree-shaking.
- Add useAsync abstraction (src/hooks/useAsync.ts) and refactor hooks (useHasSecret, useSecretItem, useSecurityAvailability) to use it. Add a new useKeyRotation hook.
- Update hooks index exports to include new hooks and types.
- Rework internal helpers: normalizeOptions improved and internal/errors re-exports updated to forward to the new typed helpers.
- Add strong types file src/sensitive-info.nitro.ts and update top-level exports in src/index.ts to include errors and new storage APIs.
- Add unit tests for errors and public index surface (src/__tests__/errors.test.ts, src/__tests__/index.test.ts).
- package.json: add "exports" map and sideEffects:false, and align react-dom version.

These changes modernize error handling, centralize async lifecycle management for hooks, and add support for key rotation while keeping backward-compatible exports.
Introduce versioned key rotation support and related developer ergonomics: add native stubs (rotateKeys, getKeyVersion) on Android, document the new useKeyRotation hook and imperative rotateKeys/getKeyVersion APIs, and wire a KeyRotationPanel into the example app. Update README and CHANGELOG for 6.0.0-rc.13, add hook docs in HOOKS.md, and include new tests for key rotation/hooks. Remove .prettierrc, apply consistent formatting/style updates across examples and components (node:path imports, minor TSX/JS formatting), and adjust expo/config plugin and other config files.
- Added HMAC-SHA256 integrity tags to entries, enhancing tamper detection.
- Introduced AES-GCM AAD for additional security against cross-entry attacks.
- Implemented zeroization of plaintext buffers post-use on both platforms.
- Updated error handling to include IntegrityViolationError for tampering cases.
- Enhanced metadata structure to include integrity tags and AAD usage flags.
- Updated tests to verify integrity tag propagation and error handling for integrity violations.

Co-authored-by: Copilot <copilot@github.com>
Introduce a shared useAsyncQuery hook to centralize stable-options → skip → memoize → useAsync semantics and ensure consistent abort/skip behavior across hooks. Refactor useHasSecret and useSecretItem to use the new hook. Add deterministic test fixtures (buildTestItem/buildTestMetadata) and update unit tests to use them. Adjust error imports to prefer the public errors surface and remove legacy re-exports from src/internal/errors.ts. Bump package version to 6.0.0-rc.13. Files added: src/hooks/useAsyncQuery.ts, src/__tests__/__mocks__/fixtures.ts; files updated: multiple hooks, tests, and internal error helpers.
…uery integration

Co-authored-by: Copilot <copilot@github.com>
Copilot AI review requested due to automatic review settings April 27, 2026 14:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR prepares a 6.0.0 release candidate by adding versioned key rotation + integrity hardening, introducing typed errors and new hook primitives, and migrating project tooling to Biome while updating package exports for tree-shaking.

Changes:

  • Added key rotation APIs (rotateKeys, getKeyVersion) + useKeyRotation hook, plus typed error surface under /errors.
  • Implemented defense-in-depth integrity protections (per-entry HMAC tags, Android AAD binding, device-unlocked gating) and related metadata updates across platforms.
  • Migrated formatting/linting to Biome and updated packaging/exports for side-effect-free, subpath-based consumption.

Reviewed changes

Copilot reviewed 92 out of 99 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tsconfig.test.json Adds Jest/Node types and streamlines include/exclude for tests.
tsconfig.json Adds TS deprecation config and excludes tests from main compilation.
src/sensitive-info.nitro.ts Extends Nitro spec/types with rotation requests/results and metadata fields.
src/internal/options.ts Makes option normalization shape deterministic by pruning undefined.
src/internal/native.ts Keeps native instance memoization while adopting Biome formatting.
src/internal/errors.ts Removes marker predicates, keeping only message extraction helper.
src/index.ts Re-exports core API + typed errors/types; removes default export behavior.
src/hooks/useStableOptions.ts Formatting + retains memoized option merging implementation.
src/hooks/useSecurityAvailability.ts Refactors to shared useAsync primitive with caching/refetch.
src/hooks/useSecureStorage.ts Refactors to useAsyncQuery + useMutation composition.
src/hooks/useSecureOperation.ts Refactors to useMutation with consistent loading/error behavior.
src/hooks/useSecretItem.ts Refactors to useAsyncQuery shared fetch+skip wiring.
src/hooks/useSecret.ts Keeps API but updates formatting and dependencies for refactor.
src/hooks/useMutation.ts New shared mutation state machine (abort + auth-cancel + HookError).
src/hooks/useKeyRotation.ts New hook wrapping rotateKeys/getKeyVersion with UI-ready state.
src/hooks/useHasSecret.ts Refactors to useAsyncQuery shared fetch+skip wiring.
src/hooks/useAsyncQuery.ts New shared “stable options → skip → memoize → useAsync” helper.
src/hooks/useAsyncLifecycle.ts Formatting; keeps abort+mount guard utility.
src/hooks/useAsync.ts New shared async state machine used by data-fetching hooks.
src/hooks/types.ts Formatting; preserves HookError + async state/result helpers.
src/hooks/index.ts Adds useKeyRotation export and reorganizes named exports.
src/hooks/error-utils.ts Uses new public /errors predicate + internal message helper.
src/errors.ts New typed error classes, codes, adapters, and predicates.
src/core/storage.ts Wraps native throws into typed errors; adds rotate APIs.
src/tests/storage.test.ts Adjusts formatting; keeps coverage for storage surface.
src/tests/internal.options.test.ts Updates expectations for normalized/pruned options.
src/tests/internal.native.test.ts Updates mocks + formatting for native instance memo tests.
src/tests/internal.errors.test.ts Switches not-found checks to new /errors predicate.
src/tests/index.test.ts Updates entrypoint expectations (no default export; new exports).
src/tests/hooks.useStableOptions.test.tsx Formatting-only updates.
src/tests/hooks.useSecurityAvailability.test.tsx Validates new useAsync-based hook behavior.
src/tests/hooks.useSecureOperation.test.tsx Validates useMutation-based execute behavior.
src/tests/hooks.useSecretItem.test.tsx Updates tests to fixture builders + new hook wiring.
src/tests/hooks.useSecret.test.tsx Updates tests to match refactor and formatting.
src/tests/hooks.useKeyRotation.test.tsx New tests for useKeyRotation.
src/tests/hooks.useHasSecret.test.tsx Updates tests for refactored hook.
src/tests/hooks.useAsyncLifecycle.test.tsx Formatting-only updates.
src/tests/hooks.types.test.ts Formatting-only updates.
src/tests/hooks.index.test.ts New test to validate hooks subpath re-exports.
src/tests/hooks.error-utils.test.ts Formatting-only updates.
src/tests/errors.test.ts New tests for typed errors/adapters/predicates.
src/tests/mocks/react-native.ts Formatting-only updates for mocks.
src/tests/mocks/react-native-nitro-modules.ts Formatting-only updates for mocks.
src/tests/mocks/fixtures.ts New deterministic test fixtures for metadata/items.
release.config.cjs Formatting-only updates for semantic-release config.
post-script.js Formatting-only updates; retains Nitro Android workaround.
package.json Adds exports + sideEffects:false, switches to Biome, updates deps.
nitro.json Formatting-only updates to Nitro config.
jest.config.js Formatting; adjusts coverage thresholds; keeps coverage collection.
ios/Internal/Security/MetadataIntegrity.swift Adds per-entry HMAC integrity signing/verification.
ios/Internal/Security/KeyVersionRegistry.swift Adds key version registry for iOS key rotation.
ios/Internal/MetadataCoders.swift Persists key version + integrity tag in metadata coding.
ios/HybridSensitiveInfo.swift Implements iOS key rotation + integrity verification + lazy upgrade.
example/tsconfig.json Formatting-only updates.
example/src/utils/formatError.ts Formatting-only updates.
example/src/constants/index.ts Updates imports and formatting for new root API shape.
example/src/components/SecretsList.tsx Formatting + type-only React import conversion.
example/src/components/SecretForm.tsx Formatting + type-only React import conversion.
example/src/components/ModeSelector.tsx Formatting + accessibility state maintained.
example/src/components/KeyRotationPanel.tsx New example UI for rotation.
example/src/components/Header.tsx Formatting + type-only React import conversion.
example/src/components/Card.tsx Formatting + type-only React import conversion.
example/src/components/ActionsPanel.tsx Formatting + type-only React import conversion.
example/src/components/ActionButton.tsx Formatting + type-only React import conversion.
example/react-native.config.js Updates to node: path import + formatting.
example/package.json Updates RN/Nitro versions; switches lint to Biome.
example/metro.config.js Updates to node: path import + formatting.
example/jest.config.js Formatting-only updates.
example/index.js Formatting-only updates.
example/babel.config.js Formatting-only updates.
example/app.json Formatting-only updates.
example/android/gradlew.bat Removes redundant CLASSPATH usage when invoking wrapper jar.
example/android/gradlew Removes unused CLASSPATH wiring for wrapper invocation.
example/android/gradle/wrapper/gradle-wrapper.properties Updates Gradle wrapper distribution URL.
example/Gemfile Adds nkf gem dependency.
example/.prettierrc.js Removes Prettier config in favor of Biome.
example/.eslintrc.js Removes ESLint config in favor of Biome.
eslint.config.mts Removes ESLint flat config (Biome migration).
docs/HOOKS.md Documents new useKeyRotation hook.
biome.json Adds Biome formatter/linter configuration and overrides.
babel.config.js Formatting-only updates.
app.plugin.js Formatting-only updates.
android/src/main/java/com/sensitiveinfo/internal/util/SensitiveInfoExceptions.kt Adds integrity-violation exception code/message.
android/src/main/java/com/sensitiveinfo/internal/util/AliasGenerator.kt Embeds key version in Keystore aliases; adds HMAC alias helper.
android/src/main/java/com/sensitiveinfo/internal/storage/PersistedMetadata.kt Persists key version + integrity tag in Android metadata.
android/src/main/java/com/sensitiveinfo/internal/storage/PersistedEntry.kt Persists key version/AAD flag/integrity tag for Android entries.
android/src/main/java/com/sensitiveinfo/internal/storage/KeyVersionRegistry.kt Adds Android key version registry backed by SharedPreferences.
android/src/main/java/com/sensitiveinfo/internal/crypto/MetadataIntegrity.kt Adds Android per-entry HMAC signing/verification (Keystore-backed).
android/src/main/java/com/sensitiveinfo/internal/crypto/CryptoManager.kt Adds optional AES-GCM AAD, plaintext zeroization, device-unlock requirement.
README.md Updates docs for new hook/error subpaths, key rotation, security model, tree-shaking.
CHANGELOG.md Adds Unreleased 6.0.0-rc.13 notes and breaking-change callouts.
.release-it.json Formatting-only updates.
.prettierrc.js Removes Prettier config in favor of Biome.
Comments suppressed due to low confidence (7)

package.json:1

  • CHANGELOG.md and the PR description refer to 6.0.0-rc.13, but package.json still reports 6.0.0-rc.12. Please align the package version with the release candidate referenced in the PR (or update the changelog/description if the version bump is intentionally deferred).
    src/hooks/useSecureStorage.ts:1
  • The effect (and its comment) implies localItems should reset when a fresh fetch result arrives, but with an empty dependency array it runs only once on mount. This can leave localItems permanently overriding fetchQuery.data after mutations (e.g., removeSecret) or after option/service changes. Update the dependency list to key off the fetch result (for example fetchQuery.data / a fetch counter) so the local override is cleared when new server/native data lands.
    src/errors.ts:1
  • extractMessage drops useful messages from non-Error objects (for example { code: 'E_INTEGRITY_VIOLATION', message: 'oops' }), causing toSensitiveInfoError() to emit generic fallback text even when a specific message is available. Consider also reading a string message field from plain objects to preserve native error detail.
    ios/Internal/Security/MetadataIntegrity.swift:1
  • If SecItemAdd returns errSecDuplicateItem (possible under cross-process races between the lookup and add), this currently returns a brand-new random key (rawKey) instead of loading and returning the already-stored key. That would cause HMAC verification failures for entries created with the existing key. On errSecDuplicateItem, re-fetch the key from the Keychain (or retry SecItemCopyMatching) and return the stored key instead.
    ios/HybridSensitiveInfo.swift:1
  • Integrity tag generation errors are silently swallowed (try?), which can result in writing new entries without an integrityTag (making them indistinguishable from legacy entries and disabling tamper detection for those writes). Consider failing the write when HMAC key creation/signing fails, or at least surfacing an explicit error so callers don’t get a false sense of integrity coverage.
    example/src/components/KeyRotationPanel.tsx:1
  • The “Rotate + re-encrypt all” button triggers the same rotate() call as the lazy path, but the hook is instantiated with { service } (no reEncryptEagerly: true), so eager rotation is never actually requested. Either create a second useKeyRotation({ service, reEncryptEagerly: true }), or update the hook API to accept per-call options so the eager button can pass reEncryptEagerly: true.
    ios/Internal/Security/MetadataIntegrity.swift:1
  • NSLock is not a recursive lock. Either switch to NSRecursiveLock (if re-entrancy is required) or update the comment to avoid implying recursion guarantees that the implementation doesn’t provide.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mCodex mCodex self-assigned this Apr 27, 2026
mCodex and others added 8 commits April 27, 2026 12:15
Co-authored-by: Copilot <copilot@github.com>
…used components

- Introduced AccessControlCard for managing access modes with visual feedback.
- Added DiagnosticsCard to display security availability and key version information.
- Removed ActionButton, ActionsPanel, Card, Header, KeyRotationPanel, ModeSelector, SecretForm, SecretsList, and formatError utility as they were no longer needed.
- Updated constants to streamline access modes and added biometric prompt configuration.
- Enhanced StorageCard to manage secure storage with improved UI and functionality.
- Introduced Section and StatusLine components for better layout and error handling.
- Updated TypeScript configuration to include hooks and errors paths for improved module resolution.

Co-authored-by: Copilot <copilot@github.com>
Split option handling into readOptions/writeOptions via resolveOptions and update components to use them (Storage, KeyRotation, Diagnostics, AccessControl). Add reusable Button and Footer components and a useAsyncAction hook. Improve Storage UI: reveal-with-TTL, async actions for save/reveal/delete/clear, item list with badges, and better loading/status handling. Adjust AccessControl to show capability labels and fallback state for unavailable biometry. Update KeyRotation/Diagnostics to use imperative getKeyVersion and avoid unnecessary auth prompts. Replace manual memset_s zeroization with Data.resetBytes on iOS. Tweak tsconfig for bundler module resolution and stricter checks. Also add GITHUB_URL constant and minor style/UX polish across the example app.
Add extensive JSDoc, examples and type refinements across the library. Introduces a SensitiveInfoApi facade, documents all core APIs (setItem/getItem/hasItem/deleteItem/getAllItems/clearService/getSupportedSecurityLevels/rotateKeys/getKeyVersion) with params, returns, errors and examples. Expands and documents typed error classes and predicates in errors.ts, improves hook-related types and helpers (HookError, AsyncState, mutation results) in hooks/types.ts, clarifies useSecureStorage usage docs, and enriches the Nitro interface and payload types in sensitive-info.nitro.ts (SecurityLevel, AccessControl, request/response shapes, StorageMetadata). Also updates package root docs and quick-start in index.ts. Changes are primarily documentation and typing improvements; no behavioral changes intended.
Add comprehensive JSDoc to useSecret and useSecretItem to clarify parameters, return shapes, and behavior. Highlights: useSecret now documents that it combines a read subscription with saveSecret/deleteSecret that refresh the cache on success and that mutation helpers return a discriminated HookMutationResult (do not throw). useSecretItem docs explain includeValue:false (metadata-only, avoids iOS biometric prompt), that NotFoundError is surfaced as data:null, and include usage examples and @see references. No functional changes — only documentation improvements.
Add comprehensive JSDoc comments to useHasSecret, useKeyRotation, useSecureOperation, and useSecurityAvailability. The updates document params, return types, remarks, examples, and related links; clarify behaviors such as avoiding biometric prompts when only checking existence, lazy vs eager key rotation and its biometric implications, execute() swallowing errors and exposing AuthenticationCanceledError as a cause, and caching/refetch semantics for security capability queries. Improves developer guidance and API discoverability.
@mCodex mCodex merged commit 5017b91 into master Apr 27, 2026
9 checks passed
@mCodex mCodex deleted the feat/nitro35Support branch April 28, 2026 15:01
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.

2 participants