react-native-dpop 0.3.0 → 0.4.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.
package/README.md CHANGED
@@ -4,18 +4,19 @@ React Native library for DPoP proof generation and key management.
4
4
 
5
5
  ## Features
6
6
 
7
- - Generate DPoP proofs (`dpop+jwt`) signed with ES256.
8
- - Manage key pairs in the device keystore (create, rotate, delete).
9
- - Export public key in `JWK`, `DER`, or `RAW` format.
10
- - Calculate JWK thumbprint (`SHA-256`, base64url).
11
- - Verify if a proof is bound to a given key alias.
12
- - Retrieve non-sensitive key metadata (hardware-backed, StrongBox info, etc.).
13
- - iOS key storage uses Secure Enclave when available, with Keychain fallback.
7
+ - Generate DPoP proofs (`dpop+jwt`) signed with ES256
8
+ - Manage key pairs in the platform keystore
9
+ - Export the public key as `JWK`, `DER`, or `RAW`
10
+ - Calculate JWK thumbprints (`SHA-256`, base64url)
11
+ - Verify whether a proof is bound to a given key alias
12
+ - Retrieve non-sensitive key metadata, including secure hardware details
13
+ - Use Secure Enclave on iOS when available, with Keychain fallback
14
+ - Prefer StrongBox on Android when available, with hardware-backed fallback
14
15
 
15
- ## Platform Support
16
+ ## Platform support
16
17
 
17
- - Android: supported.
18
- - iOS: supported.
18
+ - Android
19
+ - iOS
19
20
 
20
21
  ## Installation
21
22
 
@@ -23,13 +24,13 @@ React Native library for DPoP proof generation and key management.
23
24
  npm install react-native-dpop
24
25
  ```
25
26
 
26
- For iOS, install pods in your app project:
27
+ For iOS:
27
28
 
28
29
  ```sh
29
30
  cd ios && pod install
30
31
  ```
31
32
 
32
- ## Quick Start
33
+ ## Quick start
33
34
 
34
35
  ```ts
35
36
  import { DPoP } from 'react-native-dpop';
@@ -38,27 +39,18 @@ const dpop = await DPoP.generateProof({
38
39
  htu: 'https://api.example.com/token',
39
40
  htm: 'POST',
40
41
  accessToken: 'ACCESS_TOKEN',
41
- nonce: 'server-nonce',
42
+ nonce: 'SERVER_NONCE',
42
43
  });
43
44
 
44
45
  const proof = dpop.proof;
45
46
  const thumbprint = await dpop.calculateThumbprint();
46
47
  const publicJwk = await dpop.getPublicKey('JWK');
47
- const isBound = await dpop.isBoundToAlias();
48
+ const keyInfo = await DPoP.getKeyInfo();
48
49
  ```
49
50
 
50
51
  ## API
51
52
 
52
- ### Types
53
-
54
- - `GenerateProofInput`
55
- - `DPoPProofContext`
56
- - `DPoPKeyInfo`
57
- - `SecureHardwareFallbackReason = 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'POLICY_REJECTED' | 'UNKNOWN'`
58
- - `PublicJwk`
59
- - `PublicKeyFormat = 'JWK' | 'DER' | 'RAW'`
60
-
61
- ### `DPoP` static methods
53
+ ### Static methods
62
54
 
63
55
  - `DPoP.generateProof(input): Promise<DPoP>`
64
56
  - `DPoP.assertHardwareBacked(alias?): Promise<void>`
@@ -67,22 +59,97 @@ const isBound = await dpop.isBoundToAlias();
67
59
  - `DPoP.hasKeyPair(alias?): Promise<boolean>`
68
60
  - `DPoP.rotateKeyPair(alias?): Promise<void>`
69
61
 
70
- ### `DPoP` instance fields
62
+ ### Instance members
71
63
 
72
64
  - `proof: string`
73
65
  - `proofContext: DPoPProofContext`
74
66
  - `alias?: string`
75
-
76
- ### `DPoP` instance methods
77
-
78
67
  - `calculateThumbprint(): Promise<string>`
79
68
  - `getPublicKey(format): Promise<PublicJwk | string>`
80
69
  - `signWithDpopPrivateKey(payload): Promise<string>`
81
70
  - `isBoundToAlias(alias?): Promise<boolean>`
82
71
 
83
- ## Error Codes
72
+ ### Main types
84
73
 
85
- Native errors are rejected with codes such as:
74
+ - `GenerateProofInput`
75
+ - `DPoPProofContext`
76
+ - `DPoPKeyInfo`
77
+ - `PublicJwk`
78
+ - `PublicKeyFormat = 'JWK' | 'DER' | 'RAW'`
79
+ - `SecureHardwareFallbackReason = 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'POLICY_REJECTED' | 'UNKNOWN'`
80
+ - `AndroidSecurityLevelName = 'SOFTWARE' | 'TRUSTED_ENVIRONMENT' | 'STRONGBOX'`
81
+ - `IOSSecurityLevelName = 'SOFTWARE' | 'SECURE_ENCLAVE'`
82
+
83
+ ## `getKeyInfo()`
84
+
85
+ `getKeyInfo()` returns shared fields plus platform-specific hardware metadata.
86
+
87
+ ```ts
88
+ type DPoPKeyInfo = {
89
+ alias: string;
90
+ hasKeyPair: boolean;
91
+ algorithm?: string;
92
+ curve?: string;
93
+ insideSecureHardware?: boolean;
94
+ hardware?: {
95
+ android?: {
96
+ strongBoxAvailable: boolean;
97
+ strongBoxBacked: boolean;
98
+ securityLevel?: number;
99
+ securityLevelName?: 'SOFTWARE' | 'TRUSTED_ENVIRONMENT' | 'STRONGBOX';
100
+ strongBoxFallbackReason?: 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'POLICY_REJECTED' | 'UNKNOWN' | null;
101
+ };
102
+ ios?: {
103
+ secureEnclaveAvailable: boolean;
104
+ secureEnclaveBacked: boolean;
105
+ securityLevel?: number | null;
106
+ securityLevelName?: 'SOFTWARE' | 'SECURE_ENCLAVE';
107
+ secureEnclaveFallbackReason?: 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'POLICY_REJECTED' | 'UNKNOWN' | null;
108
+ };
109
+ };
110
+ };
111
+ ```
112
+
113
+ ### Security level semantics
114
+
115
+ - `securityLevel = 1`
116
+ Software-backed key material
117
+ - `securityLevel = 2`
118
+ Hardware-backed key material
119
+ On Android this usually means TEE
120
+ On iOS this means Secure Enclave
121
+ - `securityLevel = 3`
122
+ Android StrongBox-backed key
123
+ - `securityLevel = null`
124
+ No key material available, or the native platform did not report a numeric level
125
+
126
+ ### Fallback semantics
127
+
128
+ - On Android, the library tries StrongBox first when available
129
+ - On iOS, the library tries Secure Enclave first when available
130
+ - Fallback reasons are sanitized enums rather than raw native errors
131
+ - On iOS Simulator, `secureEnclaveFallbackReason` is expected to be `UNAVAILABLE`
132
+
133
+ ## Notes
134
+
135
+ - Default alias: `react-native-dpop`
136
+ - `htm` is normalized to uppercase
137
+ - `ath` is derived from `accessToken` when provided
138
+ - `jti` and `iat` are auto-generated when omitted
139
+ - For React Native 0.75 on Android, the library ensures `iat` is sent as a number to avoid an older bridge nullability issue with `Double`
140
+
141
+ ## Example apps
142
+
143
+ This repository includes two example apps:
144
+
145
+ - `examples/v0.75`
146
+ - `examples/v0.83`
147
+
148
+ The root `example` script points to `examples/v0.83`.
149
+
150
+ ## Errors
151
+
152
+ Native rejections use codes such as:
86
153
 
87
154
  - `ERR_DPOP_GENERATE_PROOF`
88
155
  - `ERR_DPOP_CALCULATE_THUMBPRINT`
@@ -95,23 +162,6 @@ Native errors are rejected with codes such as:
95
162
  - `ERR_DPOP_ASSERT_HARDWARE_BACKED`
96
163
  - `ERR_DPOP_IS_BOUND_TO_ALIAS`
97
164
 
98
- ## Notes
99
-
100
- - If no alias is provided, the default alias is `react-native-dpop`.
101
- - `getKeyInfo` returns cross-platform fields and platform-specific details in `hardware`:
102
- - Android: `hardware.android.strongBoxAvailable`, `hardware.android.strongBoxBacked`, `hardware.android.securityLevel`, `hardware.android.strongBoxFallbackReason`
103
- - iOS: `hardware.ios.secureEnclaveAvailable`, `hardware.ios.secureEnclaveBacked`, `hardware.ios.securityLevel`, `hardware.ios.secureEnclaveFallbackReason`
104
- - Fallback reasons are sanitized enums (no raw native error): `UNAVAILABLE`, `PROVIDER_ERROR`, `POLICY_REJECTED`, `UNKNOWN`.
105
- - `securityLevel` semantics:
106
- - `null`: no key material available (or not reported)
107
- - `1`: not backed by secure enclave/strong dedicated hardware
108
- - `2`: hardware-backed (iOS Secure Enclave, Android typically TEE)
109
- - `3`: Android-only StrongBox (when reported by the device)
110
- - On iOS, `securityLevel` is normalized by this library (`2` for Secure Enclave-backed keys, `1` for Keychain fallback), not a native Apple numeric level API.
111
- - `htm` is normalized to uppercase in proof generation.
112
- - `ath` is derived from `accessToken` (`SHA-256`, base64url) when provided.
113
- - `jti` and `iat` are auto-generated when omitted.
114
-
115
165
  ## Contributing
116
166
 
117
167
  - [Development workflow](CONTRIBUTING.md#development-workflow)
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
11
11
  s.license = package["license"]
12
12
  s.authors = package["author"]
13
13
 
14
- s.platforms = { :ios => min_ios_version_supported }
14
+ s.platforms = { :ios => "14.0" }
15
15
  s.source = { :git => "https://github.com/Cirilord/react-native-dpop.git", :tag => "#{s.version}" }
16
16
 
17
17
  s.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
@@ -28,6 +28,7 @@ internal data class KeyStoreKeyInfo(
28
28
  val curve: String,
29
29
  val insideSecureHardware: Boolean,
30
30
  val securityLevel: Int?,
31
+ val securityLevelName: String,
31
32
  val strongBoxAvailable: Boolean,
32
33
  val strongBoxBacked: Boolean
33
34
  )
@@ -119,6 +120,7 @@ internal class DPoPKeyStore(private val context: Context) {
119
120
  curve = "P-256",
120
121
  insideSecureHardware = keyInfo.isInsideSecureHardware,
121
122
  securityLevel = readSecurityLevel(keyInfo),
123
+ securityLevelName = readSecurityLevelName(keyInfo),
122
124
  strongBoxAvailable = isStrongBoxEnabled(),
123
125
  strongBoxBacked = readStrongBoxBacked(keyInfo)
124
126
  )
@@ -172,6 +174,24 @@ internal class DPoPKeyStore(private val context: Context) {
172
174
  }
173
175
  }
174
176
 
177
+ private fun readSecurityLevelName(keyInfo: KeyInfo): String {
178
+ val strongBoxBacked = readStrongBoxBacked(keyInfo)
179
+ val securityLevel = readSecurityLevel(keyInfo)
180
+
181
+ return when (securityLevel) {
182
+ 1 -> "SOFTWARE"
183
+ 2 -> "TRUSTED_ENVIRONMENT"
184
+ 3 -> "STRONGBOX"
185
+ else -> {
186
+ when {
187
+ strongBoxBacked -> "STRONGBOX"
188
+ keyInfo.isInsideSecureHardware -> "TRUSTED_ENVIRONMENT"
189
+ else -> "SOFTWARE"
190
+ }
191
+ }
192
+ }
193
+ }
194
+
175
195
  private fun readStrongBoxBacked(keyInfo: KeyInfo): Boolean {
176
196
  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
177
197
  return false
@@ -12,10 +12,32 @@ class DPoPModule(reactContext: ReactApplicationContext) :
12
12
  NativeReactNativeDPoPSpec(reactContext) {
13
13
  private val keyStore = DPoPKeyStore(reactContext)
14
14
 
15
+ companion object {
16
+ private const val DEFAULT_ALIAS = "react-native-dpop"
17
+ const val NAME = NativeReactNativeDPoPSpec.NAME
18
+ private const val UNKNOWN_STRONGBOX_FALLBACK_REASON = "UNKNOWN"
19
+ }
20
+
15
21
  private fun resolveAlias(alias: String?): String {
16
22
  return alias ?: DEFAULT_ALIAS
17
23
  }
18
24
 
25
+ private fun resolveStrongBoxFallbackReason(
26
+ strongBoxAvailable: Boolean,
27
+ strongBoxBacked: Boolean,
28
+ fallbackReason: String?
29
+ ): String? {
30
+ if (fallbackReason != null) {
31
+ return fallbackReason
32
+ }
33
+
34
+ return if (strongBoxAvailable && !strongBoxBacked) {
35
+ UNKNOWN_STRONGBOX_FALLBACK_REASON
36
+ } else {
37
+ null
38
+ }
39
+ }
40
+
19
41
  override fun assertHardwareBacked(alias: String?, promise: Promise) {
20
42
  try {
21
43
  val effectiveAlias = resolveAlias(alias)
@@ -70,9 +92,14 @@ class DPoPModule(reactContext: ReactApplicationContext) :
70
92
  try {
71
93
  val effectiveAlias = resolveAlias(alias)
72
94
  if (!keyStore.hasKeyPair(effectiveAlias)) {
73
- val fallbackReason = keyStore.getStrongBoxFallbackReason(effectiveAlias)
95
+ val strongBoxAvailable = keyStore.isStrongBoxAvailable()
96
+ val fallbackReason = resolveStrongBoxFallbackReason(
97
+ strongBoxAvailable = strongBoxAvailable,
98
+ strongBoxBacked = false,
99
+ fallbackReason = keyStore.getStrongBoxFallbackReason(effectiveAlias)
100
+ )
74
101
  val hardwareAndroid = Arguments.createMap().apply {
75
- putBoolean("strongBoxAvailable", keyStore.isStrongBoxAvailable())
102
+ putBoolean("strongBoxAvailable", strongBoxAvailable)
76
103
  putBoolean("strongBoxBacked", false)
77
104
  if (fallbackReason != null) {
78
105
  putString("strongBoxFallbackReason", fallbackReason)
@@ -93,13 +120,18 @@ class DPoPModule(reactContext: ReactApplicationContext) :
93
120
  }
94
121
 
95
122
  val keyInfo = keyStore.getKeyInfo(effectiveAlias)
96
- val fallbackReason = keyStore.getStrongBoxFallbackReason(effectiveAlias)
123
+ val fallbackReason = resolveStrongBoxFallbackReason(
124
+ strongBoxAvailable = keyInfo.strongBoxAvailable,
125
+ strongBoxBacked = keyInfo.strongBoxBacked,
126
+ fallbackReason = keyStore.getStrongBoxFallbackReason(effectiveAlias)
127
+ )
97
128
  val hardwareAndroid = Arguments.createMap().apply {
98
129
  putBoolean("strongBoxAvailable", keyInfo.strongBoxAvailable)
99
130
  putBoolean("strongBoxBacked", keyInfo.strongBoxBacked)
100
131
  if (keyInfo.securityLevel != null) {
101
132
  putInt("securityLevel", keyInfo.securityLevel)
102
133
  }
134
+ putString("securityLevelName", keyInfo.securityLevelName)
103
135
  if (fallbackReason != null) {
104
136
  putString("strongBoxFallbackReason", fallbackReason)
105
137
  } else {
@@ -320,9 +352,4 @@ class DPoPModule(reactContext: ReactApplicationContext) :
320
352
  promise.reject("ERR_DPOP_GENERATE_PROOF", e.message, e)
321
353
  }
322
354
  }
323
-
324
- companion object {
325
- private const val DEFAULT_ALIAS = "react-native-dpop"
326
- const val NAME = NativeReactNativeDPoPSpec.NAME
327
- }
328
355
  }
@@ -5,7 +5,6 @@ import com.facebook.react.bridge.NativeModule
5
5
  import com.facebook.react.bridge.ReactApplicationContext
6
6
  import com.facebook.react.module.model.ReactModuleInfo
7
7
  import com.facebook.react.module.model.ReactModuleInfoProvider
8
- import java.util.HashMap
9
8
 
10
9
  class DPoPPackage : BaseReactPackage() {
11
10
  override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
@@ -19,12 +18,13 @@ class DPoPPackage : BaseReactPackage() {
19
18
  override fun getReactModuleInfoProvider() = ReactModuleInfoProvider {
20
19
  mapOf(
21
20
  DPoPModule.NAME to ReactModuleInfo(
22
- name = DPoPModule.NAME,
23
- className = DPoPModule.NAME,
24
- canOverrideExistingModule = false,
25
- needsEagerInit = false,
26
- isCxxModule = false,
27
- isTurboModule = true
21
+ DPoPModule.NAME,
22
+ DPoPModule::class.java.name,
23
+ false,
24
+ false,
25
+ false,
26
+ false,
27
+ true
28
28
  )
29
29
  )
30
30
  }
@@ -19,6 +19,7 @@ final class DPoPKeyStore {
19
19
  private let keychain = KeychainKeyStore()
20
20
  private let fallbackReasonDefaults = UserDefaults.standard
21
21
  private let fallbackReasonPrefix = "react_native_dpop_secure_enclave_fallback_reason_"
22
+ private let unavailableFallbackReason = "UNAVAILABLE"
22
23
  private lazy var secureEnclaveAvailable = secureEnclave.isAvailable()
23
24
 
24
25
  func generateKeyPair(alias: String) throws {
@@ -100,7 +101,15 @@ final class DPoPKeyStore {
100
101
  }
101
102
 
102
103
  func getSecureEnclaveFallbackReason(alias: String) -> String? {
103
- fallbackReasonDefaults.string(forKey: fallbackReasonKey(alias: alias))
104
+ if !secureEnclaveAvailable && keychain.hasKeyPair(alias: alias) {
105
+ return unavailableFallbackReason
106
+ }
107
+
108
+ if let storedReason = fallbackReasonDefaults.string(forKey: fallbackReasonKey(alias: alias)) {
109
+ return storedReason
110
+ }
111
+
112
+ return nil
104
113
  }
105
114
 
106
115
  private func storeSecureEnclaveFallbackReason(alias: String, reason: String) {
@@ -7,6 +7,8 @@ final class DPoPModule {
7
7
 
8
8
  private let keyStore = DPoPKeyStore()
9
9
  private let defaultAlias = "react-native-dpop"
10
+ private let unknownSecureEnclaveFallbackReason = "UNKNOWN"
11
+ private let unavailableSecureEnclaveFallbackReason = "UNAVAILABLE"
10
12
 
11
13
  private init() {}
12
14
 
@@ -45,9 +47,15 @@ final class DPoPModule {
45
47
  func getKeyInfo(alias: String?) -> [String: Any] {
46
48
  let effectiveAlias = resolveAlias(alias)
47
49
  let secureEnclaveAvailable = keyStore.isSecureEnclaveAvailable()
48
- let fallbackReason = keyStore.getSecureEnclaveFallbackReason(alias: effectiveAlias)
49
- let secureEnclaveFallbackReason: Any = fallbackReason ?? NSNull()
50
50
  let keyInfo = keyStore.getKeyInfo(alias: effectiveAlias)
51
+ let secureEnclaveBacked = secureEnclaveAvailable && keyInfo.insideSecureHardware
52
+ let fallbackReason = resolveSecureEnclaveFallbackReason(
53
+ secureEnclaveAvailable: secureEnclaveAvailable,
54
+ secureEnclaveBacked: secureEnclaveBacked,
55
+ hasKeyPair: keyInfo.hasKeyPair,
56
+ fallbackReason: keyStore.getSecureEnclaveFallbackReason(alias: effectiveAlias)
57
+ )
58
+ let secureEnclaveFallbackReason: Any = fallbackReason ?? NSNull()
51
59
 
52
60
  if !keyInfo.hasKeyPair {
53
61
  return [
@@ -58,14 +66,15 @@ final class DPoPModule {
58
66
  "secureEnclaveAvailable": secureEnclaveAvailable,
59
67
  "secureEnclaveBacked": false,
60
68
  "securityLevel": NSNull(),
69
+ "securityLevelName": "SOFTWARE",
61
70
  "secureEnclaveFallbackReason": secureEnclaveFallbackReason
62
71
  ]
63
72
  ]
64
73
  ]
65
74
  }
66
75
 
67
- let secureEnclaveBacked = secureEnclaveAvailable && keyInfo.insideSecureHardware
68
76
  let securityLevel = secureEnclaveBacked ? 2 : 1
77
+ let securityLevelName = secureEnclaveBacked ? "SECURE_ENCLAVE" : "SOFTWARE"
69
78
 
70
79
  return [
71
80
  "alias": keyInfo.alias,
@@ -78,12 +87,34 @@ final class DPoPModule {
78
87
  "secureEnclaveAvailable": secureEnclaveAvailable,
79
88
  "secureEnclaveBacked": secureEnclaveBacked,
80
89
  "securityLevel": securityLevel,
90
+ "securityLevelName": securityLevelName,
81
91
  "secureEnclaveFallbackReason": secureEnclaveFallbackReason
82
92
  ]
83
93
  ]
84
94
  ]
85
95
  }
86
96
 
97
+ private func resolveSecureEnclaveFallbackReason(
98
+ secureEnclaveAvailable: Bool,
99
+ secureEnclaveBacked: Bool,
100
+ hasKeyPair: Bool,
101
+ fallbackReason: String?
102
+ ) -> String? {
103
+ if let fallbackReason {
104
+ return fallbackReason
105
+ }
106
+
107
+ if hasKeyPair && !secureEnclaveAvailable {
108
+ return unavailableSecureEnclaveFallbackReason
109
+ }
110
+
111
+ if hasKeyPair && !secureEnclaveBacked {
112
+ return unknownSecureEnclaveFallbackReason
113
+ }
114
+
115
+ return nil
116
+ }
117
+
87
118
  func getPublicKeyDer(alias: String?) throws -> String {
88
119
  let effectiveAlias = resolveAlias(alias)
89
120
  if !keyStore.hasKeyPair(alias: effectiveAlias) {
@@ -347,12 +378,19 @@ final class DPoPModule {
347
378
  additional: [String: Any]?,
348
379
  kid: String?,
349
380
  jti: String?,
350
- iat: NSNumber?,
381
+ iat: Any?,
351
382
  alias: String?,
352
383
  resolve: @escaping RCTPromiseResolveBlock,
353
384
  reject: @escaping RCTPromiseRejectBlock
354
385
  ) {
355
386
  do {
387
+ let normalizedIat: NSNumber?
388
+ if iat is NSNull {
389
+ normalizedIat = nil
390
+ } else {
391
+ normalizedIat = iat as? NSNumber
392
+ }
393
+
356
394
  resolve(
357
395
  try DPoPModule.shared.generateProof(
358
396
  htu: htu,
@@ -362,7 +400,7 @@ final class DPoPModule {
362
400
  additional: additional,
363
401
  kid: kid,
364
402
  jti: jti,
365
- iat: iat,
403
+ iat: normalizedIat,
366
404
  alias: alias
367
405
  )
368
406
  )
@@ -70,7 +70,7 @@ RCT_EXTERN_METHOD(generateProof:(NSString *)htu
70
70
  additional:(NSDictionary * _Nullable)additional
71
71
  kid:(NSString * _Nullable)kid
72
72
  jti:(NSString * _Nullable)jti
73
- iat:(NSNumber * _Nullable)iat
73
+ iat:(id _Nullable)iat
74
74
  alias:(NSString * _Nullable)alias
75
75
  resolve:(RCTPromiseResolveBlock)resolve
76
76
  reject:(RCTPromiseRejectBlock)reject)
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
 
3
3
  import { NativeModules, TurboModuleRegistry } from 'react-native';
4
- const nativeDpopModule = TurboModuleRegistry.get('ReactNativeDPoP') ?? NativeModules.ReactNativeDPoP;
4
+ const nativeDpopModule =
5
+ // eslint-disable-next-line dot-notation -- required by noPropertyAccessFromIndexSignature from @tsconfig/strictest
6
+ TurboModuleRegistry.get('ReactNativeDPoP') ?? NativeModules['ReactNativeDPoP'];
5
7
  export default nativeDpopModule;
6
8
  //# sourceMappingURL=NativeReactNativeDPoP.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["NativeModules","TurboModuleRegistry","nativeDpopModule","get","ReactNativeDPoP"],"sourceRoot":"../../src","sources":["NativeReactNativeDPoP.ts"],"mappings":";;AACA,SAASA,aAAa,EAAEC,mBAAmB,QAAQ,cAAc;AA4BjE,MAAMC,gBAAgB,GACpBD,mBAAmB,CAACE,GAAG,CAAO,iBAAiB,CAAC,IAAKH,aAAa,CAACI,eAAoC;AAEzG,eAAeF,gBAAgB","ignoreList":[]}
1
+ {"version":3,"names":["NativeModules","TurboModuleRegistry","nativeDpopModule","get"],"sourceRoot":"../../src","sources":["NativeReactNativeDPoP.ts"],"mappings":";;AACA,SAASA,aAAa,EAAEC,mBAAmB,QAAQ,cAAc;AA4BjE,MAAMC,gBAAgB;AACpB;AACAD,mBAAmB,CAACE,GAAG,CAAO,iBAAiB,CAAC,IAAKH,aAAa,CAAC,iBAAiB,CAAsB;AAE5G,eAAeE,gBAAgB","ignoreList":[]}
@@ -26,7 +26,9 @@ export class DPoP {
26
26
  return NativeReactNativeDPoP.isBoundToAlias(this.proof, alias ?? this.alias ?? null);
27
27
  }
28
28
  static async generateProof(input) {
29
- const result = await NativeReactNativeDPoP.generateProof(input.htu, input.htm, input.nonce ?? null, input.accessToken ?? null, input.additional ?? null, input.kid ?? null, input.jti ?? null, input.iat ?? null, input.alias ?? null);
29
+ const result = await NativeReactNativeDPoP.generateProof(input.htu, input.htm, input.nonce ?? null, input.accessToken ?? null, input.additional ?? null, input.kid ?? null, input.jti ?? null,
30
+ // RN 0.75 Android bridge can crash when a nullable Double arrives as null.
31
+ input.iat ?? Math.floor(Date.now() / 1000), input.alias ?? null);
30
32
  return new DPoP(result.proof, result.proofContext, input.alias);
31
33
  }
32
34
  static async assertHardwareBacked(alias) {
@@ -1 +1 @@
1
- {"version":3,"names":["NativeReactNativeDPoP","DPoP","constructor","proof","proofContext","alias","calculateThumbprint","getPublicKey","format","getPublicKeyDer","getPublicKeyRaw","getPublicKeyJwk","signWithDpopPrivateKey","payload","isBoundToAlias","generateProof","input","result","htu","htm","nonce","accessToken","additional","kid","jti","iat","assertHardwareBacked","deleteKeyPair","getKeyInfo","hasKeyPair","rotateKeyPair"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,qBAAqB,MAAM,4BAAyB;AAiE3D,OAAO,MAAMC,IAAI,CAAC;EAKRC,WAAWA,CAACC,KAAa,EAAEC,YAA8B,EAAEC,KAAc,EAAE;IACjF,IAAI,CAACF,KAAK,GAAGA,KAAK;IAClB,IAAI,CAACC,YAAY,GAAGA,YAAY;IAChC,IAAI,CAACC,KAAK,GAAGA,KAAK;EACpB;EAEA,MAAaC,mBAAmBA,CAAA,EAAoB;IAClD,OAAON,qBAAqB,CAACM,mBAAmB,CAAC,IAAI,CAACD,KAAK,IAAI,IAAI,CAAC;EACtE;EAEA,MAAaE,YAAYA,CAACC,MAAuB,EAA+B;IAC9E,IAAIA,MAAM,KAAK,KAAK,EAAE;MACpB,OAAOR,qBAAqB,CAACS,eAAe,CAAC,IAAI,CAACJ,KAAK,IAAI,IAAI,CAAC;IAClE;IACA,IAAIG,MAAM,KAAK,KAAK,EAAE;MACpB,OAAOR,qBAAqB,CAACU,eAAe,CAAC,IAAI,CAACL,KAAK,IAAI,IAAI,CAAC;IAClE;IAEA,OAAOL,qBAAqB,CAACW,eAAe,CAAC,IAAI,CAACN,KAAK,IAAI,IAAI,CAAC;EAClE;EAEA,MAAaO,sBAAsBA,CAACC,OAAe,EAAmB;IACpE,OAAOb,qBAAqB,CAACY,sBAAsB,CAACC,OAAO,EAAE,IAAI,CAACR,KAAK,IAAI,IAAI,CAAC;EAClF;EAEA,MAAaS,cAAcA,CAACT,KAAc,EAAoB;IAC5D,OAAOL,qBAAqB,CAACc,cAAc,CAAC,IAAI,CAACX,KAAK,EAAEE,KAAK,IAAI,IAAI,CAACA,KAAK,IAAI,IAAI,CAAC;EACtF;EAEA,aAAoBU,aAAaA,CAACC,KAAyB,EAAiB;IAC1E,MAAMC,MAAM,GAAI,MAAMjB,qBAAqB,CAACe,aAAa,CACvDC,KAAK,CAACE,GAAG,EACTF,KAAK,CAACG,GAAG,EACTH,KAAK,CAACI,KAAK,IAAI,IAAI,EACnBJ,KAAK,CAACK,WAAW,IAAI,IAAI,EACzBL,KAAK,CAACM,UAAU,IAAI,IAAI,EACxBN,KAAK,CAACO,GAAG,IAAI,IAAI,EACjBP,KAAK,CAACQ,GAAG,IAAI,IAAI,EACjBR,KAAK,CAACS,GAAG,IAAI,IAAI,EACjBT,KAAK,CAACX,KAAK,IAAI,IACjB,CAAyB;IAEzB,OAAO,IAAIJ,IAAI,CAACgB,MAAM,CAACd,KAAK,EAAEc,MAAM,CAACb,YAAY,EAAEY,KAAK,CAACX,KAAK,CAAC;EACjE;EAEA,aAAoBqB,oBAAoBA,CAACrB,KAAc,EAAiB;IACtE,MAAML,qBAAqB,CAAC0B,oBAAoB,CAACrB,KAAK,IAAI,IAAI,CAAC;EACjE;EAEA,aAAoBsB,aAAaA,CAACtB,KAAc,EAAiB;IAC/D,MAAML,qBAAqB,CAAC2B,aAAa,CAACtB,KAAK,IAAI,IAAI,CAAC;EAC1D;EAEA,aAAoBuB,UAAUA,CAACvB,KAAc,EAAwB;IACnE,OAAOL,qBAAqB,CAAC4B,UAAU,CAACvB,KAAK,IAAI,IAAI,CAAC;EACxD;EAEA,aAAoBwB,UAAUA,CAACxB,KAAc,EAAoB;IAC/D,OAAOL,qBAAqB,CAAC6B,UAAU,CAACxB,KAAK,IAAI,IAAI,CAAC;EACxD;EAEA,aAAoByB,aAAaA,CAACzB,KAAc,EAAiB;IAC/D,MAAML,qBAAqB,CAAC8B,aAAa,CAACzB,KAAK,IAAI,IAAI,CAAC;EAC1D;AACF","ignoreList":[]}
1
+ {"version":3,"names":["NativeReactNativeDPoP","DPoP","constructor","proof","proofContext","alias","calculateThumbprint","getPublicKey","format","getPublicKeyDer","getPublicKeyRaw","getPublicKeyJwk","signWithDpopPrivateKey","payload","isBoundToAlias","generateProof","input","result","htu","htm","nonce","accessToken","additional","kid","jti","iat","Math","floor","Date","now","assertHardwareBacked","deleteKeyPair","getKeyInfo","hasKeyPair","rotateKeyPair"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,qBAAqB,MAAM,4BAAyB;AAqE3D,OAAO,MAAMC,IAAI,CAAC;EAKRC,WAAWA,CAACC,KAAa,EAAEC,YAA8B,EAAEC,KAAc,EAAE;IACjF,IAAI,CAACF,KAAK,GAAGA,KAAK;IAClB,IAAI,CAACC,YAAY,GAAGA,YAAY;IAChC,IAAI,CAACC,KAAK,GAAGA,KAAK;EACpB;EAEA,MAAaC,mBAAmBA,CAAA,EAAoB;IAClD,OAAON,qBAAqB,CAACM,mBAAmB,CAAC,IAAI,CAACD,KAAK,IAAI,IAAI,CAAC;EACtE;EAEA,MAAaE,YAAYA,CAACC,MAAuB,EAA+B;IAC9E,IAAIA,MAAM,KAAK,KAAK,EAAE;MACpB,OAAOR,qBAAqB,CAACS,eAAe,CAAC,IAAI,CAACJ,KAAK,IAAI,IAAI,CAAC;IAClE;IACA,IAAIG,MAAM,KAAK,KAAK,EAAE;MACpB,OAAOR,qBAAqB,CAACU,eAAe,CAAC,IAAI,CAACL,KAAK,IAAI,IAAI,CAAC;IAClE;IAEA,OAAOL,qBAAqB,CAACW,eAAe,CAAC,IAAI,CAACN,KAAK,IAAI,IAAI,CAAC;EAClE;EAEA,MAAaO,sBAAsBA,CAACC,OAAe,EAAmB;IACpE,OAAOb,qBAAqB,CAACY,sBAAsB,CAACC,OAAO,EAAE,IAAI,CAACR,KAAK,IAAI,IAAI,CAAC;EAClF;EAEA,MAAaS,cAAcA,CAACT,KAAc,EAAoB;IAC5D,OAAOL,qBAAqB,CAACc,cAAc,CAAC,IAAI,CAACX,KAAK,EAAEE,KAAK,IAAI,IAAI,CAACA,KAAK,IAAI,IAAI,CAAC;EACtF;EAEA,aAAoBU,aAAaA,CAACC,KAAyB,EAAiB;IAC1E,MAAMC,MAAM,GAAI,MAAMjB,qBAAqB,CAACe,aAAa,CACvDC,KAAK,CAACE,GAAG,EACTF,KAAK,CAACG,GAAG,EACTH,KAAK,CAACI,KAAK,IAAI,IAAI,EACnBJ,KAAK,CAACK,WAAW,IAAI,IAAI,EACzBL,KAAK,CAACM,UAAU,IAAI,IAAI,EACxBN,KAAK,CAACO,GAAG,IAAI,IAAI,EACjBP,KAAK,CAACQ,GAAG,IAAI,IAAI;IACjB;IACAR,KAAK,CAACS,GAAG,IAAIC,IAAI,CAACC,KAAK,CAACC,IAAI,CAACC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAC1Cb,KAAK,CAACX,KAAK,IAAI,IACjB,CAAyB;IAEzB,OAAO,IAAIJ,IAAI,CAACgB,MAAM,CAACd,KAAK,EAAEc,MAAM,CAACb,YAAY,EAAEY,KAAK,CAACX,KAAK,CAAC;EACjE;EAEA,aAAoByB,oBAAoBA,CAACzB,KAAc,EAAiB;IACtE,MAAML,qBAAqB,CAAC8B,oBAAoB,CAACzB,KAAK,IAAI,IAAI,CAAC;EACjE;EAEA,aAAoB0B,aAAaA,CAAC1B,KAAc,EAAiB;IAC/D,MAAML,qBAAqB,CAAC+B,aAAa,CAAC1B,KAAK,IAAI,IAAI,CAAC;EAC1D;EAEA,aAAoB2B,UAAUA,CAAC3B,KAAc,EAAwB;IACnE,OAAOL,qBAAqB,CAACgC,UAAU,CAAC3B,KAAK,IAAI,IAAI,CAAC;EACxD;EAEA,aAAoB4B,UAAUA,CAAC5B,KAAc,EAAoB;IAC/D,OAAOL,qBAAqB,CAACiC,UAAU,CAAC5B,KAAK,IAAI,IAAI,CAAC;EACxD;EAEA,aAAoB6B,aAAaA,CAAC7B,KAAc,EAAiB;IAC/D,MAAML,qBAAqB,CAACkC,aAAa,CAAC7B,KAAK,IAAI,IAAI,CAAC;EAC1D;AACF","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ export default function DPoPExampleContent(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=DPoPExampleContent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DPoPExampleContent.d.ts","sourceRoot":"","sources":["../../../../examples/shared/DPoPExampleContent.tsx"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,kBAAkB,4CA0BzC"}
@@ -0,0 +1,2 @@
1
+ export default function App(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=App.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../examples/v0.75/App.tsx"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,GAAG,4CAM1B"}
@@ -0,0 +1,2 @@
1
+ export default function App(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=App.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../examples/v0.83/App.tsx"],"names":[],"mappings":"AAKA,MAAM,CAAC,OAAO,UAAU,GAAG,4CAM1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"NativeReactNativeDPoP.d.ts","sourceRoot":"","sources":["../../../src/NativeReactNativeDPoP.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AAE9E,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3D,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACxD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7D,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/E,aAAa,CACX,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,UAAU,EAAE,YAAY,GAAG,IAAI,EAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1B;wBAKkC,IAAI;AAAvC,wBAAwC"}
1
+ {"version":3,"file":"NativeReactNativeDPoP.d.ts","sourceRoot":"","sources":["../../../src/NativeReactNativeDPoP.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AAE9E,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3D,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACxD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7D,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/E,aAAa,CACX,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,UAAU,EAAE,YAAY,GAAG,IAAI,EAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1B;wBAMkC,IAAI;AAAvC,wBAAwC"}
@@ -7,6 +7,8 @@ export type PublicJwk = {
7
7
  };
8
8
  export type PublicKeyFormat = 'JWK' | 'DER' | 'RAW';
9
9
  export type SecureHardwareFallbackReason = 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'POLICY_REJECTED' | 'UNKNOWN';
10
+ export type AndroidSecurityLevelName = 'SOFTWARE' | 'TRUSTED_ENVIRONMENT' | 'STRONGBOX';
11
+ export type IOSSecurityLevelName = 'SOFTWARE' | 'SECURE_ENCLAVE';
10
12
  export type DPoPKeyInfo = {
11
13
  alias: string;
12
14
  hasKeyPair: boolean;
@@ -18,12 +20,14 @@ export type DPoPKeyInfo = {
18
20
  strongBoxAvailable: boolean;
19
21
  strongBoxBacked: boolean;
20
22
  securityLevel?: number;
23
+ securityLevelName?: AndroidSecurityLevelName;
21
24
  strongBoxFallbackReason?: SecureHardwareFallbackReason | null;
22
25
  };
23
26
  ios?: {
24
27
  secureEnclaveAvailable: boolean;
25
28
  secureEnclaveBacked: boolean;
26
29
  securityLevel?: number | null;
30
+ securityLevelName?: IOSSecurityLevelName;
27
31
  secureEnclaveFallbackReason?: SecureHardwareFallbackReason | null;
28
32
  };
29
33
  };
@@ -51,7 +55,7 @@ export type DPoPProofContext = {
51
55
  };
52
56
  export declare class DPoP {
53
57
  readonly proof: string;
54
- readonly alias?: string;
58
+ readonly alias: string | undefined;
55
59
  readonly proofContext: DPoPProofContext;
56
60
  private constructor();
57
61
  calculateThumbprint(): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-dpop",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "React Native library for DPoP proof generation and key management.",
5
5
  "keywords": [
6
6
  "android",
@@ -18,6 +18,7 @@
18
18
  "license": "MIT",
19
19
  "author": "Pedro Cirilo <phscirilo123@gmail.com> (https://github.com/Cirilord)",
20
20
  "main": "./lib/module/index.js",
21
+ "react-native": "./src/index.tsx",
21
22
  "types": "./lib/typescript/src/index.d.ts",
22
23
  "exports": {
23
24
  ".": {
@@ -47,8 +48,8 @@
47
48
  "!**/.*"
48
49
  ],
49
50
  "scripts": {
50
- "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
51
- "example": "yarn workspace react-native-dpop-example",
51
+ "clean": "del-cli android/build examples/v0.83/android/build examples/v0.83/android/app/build examples/v0.83/ios/build lib",
52
+ "example": "yarn workspace react-native-dpop-example-v0.83",
52
53
  "lint": "eslint \"**/*.{js,ts,tsx}\"",
53
54
  "prepare": "bob build",
54
55
  "release": "release-it",
@@ -71,12 +72,14 @@
71
72
  "@react-native/babel-preset": "0.83.0",
72
73
  "@react-native/eslint-config": "0.83.0",
73
74
  "@release-it/conventional-changelog": "^10.0.1",
75
+ "@tsconfig/strictest": "^2.0.8",
74
76
  "@types/jest": "^29.5.14",
75
77
  "@types/react": "^19.2.0",
76
78
  "commitlint": "^19.8.1",
77
79
  "del-cli": "^6.0.0",
78
80
  "eslint": "^9.35.0",
79
81
  "eslint-config-prettier": "^10.1.8",
82
+ "eslint-plugin-import": "^2.32.0",
80
83
  "eslint-plugin-prettier": "^5.5.4",
81
84
  "jest": "^29.7.0",
82
85
  "lefthook": "^2.0.3",
@@ -89,7 +92,8 @@
89
92
  "typescript": "^5.9.2"
90
93
  },
91
94
  "workspaces": [
92
- "example"
95
+ "examples/v0.75",
96
+ "examples/v0.83"
93
97
  ],
94
98
  "packageManager": "yarn@4.11.0",
95
99
  "react-native-builder-bob": {
@@ -28,6 +28,7 @@ export interface Spec extends TurboModule {
28
28
  }
29
29
 
30
30
  const nativeDpopModule =
31
- TurboModuleRegistry.get<Spec>('ReactNativeDPoP') ?? (NativeModules.ReactNativeDPoP as Spec | undefined);
31
+ // eslint-disable-next-line dot-notation -- required by noPropertyAccessFromIndexSignature from @tsconfig/strictest
32
+ TurboModuleRegistry.get<Spec>('ReactNativeDPoP') ?? (NativeModules['ReactNativeDPoP'] as Spec | undefined);
32
33
 
33
34
  export default nativeDpopModule as Spec;
package/src/index.tsx CHANGED
@@ -12,6 +12,8 @@ export type PublicJwk = {
12
12
  export type PublicKeyFormat = 'JWK' | 'DER' | 'RAW';
13
13
 
14
14
  export type SecureHardwareFallbackReason = 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'POLICY_REJECTED' | 'UNKNOWN';
15
+ export type AndroidSecurityLevelName = 'SOFTWARE' | 'TRUSTED_ENVIRONMENT' | 'STRONGBOX';
16
+ export type IOSSecurityLevelName = 'SOFTWARE' | 'SECURE_ENCLAVE';
15
17
 
16
18
  export type DPoPKeyInfo = {
17
19
  alias: string;
@@ -24,12 +26,14 @@ export type DPoPKeyInfo = {
24
26
  strongBoxAvailable: boolean;
25
27
  strongBoxBacked: boolean;
26
28
  securityLevel?: number;
29
+ securityLevelName?: AndroidSecurityLevelName;
27
30
  strongBoxFallbackReason?: SecureHardwareFallbackReason | null;
28
31
  };
29
32
  ios?: {
30
33
  secureEnclaveAvailable: boolean;
31
34
  secureEnclaveBacked: boolean;
32
35
  securityLevel?: number | null;
36
+ securityLevelName?: IOSSecurityLevelName;
33
37
  secureEnclaveFallbackReason?: SecureHardwareFallbackReason | null;
34
38
  };
35
39
  };
@@ -65,7 +69,7 @@ type GenerateProofResult = {
65
69
 
66
70
  export class DPoP {
67
71
  public readonly proof: string;
68
- public readonly alias?: string;
72
+ public readonly alias: string | undefined;
69
73
  public readonly proofContext: DPoPProofContext;
70
74
 
71
75
  private constructor(proof: string, proofContext: DPoPProofContext, alias?: string) {
@@ -106,7 +110,8 @@ export class DPoP {
106
110
  input.additional ?? null,
107
111
  input.kid ?? null,
108
112
  input.jti ?? null,
109
- input.iat ?? null,
113
+ // RN 0.75 Android bridge can crash when a nullable Double arrives as null.
114
+ input.iat ?? Math.floor(Date.now() / 1000),
110
115
  input.alias ?? null
111
116
  )) as GenerateProofResult;
112
117