react-native-dpop 0.2.0 → 0.3.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
@@ -54,6 +54,7 @@ const isBound = await dpop.isBoundToAlias();
54
54
  - `GenerateProofInput`
55
55
  - `DPoPProofContext`
56
56
  - `DPoPKeyInfo`
57
+ - `SecureHardwareFallbackReason = 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'POLICY_REJECTED' | 'UNKNOWN'`
57
58
  - `PublicJwk`
58
59
  - `PublicKeyFormat = 'JWK' | 'DER' | 'RAW'`
59
60
 
@@ -97,6 +98,16 @@ Native errors are rejected with codes such as:
97
98
  ## Notes
98
99
 
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.
100
111
  - `htm` is normalized to uppercase in proof generation.
101
112
  - `ath` is derived from `accessToken` (`SHA-256`, base64url) when provided.
102
113
  - `jti` and `iat` are auto-generated when omitted.
@@ -36,6 +36,14 @@ internal class DPoPKeyStore(private val context: Context) {
36
36
  companion object {
37
37
  private const val KEYSTORE_PROVIDER = "AndroidKeyStore"
38
38
  private const val EC_CURVE = "secp256r1"
39
+ private const val META_PREFS = "react_native_dpop_keystore_meta"
40
+ private const val META_STRONGBOX_FALLBACK_PREFIX = "strongbox_fallback_reason_"
41
+ private const val REASON_UNAVAILABLE = "UNAVAILABLE"
42
+ private const val REASON_PROVIDER_ERROR = "PROVIDER_ERROR"
43
+ }
44
+
45
+ private val metadataPrefs by lazy {
46
+ context.getSharedPreferences(META_PREFS, Context.MODE_PRIVATE)
39
47
  }
40
48
 
41
49
  private val keyStore: KeyStore by lazy {
@@ -46,6 +54,7 @@ internal class DPoPKeyStore(private val context: Context) {
46
54
  if (keyStore.containsAlias(alias)) {
47
55
  keyStore.deleteEntry(alias)
48
56
  }
57
+ clearStrongBoxFallbackReason(alias)
49
58
  }
50
59
 
51
60
  fun generateKeyPair(alias: String): Boolean {
@@ -56,16 +65,20 @@ internal class DPoPKeyStore(private val context: Context) {
56
65
  if (keyStore.containsAlias(alias)) {
57
66
  keyStore.deleteEntry(alias)
58
67
  }
68
+ clearStrongBoxFallbackReason(alias)
59
69
 
60
70
  val generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, KEYSTORE_PROVIDER)
61
71
  if (isStrongBoxEnabled()) {
62
72
  try {
63
73
  generator.initialize(buildSpec(alias, useStrongBox = true))
64
74
  generator.generateKeyPair()
75
+ clearStrongBoxFallbackReason(alias)
65
76
  return true
66
77
  } catch (_: StrongBoxUnavailableException) {
78
+ storeStrongBoxFallbackReason(alias, REASON_UNAVAILABLE)
67
79
  // Fallback to hardware-backed keystore when StrongBox is unavailable.
68
80
  } catch (_: ProviderException) {
81
+ storeStrongBoxFallbackReason(alias, REASON_PROVIDER_ERROR)
69
82
  // Some devices expose StrongBox but fail during generation.
70
83
  }
71
84
  }
@@ -89,6 +102,12 @@ internal class DPoPKeyStore(private val context: Context) {
89
102
  return privateKey != null && publicKey != null
90
103
  }
91
104
 
105
+ fun isStrongBoxAvailable(): Boolean = isStrongBoxEnabled()
106
+
107
+ fun getStrongBoxFallbackReason(alias: String): String? {
108
+ return metadataPrefs.getString(strongBoxFallbackKey(alias), null)
109
+ }
110
+
92
111
  fun getKeyInfo(alias: String): KeyStoreKeyInfo {
93
112
  val keyPair = getKeyPair(alias)
94
113
  val keyFactory = KeyFactory.getInstance(keyPair.privateKey.algorithm, KEYSTORE_PROVIDER)
@@ -165,4 +184,14 @@ internal class DPoPKeyStore(private val context: Context) {
165
184
  false
166
185
  }
167
186
  }
187
+
188
+ private fun storeStrongBoxFallbackReason(alias: String, reason: String) {
189
+ metadataPrefs.edit().putString(strongBoxFallbackKey(alias), reason).apply()
190
+ }
191
+
192
+ private fun clearStrongBoxFallbackReason(alias: String) {
193
+ metadataPrefs.edit().remove(strongBoxFallbackKey(alias)).apply()
194
+ }
195
+
196
+ private fun strongBoxFallbackKey(alias: String): String = "$META_STRONGBOX_FALLBACK_PREFIX$alias"
168
197
  }
@@ -70,26 +70,52 @@ class DPoPModule(reactContext: ReactApplicationContext) :
70
70
  try {
71
71
  val effectiveAlias = resolveAlias(alias)
72
72
  if (!keyStore.hasKeyPair(effectiveAlias)) {
73
+ val fallbackReason = keyStore.getStrongBoxFallbackReason(effectiveAlias)
74
+ val hardwareAndroid = Arguments.createMap().apply {
75
+ putBoolean("strongBoxAvailable", keyStore.isStrongBoxAvailable())
76
+ putBoolean("strongBoxBacked", false)
77
+ if (fallbackReason != null) {
78
+ putString("strongBoxFallbackReason", fallbackReason)
79
+ } else {
80
+ putNull("strongBoxFallbackReason")
81
+ }
82
+ }
83
+ val hardware = Arguments.createMap().apply {
84
+ putMap("android", hardwareAndroid)
85
+ }
73
86
  val result = Arguments.createMap().apply {
74
87
  putString("alias", effectiveAlias)
75
88
  putBoolean("hasKeyPair", false)
89
+ putMap("hardware", hardware)
76
90
  }
77
91
  promise.resolve(result)
78
92
  return
79
93
  }
80
94
 
81
95
  val keyInfo = keyStore.getKeyInfo(effectiveAlias)
96
+ val fallbackReason = keyStore.getStrongBoxFallbackReason(effectiveAlias)
97
+ val hardwareAndroid = Arguments.createMap().apply {
98
+ putBoolean("strongBoxAvailable", keyInfo.strongBoxAvailable)
99
+ putBoolean("strongBoxBacked", keyInfo.strongBoxBacked)
100
+ if (keyInfo.securityLevel != null) {
101
+ putInt("securityLevel", keyInfo.securityLevel)
102
+ }
103
+ if (fallbackReason != null) {
104
+ putString("strongBoxFallbackReason", fallbackReason)
105
+ } else {
106
+ putNull("strongBoxFallbackReason")
107
+ }
108
+ }
109
+ val hardware = Arguments.createMap().apply {
110
+ putMap("android", hardwareAndroid)
111
+ }
82
112
  val result = Arguments.createMap().apply {
83
113
  putString("alias", keyInfo.alias)
84
114
  putString("algorithm", keyInfo.algorithm)
85
115
  putString("curve", keyInfo.curve)
86
116
  putBoolean("hasKeyPair", true)
87
117
  putBoolean("insideSecureHardware", keyInfo.insideSecureHardware)
88
- putBoolean("strongBoxAvailable", keyInfo.strongBoxAvailable)
89
- putBoolean("strongBoxBacked", keyInfo.strongBoxBacked)
90
- if (keyInfo.securityLevel != null) {
91
- putInt("securityLevel", keyInfo.securityLevel)
92
- }
118
+ putMap("hardware", hardware)
93
119
  }
94
120
  promise.resolve(result)
95
121
  } catch (e: Exception) {
@@ -12,20 +12,23 @@ struct DPoPKeyInfo {
12
12
  let curve: String
13
13
  let hasKeyPair: Bool
14
14
  let insideSecureHardware: Bool
15
- let strongBoxAvailable: Bool
16
- let strongBoxBacked: Bool
17
15
  }
18
16
 
19
17
  final class DPoPKeyStore {
20
18
  private let secureEnclave = SecureEnclaveKeyStore()
21
19
  private let keychain = KeychainKeyStore()
20
+ private let fallbackReasonDefaults = UserDefaults.standard
21
+ private let fallbackReasonPrefix = "react_native_dpop_secure_enclave_fallback_reason_"
22
+ private lazy var secureEnclaveAvailable = secureEnclave.isAvailable()
22
23
 
23
24
  func generateKeyPair(alias: String) throws {
24
25
  try deleteKeyPair(alias: alias)
25
26
 
26
27
  do {
27
28
  try secureEnclave.generateKeyPair(alias: alias)
29
+ clearSecureEnclaveFallbackReason(alias: alias)
28
30
  } catch {
31
+ storeSecureEnclaveFallbackReason(alias: alias, reason: mapSecureEnclaveFallbackReason(error))
29
32
  try keychain.generateKeyPair(alias: alias)
30
33
  }
31
34
  }
@@ -33,6 +36,7 @@ final class DPoPKeyStore {
33
36
  func deleteKeyPair(alias: String) throws {
34
37
  try secureEnclave.deleteKeyPair(alias: alias)
35
38
  try keychain.deleteKeyPair(alias: alias)
39
+ clearSecureEnclaveFallbackReason(alias: alias)
36
40
  }
37
41
 
38
42
  func hasKeyPair(alias: String) -> Bool {
@@ -64,9 +68,7 @@ final class DPoPKeyStore {
64
68
  algorithm: "EC",
65
69
  curve: "P-256",
66
70
  hasKeyPair: true,
67
- insideSecureHardware: true,
68
- strongBoxAvailable: false,
69
- strongBoxBacked: false
71
+ insideSecureHardware: true
70
72
  )
71
73
  }
72
74
 
@@ -76,9 +78,7 @@ final class DPoPKeyStore {
76
78
  algorithm: "EC",
77
79
  curve: "P-256",
78
80
  hasKeyPair: true,
79
- insideSecureHardware: false,
80
- strongBoxAvailable: false,
81
- strongBoxBacked: false
81
+ insideSecureHardware: false
82
82
  )
83
83
  }
84
84
 
@@ -87,13 +87,48 @@ final class DPoPKeyStore {
87
87
  algorithm: "EC",
88
88
  curve: "P-256",
89
89
  hasKeyPair: false,
90
- insideSecureHardware: false,
91
- strongBoxAvailable: false,
92
- strongBoxBacked: false
90
+ insideSecureHardware: false
93
91
  )
94
92
  }
95
93
 
96
94
  func isHardwareBacked(alias: String) -> Bool {
97
95
  secureEnclave.isHardwareBacked(alias: alias)
98
96
  }
97
+
98
+ func isSecureEnclaveAvailable() -> Bool {
99
+ secureEnclaveAvailable
100
+ }
101
+
102
+ func getSecureEnclaveFallbackReason(alias: String) -> String? {
103
+ fallbackReasonDefaults.string(forKey: fallbackReasonKey(alias: alias))
104
+ }
105
+
106
+ private func storeSecureEnclaveFallbackReason(alias: String, reason: String) {
107
+ fallbackReasonDefaults.set(reason, forKey: fallbackReasonKey(alias: alias))
108
+ }
109
+
110
+ private func clearSecureEnclaveFallbackReason(alias: String) {
111
+ fallbackReasonDefaults.removeObject(forKey: fallbackReasonKey(alias: alias))
112
+ }
113
+
114
+ private func fallbackReasonKey(alias: String) -> String {
115
+ "\(fallbackReasonPrefix)\(alias)"
116
+ }
117
+
118
+ private func mapSecureEnclaveFallbackReason(_ error: Error) -> String {
119
+ let nsError = error as NSError
120
+
121
+ if nsError.domain == NSOSStatusErrorDomain {
122
+ switch nsError.code {
123
+ case Int(errSecNotAvailable), Int(errSecUnimplemented):
124
+ return "UNAVAILABLE"
125
+ case Int(errSecAuthFailed), Int(errSecInteractionNotAllowed), Int(errSecUserCanceled):
126
+ return "POLICY_REJECTED"
127
+ default:
128
+ return "PROVIDER_ERROR"
129
+ }
130
+ }
131
+
132
+ return "UNKNOWN"
133
+ }
99
134
  }
@@ -44,23 +44,43 @@ final class DPoPModule {
44
44
 
45
45
  func getKeyInfo(alias: String?) -> [String: Any] {
46
46
  let effectiveAlias = resolveAlias(alias)
47
+ let secureEnclaveAvailable = keyStore.isSecureEnclaveAvailable()
48
+ let fallbackReason = keyStore.getSecureEnclaveFallbackReason(alias: effectiveAlias)
49
+ let secureEnclaveFallbackReason: Any = fallbackReason ?? NSNull()
47
50
  let keyInfo = keyStore.getKeyInfo(alias: effectiveAlias)
48
51
 
49
52
  if !keyInfo.hasKeyPair {
50
53
  return [
51
54
  "alias": effectiveAlias,
52
- "hasKeyPair": false
55
+ "hasKeyPair": false,
56
+ "hardware": [
57
+ "ios": [
58
+ "secureEnclaveAvailable": secureEnclaveAvailable,
59
+ "secureEnclaveBacked": false,
60
+ "securityLevel": NSNull(),
61
+ "secureEnclaveFallbackReason": secureEnclaveFallbackReason
62
+ ]
63
+ ]
53
64
  ]
54
65
  }
55
66
 
67
+ let secureEnclaveBacked = secureEnclaveAvailable && keyInfo.insideSecureHardware
68
+ let securityLevel = secureEnclaveBacked ? 2 : 1
69
+
56
70
  return [
57
71
  "alias": keyInfo.alias,
58
72
  "algorithm": keyInfo.algorithm,
59
73
  "curve": keyInfo.curve,
60
74
  "hasKeyPair": true,
61
- "insideSecureHardware": keyInfo.insideSecureHardware,
62
- "strongBoxAvailable": keyInfo.strongBoxAvailable,
63
- "strongBoxBacked": keyInfo.strongBoxBacked
75
+ "insideSecureHardware": secureEnclaveBacked,
76
+ "hardware": [
77
+ "ios": [
78
+ "secureEnclaveAvailable": secureEnclaveAvailable,
79
+ "secureEnclaveBacked": secureEnclaveBacked,
80
+ "securityLevel": securityLevel,
81
+ "secureEnclaveFallbackReason": secureEnclaveFallbackReason
82
+ ]
83
+ ]
64
84
  ]
65
85
  }
66
86
 
@@ -4,6 +4,21 @@ import Security
4
4
  final class SecureEnclaveKeyStore {
5
5
  private let service = "com.dpop.secureenclave"
6
6
 
7
+ func isAvailable() -> Bool {
8
+ #if targetEnvironment(simulator)
9
+ return false
10
+ #else
11
+ let probeAlias = "__secure_enclave_probe_\(UUID().uuidString)"
12
+ do {
13
+ try generateKeyPair(alias: probeAlias)
14
+ try deleteKeyPair(alias: probeAlias)
15
+ return true
16
+ } catch {
17
+ return false
18
+ }
19
+ #endif
20
+ }
21
+
7
22
  func generateKeyPair(alias: String) throws {
8
23
  try deleteKeyPair(alias: alias)
9
24
 
@@ -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;AAoD3D,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","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":[]}
@@ -6,15 +6,27 @@ export type PublicJwk = {
6
6
  y: string;
7
7
  };
8
8
  export type PublicKeyFormat = 'JWK' | 'DER' | 'RAW';
9
+ export type SecureHardwareFallbackReason = 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'POLICY_REJECTED' | 'UNKNOWN';
9
10
  export type DPoPKeyInfo = {
10
11
  alias: string;
11
12
  hasKeyPair: boolean;
12
13
  algorithm?: string;
13
14
  curve?: string;
14
15
  insideSecureHardware?: boolean;
15
- securityLevel?: number;
16
- strongBoxAvailable?: boolean;
17
- strongBoxBacked?: boolean;
16
+ hardware?: {
17
+ android?: {
18
+ strongBoxAvailable: boolean;
19
+ strongBoxBacked: boolean;
20
+ securityLevel?: number;
21
+ strongBoxFallbackReason?: SecureHardwareFallbackReason | null;
22
+ };
23
+ ios?: {
24
+ secureEnclaveAvailable: boolean;
25
+ secureEnclaveBacked: boolean;
26
+ securityLevel?: number | null;
27
+ secureEnclaveFallbackReason?: SecureHardwareFallbackReason | null;
28
+ };
29
+ };
18
30
  };
19
31
  export type GenerateProofInput = {
20
32
  htu: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,IAAI,CAAC;IACV,GAAG,EAAE,OAAO,CAAC;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEpD,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAOF,qBAAa,IAAI;IACf,SAAgB,KAAK,EAAE,MAAM,CAAC;IAC9B,SAAgB,KAAK,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAgB,YAAY,EAAE,gBAAgB,CAAC;IAE/C,OAAO;IAMM,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAItC,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC;IAWlE,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIxD,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAIzC,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;WAgBvD,oBAAoB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAInD,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAI5C,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;WAIhD,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAI5C,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGjE"}
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.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "React Native library for DPoP proof generation and key management.",
5
5
  "keywords": [
6
6
  "android",
@@ -51,7 +51,8 @@
51
51
  "example": "yarn workspace react-native-dpop-example",
52
52
  "lint": "eslint \"**/*.{js,ts,tsx}\"",
53
53
  "prepare": "bob build",
54
- "release": "release-it --only-version",
54
+ "release": "release-it",
55
+ "release:version": "release-it --only-version",
55
56
  "test": "jest",
56
57
  "typecheck": "tsc"
57
58
  },
package/src/index.tsx CHANGED
@@ -11,15 +11,28 @@ export type PublicJwk = {
11
11
 
12
12
  export type PublicKeyFormat = 'JWK' | 'DER' | 'RAW';
13
13
 
14
+ export type SecureHardwareFallbackReason = 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'POLICY_REJECTED' | 'UNKNOWN';
15
+
14
16
  export type DPoPKeyInfo = {
15
17
  alias: string;
16
18
  hasKeyPair: boolean;
17
19
  algorithm?: string;
18
20
  curve?: string;
19
21
  insideSecureHardware?: boolean;
20
- securityLevel?: number;
21
- strongBoxAvailable?: boolean;
22
- strongBoxBacked?: boolean;
22
+ hardware?: {
23
+ android?: {
24
+ strongBoxAvailable: boolean;
25
+ strongBoxBacked: boolean;
26
+ securityLevel?: number;
27
+ strongBoxFallbackReason?: SecureHardwareFallbackReason | null;
28
+ };
29
+ ios?: {
30
+ secureEnclaveAvailable: boolean;
31
+ secureEnclaveBacked: boolean;
32
+ securityLevel?: number | null;
33
+ secureEnclaveFallbackReason?: SecureHardwareFallbackReason | null;
34
+ };
35
+ };
23
36
  };
24
37
 
25
38
  export type GenerateProofInput = {