react-native-dpop 0.4.0 → 1.0.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 +46 -6
- package/android/src/main/java/com/reactnativedpop/DPoPKeyStore.kt +6 -5
- package/android/src/main/java/com/reactnativedpop/DPoPModule.kt +44 -25
- package/android/src/main/java/com/reactnativedpop/DPoPUtils.kt +6 -6
- package/ios/DPoPKeyStore.swift +1 -1
- package/ios/DPoPModule.swift +53 -26
- package/ios/DPoPModuleBridge.mm +6 -5
- package/ios/DPoPUtils.swift +5 -5
- package/lib/module/NativeReactNativeDPoP.js +2 -2
- package/lib/module/NativeReactNativeDPoP.js.map +1 -1
- package/lib/module/index.js +31 -22
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/examples/shared/DPoPExampleContent.d.ts +1 -1
- package/lib/typescript/examples/shared/DPoPExampleContent.d.ts.map +1 -1
- package/lib/typescript/examples/v0.75/App.d.ts +1 -1
- package/lib/typescript/examples/v0.75/App.d.ts.map +1 -1
- package/lib/typescript/examples/v0.83/App.d.ts +1 -1
- package/lib/typescript/examples/v0.83/App.d.ts.map +1 -1
- package/lib/typescript/src/NativeReactNativeDPoP.d.ts +3 -3
- package/lib/typescript/src/NativeReactNativeDPoP.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +31 -25
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeReactNativeDPoP.ts +13 -12
- package/src/index.tsx +61 -45
package/README.md
CHANGED
|
@@ -35,16 +35,17 @@ cd ios && pod install
|
|
|
35
35
|
```ts
|
|
36
36
|
import { DPoP } from 'react-native-dpop';
|
|
37
37
|
|
|
38
|
-
const
|
|
38
|
+
const dPoP = await DPoP.generateProof({
|
|
39
39
|
htu: 'https://api.example.com/token',
|
|
40
40
|
htm: 'POST',
|
|
41
41
|
accessToken: 'ACCESS_TOKEN',
|
|
42
42
|
nonce: 'SERVER_NONCE',
|
|
43
|
+
requireHardwareBacked: true,
|
|
43
44
|
});
|
|
44
45
|
|
|
45
|
-
const proof =
|
|
46
|
-
const thumbprint = await
|
|
47
|
-
const publicJwk = await
|
|
46
|
+
const proof = dPoP.proof;
|
|
47
|
+
const thumbprint = await dPoP.getPublicKeyThumbprint();
|
|
48
|
+
const publicJwk = await dPoP.getPublicKey('JWK');
|
|
48
49
|
const keyInfo = await DPoP.getKeyInfo();
|
|
49
50
|
```
|
|
50
51
|
|
|
@@ -53,6 +54,7 @@ const keyInfo = await DPoP.getKeyInfo();
|
|
|
53
54
|
### Static methods
|
|
54
55
|
|
|
55
56
|
- `DPoP.generateProof(input): Promise<DPoP>`
|
|
57
|
+
- `DPoP.buildDPoPHeaders(input): Promise<DPoPHeaders>`
|
|
56
58
|
- `DPoP.assertHardwareBacked(alias?): Promise<void>`
|
|
57
59
|
- `DPoP.deleteKeyPair(alias?): Promise<void>`
|
|
58
60
|
- `DPoP.getKeyInfo(alias?): Promise<DPoPKeyInfo>`
|
|
@@ -64,14 +66,32 @@ const keyInfo = await DPoP.getKeyInfo();
|
|
|
64
66
|
- `proof: string`
|
|
65
67
|
- `proofContext: DPoPProofContext`
|
|
66
68
|
- `alias?: string`
|
|
67
|
-
- `calculateThumbprint(): Promise<string>`
|
|
68
69
|
- `getPublicKey(format): Promise<PublicJwk | string>`
|
|
69
|
-
- `
|
|
70
|
+
- `getPublicKeyThumbprint(): Promise<string>`
|
|
71
|
+
- `signWithDPoPPrivateKey(payload): Promise<string>`
|
|
70
72
|
- `isBoundToAlias(alias?): Promise<boolean>`
|
|
71
73
|
|
|
74
|
+
### `signWithDPoPPrivateKey()`
|
|
75
|
+
|
|
76
|
+
`signWithDPoPPrivateKey()` reuses the same private key pair managed by the DPoP alias. It does not create or use a separate signing key.
|
|
77
|
+
|
|
78
|
+
This means:
|
|
79
|
+
|
|
80
|
+
- the signature is produced with the same key material used for DPoP proofs
|
|
81
|
+
- the active alias determines which private key is used
|
|
82
|
+
- if the alias points to a hardware-backed key, the same hardware-backed key is reused
|
|
83
|
+
- if the alias points to a fallback software-backed key, the same fallback key is reused
|
|
84
|
+
|
|
85
|
+
Recommended usage:
|
|
86
|
+
|
|
87
|
+
- use this only when you intentionally want to sign arbitrary payloads with the same DPoP key
|
|
88
|
+
- avoid treating it as a general-purpose application signing API
|
|
89
|
+
- if you need a different trust boundary or lifecycle, use a different alias or a different key management flow
|
|
90
|
+
|
|
72
91
|
### Main types
|
|
73
92
|
|
|
74
93
|
- `GenerateProofInput`
|
|
94
|
+
- `DPoPHeaders`
|
|
75
95
|
- `DPoPProofContext`
|
|
76
96
|
- `DPoPKeyInfo`
|
|
77
97
|
- `PublicJwk`
|
|
@@ -130,12 +150,32 @@ type DPoPKeyInfo = {
|
|
|
130
150
|
- Fallback reasons are sanitized enums rather than raw native errors
|
|
131
151
|
- On iOS Simulator, `secureEnclaveFallbackReason` is expected to be `UNAVAILABLE`
|
|
132
152
|
|
|
153
|
+
## `buildDPoPHeaders()`
|
|
154
|
+
|
|
155
|
+
`buildDPoPHeaders()` generates a proof and returns request headers ready to use.
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
const headers = await DPoP.buildDPoPHeaders({
|
|
159
|
+
htu: 'https://api.example.com/token',
|
|
160
|
+
htm: 'POST',
|
|
161
|
+
accessToken: 'ACCESS_TOKEN',
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// {
|
|
165
|
+
// DPoP: '<proof>',
|
|
166
|
+
// Authorization: 'DPoP ACCESS_TOKEN',
|
|
167
|
+
// }
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
If `accessToken` is omitted, only the `DPoP` header is returned.
|
|
171
|
+
|
|
133
172
|
## Notes
|
|
134
173
|
|
|
135
174
|
- Default alias: `react-native-dpop`
|
|
136
175
|
- `htm` is normalized to uppercase
|
|
137
176
|
- `ath` is derived from `accessToken` when provided
|
|
138
177
|
- `jti` and `iat` are auto-generated when omitted
|
|
178
|
+
- `requireHardwareBacked` forces proof generation to fail instead of silently persisting a software-backed fallback key
|
|
139
179
|
- 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
180
|
|
|
141
181
|
## Example apps
|
|
@@ -113,6 +113,8 @@ internal class DPoPKeyStore(private val context: Context) {
|
|
|
113
113
|
val keyPair = getKeyPair(alias)
|
|
114
114
|
val keyFactory = KeyFactory.getInstance(keyPair.privateKey.algorithm, KEYSTORE_PROVIDER)
|
|
115
115
|
val keyInfo = keyFactory.getKeySpec(keyPair.privateKey, KeyInfo::class.java)
|
|
116
|
+
val strongBoxAvailable = isStrongBoxEnabled()
|
|
117
|
+
val strongBoxBacked = strongBoxAvailable && readStrongBoxBacked(keyInfo)
|
|
116
118
|
|
|
117
119
|
return KeyStoreKeyInfo(
|
|
118
120
|
alias = alias,
|
|
@@ -120,9 +122,9 @@ internal class DPoPKeyStore(private val context: Context) {
|
|
|
120
122
|
curve = "P-256",
|
|
121
123
|
insideSecureHardware = keyInfo.isInsideSecureHardware,
|
|
122
124
|
securityLevel = readSecurityLevel(keyInfo),
|
|
123
|
-
securityLevelName = readSecurityLevelName(keyInfo),
|
|
124
|
-
strongBoxAvailable =
|
|
125
|
-
strongBoxBacked =
|
|
125
|
+
securityLevelName = readSecurityLevelName(keyInfo, strongBoxBacked),
|
|
126
|
+
strongBoxAvailable = strongBoxAvailable,
|
|
127
|
+
strongBoxBacked = strongBoxBacked
|
|
126
128
|
)
|
|
127
129
|
}
|
|
128
130
|
|
|
@@ -174,8 +176,7 @@ internal class DPoPKeyStore(private val context: Context) {
|
|
|
174
176
|
}
|
|
175
177
|
}
|
|
176
178
|
|
|
177
|
-
private fun readSecurityLevelName(keyInfo: KeyInfo): String {
|
|
178
|
-
val strongBoxBacked = readStrongBoxBacked(keyInfo)
|
|
179
|
+
private fun readSecurityLevelName(keyInfo: KeyInfo, strongBoxBacked: Boolean): String {
|
|
179
180
|
val securityLevel = readSecurityLevel(keyInfo)
|
|
180
181
|
|
|
181
182
|
return when (securityLevel) {
|
|
@@ -16,12 +16,29 @@ class DPoPModule(reactContext: ReactApplicationContext) :
|
|
|
16
16
|
private const val DEFAULT_ALIAS = "react-native-dpop"
|
|
17
17
|
const val NAME = NativeReactNativeDPoPSpec.NAME
|
|
18
18
|
private const val UNKNOWN_STRONGBOX_FALLBACK_REASON = "UNKNOWN"
|
|
19
|
+
private val RESERVED_DPOP_CLAIMS = setOf("ath", "htm", "htu", "iat", "jti", "nonce")
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
private fun resolveAlias(alias: String?): String {
|
|
22
23
|
return alias ?: DEFAULT_ALIAS
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
private fun ensureKeyPair(alias: String, requireHardwareBacked: Boolean): Unit {
|
|
27
|
+
var generatedInThisCall = false
|
|
28
|
+
|
|
29
|
+
if (!keyStore.hasKeyPair(alias)) {
|
|
30
|
+
keyStore.generateKeyPair(alias)
|
|
31
|
+
generatedInThisCall = true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (requireHardwareBacked && !keyStore.isHardwareBacked(alias)) {
|
|
35
|
+
if (generatedInThisCall) {
|
|
36
|
+
keyStore.deleteKeyPair(alias)
|
|
37
|
+
}
|
|
38
|
+
throw IllegalStateException("Hardware-backed key required for alias: $alias")
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
25
42
|
private fun resolveStrongBoxFallbackReason(
|
|
26
43
|
strongBoxAvailable: Boolean,
|
|
27
44
|
strongBoxBacked: Boolean,
|
|
@@ -57,27 +74,6 @@ class DPoPModule(reactContext: ReactApplicationContext) :
|
|
|
57
74
|
}
|
|
58
75
|
}
|
|
59
76
|
|
|
60
|
-
override fun calculateThumbprint(alias: String?, promise: Promise) {
|
|
61
|
-
try {
|
|
62
|
-
val effectiveAlias = resolveAlias(alias)
|
|
63
|
-
if (!keyStore.hasKeyPair(effectiveAlias)) {
|
|
64
|
-
keyStore.generateKeyPair(effectiveAlias)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
val keyPair = keyStore.getKeyPair(effectiveAlias)
|
|
68
|
-
val coordinates = DPoPUtils.getPublicCoordinates(keyPair.publicKey)
|
|
69
|
-
val thumbprint = DPoPUtils.calculateThumbprint(
|
|
70
|
-
kty = "EC",
|
|
71
|
-
crv = "P-256",
|
|
72
|
-
x = coordinates.first,
|
|
73
|
-
y = coordinates.second
|
|
74
|
-
)
|
|
75
|
-
promise.resolve(thumbprint)
|
|
76
|
-
} catch (e: Exception) {
|
|
77
|
-
promise.reject("ERR_DPOP_CALCULATE_THUMBPRINT", e.message, e)
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
77
|
override fun deleteKeyPair(alias: String?, promise: Promise) {
|
|
82
78
|
try {
|
|
83
79
|
val effectiveAlias = resolveAlias(alias)
|
|
@@ -205,6 +201,27 @@ class DPoPModule(reactContext: ReactApplicationContext) :
|
|
|
205
201
|
}
|
|
206
202
|
}
|
|
207
203
|
|
|
204
|
+
override fun getPublicKeyThumbprint(alias: String?, promise: Promise) {
|
|
205
|
+
try {
|
|
206
|
+
val effectiveAlias = resolveAlias(alias)
|
|
207
|
+
if (!keyStore.hasKeyPair(effectiveAlias)) {
|
|
208
|
+
keyStore.generateKeyPair(effectiveAlias)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
val keyPair = keyStore.getKeyPair(effectiveAlias)
|
|
212
|
+
val coordinates = DPoPUtils.getPublicCoordinates(keyPair.publicKey)
|
|
213
|
+
val thumbprint = DPoPUtils.getPublicKeyThumbprint(
|
|
214
|
+
kty = "EC",
|
|
215
|
+
crv = "P-256",
|
|
216
|
+
x = coordinates.first,
|
|
217
|
+
y = coordinates.second
|
|
218
|
+
)
|
|
219
|
+
promise.resolve(thumbprint)
|
|
220
|
+
} catch (e: Exception) {
|
|
221
|
+
promise.reject("ERR_DPOP_CALCULATE_THUMBPRINT", e.message, e)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
208
225
|
override fun hasKeyPair(alias: String?, promise: Promise) {
|
|
209
226
|
try {
|
|
210
227
|
val effectiveAlias = resolveAlias(alias)
|
|
@@ -238,7 +255,7 @@ class DPoPModule(reactContext: ReactApplicationContext) :
|
|
|
238
255
|
}
|
|
239
256
|
}
|
|
240
257
|
|
|
241
|
-
override fun
|
|
258
|
+
override fun signWithDPoPPrivateKey(payload: String, alias: String?, promise: Promise) {
|
|
242
259
|
try {
|
|
243
260
|
val effectiveAlias = resolveAlias(alias)
|
|
244
261
|
if (!keyStore.hasKeyPair(effectiveAlias)) {
|
|
@@ -267,13 +284,12 @@ class DPoPModule(reactContext: ReactApplicationContext) :
|
|
|
267
284
|
jti: String?,
|
|
268
285
|
iat: Double?,
|
|
269
286
|
alias: String?,
|
|
287
|
+
requireHardwareBacked: Boolean,
|
|
270
288
|
promise: Promise
|
|
271
289
|
) {
|
|
272
290
|
try {
|
|
273
291
|
val effectiveAlias = resolveAlias(alias)
|
|
274
|
-
|
|
275
|
-
keyStore.generateKeyPair(effectiveAlias)
|
|
276
|
-
}
|
|
292
|
+
ensureKeyPair(effectiveAlias, requireHardwareBacked)
|
|
277
293
|
|
|
278
294
|
val keyPair = keyStore.getKeyPair(effectiveAlias)
|
|
279
295
|
val coordinates = DPoPUtils.getPublicCoordinates(keyPair.publicKey)
|
|
@@ -313,6 +329,9 @@ class DPoPModule(reactContext: ReactApplicationContext) :
|
|
|
313
329
|
val keys = additionalJson.keys()
|
|
314
330
|
while (keys.hasNext()) {
|
|
315
331
|
val key = keys.next()
|
|
332
|
+
if (RESERVED_DPOP_CLAIMS.contains(key)) {
|
|
333
|
+
throw IllegalArgumentException("additional must not override reserved DPoP claim: $key")
|
|
334
|
+
}
|
|
316
335
|
payload.put(key, additionalJson.get(key))
|
|
317
336
|
}
|
|
318
337
|
}
|
|
@@ -18,12 +18,6 @@ internal object DPoPUtils {
|
|
|
18
18
|
return Base64.getUrlEncoder().withoutPadding().encodeToString(input)
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
internal fun calculateThumbprint(kty: String, crv: String, x: String, y: String): String {
|
|
22
|
-
val canonicalJwk = """{"crv":"$crv","kty":"$kty","x":"$x","y":"$y"}"""
|
|
23
|
-
val hash = MessageDigest.getInstance("SHA-256").digest(canonicalJwk.toByteArray(Charsets.UTF_8))
|
|
24
|
-
return base64UrlEncode(hash)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
21
|
internal fun derToJose(derSignature: ByteArray, partLength: Int = 32): ByteArray {
|
|
28
22
|
if (derSignature.isEmpty() || derSignature[0].toInt() != 0x30) {
|
|
29
23
|
throw IllegalArgumentException("Invalid DER signature format")
|
|
@@ -65,6 +59,12 @@ internal object DPoPUtils {
|
|
|
65
59
|
return Pair(x, y)
|
|
66
60
|
}
|
|
67
61
|
|
|
62
|
+
internal fun getPublicKeyThumbprint(kty: String, crv: String, x: String, y: String): String {
|
|
63
|
+
val canonicalJwk = """{"crv":"$crv","kty":"$kty","x":"$x","y":"$y"}"""
|
|
64
|
+
val hash = MessageDigest.getInstance("SHA-256").digest(canonicalJwk.toByteArray(Charsets.UTF_8))
|
|
65
|
+
return base64UrlEncode(hash)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
68
|
internal fun hashAccessToken(accessToken: String): String {
|
|
69
69
|
val hash = MessageDigest.getInstance("SHA-256").digest(accessToken.toByteArray(Charsets.UTF_8))
|
|
70
70
|
return base64UrlEncode(hash)
|
package/ios/DPoPKeyStore.swift
CHANGED
package/ios/DPoPModule.swift
CHANGED
|
@@ -7,6 +7,7 @@ final class DPoPModule {
|
|
|
7
7
|
|
|
8
8
|
private let keyStore = DPoPKeyStore()
|
|
9
9
|
private let defaultAlias = "react-native-dpop"
|
|
10
|
+
private let reservedDPoPClaims = Set(["ath", "htm", "htu", "iat", "jti", "nonce"])
|
|
10
11
|
private let unknownSecureEnclaveFallbackReason = "UNKNOWN"
|
|
11
12
|
private let unavailableSecureEnclaveFallbackReason = "UNAVAILABLE"
|
|
12
13
|
|
|
@@ -19,6 +20,24 @@ final class DPoPModule {
|
|
|
19
20
|
return alias
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
func ensureKeyPair(alias: String, requireHardwareBacked: Bool) throws {
|
|
24
|
+
var generatedInThisCall = false
|
|
25
|
+
|
|
26
|
+
if !keyStore.hasKeyPair(alias: alias) {
|
|
27
|
+
try keyStore.generateKeyPair(alias: alias)
|
|
28
|
+
generatedInThisCall = true
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let isHardwareBacked = keyStore.isHardwareBacked(alias: alias)
|
|
32
|
+
|
|
33
|
+
if requireHardwareBacked && !isHardwareBacked {
|
|
34
|
+
if generatedInThisCall {
|
|
35
|
+
try? keyStore.deleteKeyPair(alias: alias)
|
|
36
|
+
}
|
|
37
|
+
throw DPoPError.notHardwareBacked(alias: alias)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
22
41
|
func assertHardwareBacked(alias: String?) throws {
|
|
23
42
|
let effectiveAlias = resolveAlias(alias)
|
|
24
43
|
guard keyStore.hasKeyPair(alias: effectiveAlias) else {
|
|
@@ -30,16 +49,6 @@ final class DPoPModule {
|
|
|
30
49
|
}
|
|
31
50
|
}
|
|
32
51
|
|
|
33
|
-
func calculateThumbprint(alias: String?) throws -> String {
|
|
34
|
-
let effectiveAlias = resolveAlias(alias)
|
|
35
|
-
if !keyStore.hasKeyPair(alias: effectiveAlias) {
|
|
36
|
-
try keyStore.generateKeyPair(alias: effectiveAlias)
|
|
37
|
-
}
|
|
38
|
-
let keyPair = try keyStore.getKeyPair(alias: effectiveAlias)
|
|
39
|
-
let coordinates = try DPoPUtils.getPublicCoordinates(fromRawPublicKey: try DPoPUtils.toRawPublicKey(keyPair.publicKey))
|
|
40
|
-
return DPoPUtils.calculateThumbprint(kty: "EC", crv: "P-256", x: coordinates.x, y: coordinates.y)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
52
|
func deleteKeyPair(alias: String?) throws {
|
|
44
53
|
try keyStore.deleteKeyPair(alias: resolveAlias(alias))
|
|
45
54
|
}
|
|
@@ -148,6 +157,16 @@ final class DPoPModule {
|
|
|
148
157
|
return DPoPUtils.base64UrlEncode(try DPoPUtils.toRawPublicKey(keyPair.publicKey))
|
|
149
158
|
}
|
|
150
159
|
|
|
160
|
+
func getPublicKeyThumbprint(alias: String?) throws -> String {
|
|
161
|
+
let effectiveAlias = resolveAlias(alias)
|
|
162
|
+
if !keyStore.hasKeyPair(alias: effectiveAlias) {
|
|
163
|
+
try keyStore.generateKeyPair(alias: effectiveAlias)
|
|
164
|
+
}
|
|
165
|
+
let keyPair = try keyStore.getKeyPair(alias: effectiveAlias)
|
|
166
|
+
let coordinates = try DPoPUtils.getPublicCoordinates(fromRawPublicKey: try DPoPUtils.toRawPublicKey(keyPair.publicKey))
|
|
167
|
+
return DPoPUtils.getPublicKeyThumbprint(kty: "EC", crv: "P-256", x: coordinates.x, y: coordinates.y)
|
|
168
|
+
}
|
|
169
|
+
|
|
151
170
|
func hasKeyPair(alias: String?) -> Bool {
|
|
152
171
|
keyStore.hasKeyPair(alias: resolveAlias(alias))
|
|
153
172
|
}
|
|
@@ -165,7 +184,7 @@ final class DPoPModule {
|
|
|
165
184
|
try keyStore.generateKeyPair(alias: resolveAlias(alias))
|
|
166
185
|
}
|
|
167
186
|
|
|
168
|
-
func
|
|
187
|
+
func signWithDPoPPrivateKey(payload: String, alias: String?) throws -> String {
|
|
169
188
|
let effectiveAlias = resolveAlias(alias)
|
|
170
189
|
if !keyStore.hasKeyPair(alias: effectiveAlias) {
|
|
171
190
|
try keyStore.generateKeyPair(alias: effectiveAlias)
|
|
@@ -193,12 +212,11 @@ final class DPoPModule {
|
|
|
193
212
|
kid: String?,
|
|
194
213
|
jti: String?,
|
|
195
214
|
iat: NSNumber?,
|
|
196
|
-
alias: String
|
|
215
|
+
alias: String?,
|
|
216
|
+
requireHardwareBacked: Bool
|
|
197
217
|
) throws -> [String: Any] {
|
|
198
218
|
let effectiveAlias = resolveAlias(alias)
|
|
199
|
-
|
|
200
|
-
try keyStore.generateKeyPair(alias: effectiveAlias)
|
|
201
|
-
}
|
|
219
|
+
try ensureKeyPair(alias: effectiveAlias, requireHardwareBacked: requireHardwareBacked)
|
|
202
220
|
let keyPair = try keyStore.getKeyPair(alias: effectiveAlias)
|
|
203
221
|
let coordinates = try DPoPUtils.getPublicCoordinates(fromRawPublicKey: try DPoPUtils.toRawPublicKey(keyPair.publicKey))
|
|
204
222
|
|
|
@@ -239,6 +257,13 @@ final class DPoPModule {
|
|
|
239
257
|
|
|
240
258
|
if let additional {
|
|
241
259
|
for (key, value) in additional {
|
|
260
|
+
if reservedDPoPClaims.contains(key) {
|
|
261
|
+
throw NSError(
|
|
262
|
+
domain: "ReactNativeDPoP",
|
|
263
|
+
code: 0,
|
|
264
|
+
userInfo: [NSLocalizedDescriptionKey: "additional must not override reserved DPoP claim: \(key)"]
|
|
265
|
+
)
|
|
266
|
+
}
|
|
242
267
|
payload[key] = value
|
|
243
268
|
}
|
|
244
269
|
}
|
|
@@ -296,14 +321,6 @@ final class DPoPModule {
|
|
|
296
321
|
}
|
|
297
322
|
}
|
|
298
323
|
|
|
299
|
-
func calculateThumbprint(_ alias: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
300
|
-
do {
|
|
301
|
-
resolve(try DPoPModule.shared.calculateThumbprint(alias: alias))
|
|
302
|
-
} catch {
|
|
303
|
-
reject("ERR_DPOP_CALCULATE_THUMBPRINT", error.localizedDescription, error)
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
324
|
func deleteKeyPair(_ alias: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
308
325
|
do {
|
|
309
326
|
try DPoPModule.shared.deleteKeyPair(alias: alias)
|
|
@@ -341,6 +358,14 @@ final class DPoPModule {
|
|
|
341
358
|
}
|
|
342
359
|
}
|
|
343
360
|
|
|
361
|
+
func getPublicKeyThumbprint(_ alias: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
362
|
+
do {
|
|
363
|
+
resolve(try DPoPModule.shared.getPublicKeyThumbprint(alias: alias))
|
|
364
|
+
} catch {
|
|
365
|
+
reject("ERR_DPOP_CALCULATE_THUMBPRINT", error.localizedDescription, error)
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
344
369
|
func hasKeyPair(_ alias: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
345
370
|
resolve(DPoPModule.shared.hasKeyPair(alias: alias))
|
|
346
371
|
}
|
|
@@ -362,9 +387,9 @@ final class DPoPModule {
|
|
|
362
387
|
}
|
|
363
388
|
}
|
|
364
389
|
|
|
365
|
-
func
|
|
390
|
+
func signWithDPoPPrivateKey(_ payload: String, alias: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
366
391
|
do {
|
|
367
|
-
resolve(try DPoPModule.shared.
|
|
392
|
+
resolve(try DPoPModule.shared.signWithDPoPPrivateKey(payload: payload, alias: alias))
|
|
368
393
|
} catch {
|
|
369
394
|
reject("ERR_DPOP_SIGN_WITH_PRIVATE_KEY", error.localizedDescription, error)
|
|
370
395
|
}
|
|
@@ -380,6 +405,7 @@ final class DPoPModule {
|
|
|
380
405
|
jti: String?,
|
|
381
406
|
iat: Any?,
|
|
382
407
|
alias: String?,
|
|
408
|
+
requireHardwareBacked: Bool,
|
|
383
409
|
resolve: @escaping RCTPromiseResolveBlock,
|
|
384
410
|
reject: @escaping RCTPromiseRejectBlock
|
|
385
411
|
) {
|
|
@@ -401,7 +427,8 @@ final class DPoPModule {
|
|
|
401
427
|
kid: kid,
|
|
402
428
|
jti: jti,
|
|
403
429
|
iat: normalizedIat,
|
|
404
|
-
alias: alias
|
|
430
|
+
alias: alias,
|
|
431
|
+
requireHardwareBacked: requireHardwareBacked
|
|
405
432
|
)
|
|
406
433
|
)
|
|
407
434
|
} catch {
|
package/ios/DPoPModuleBridge.mm
CHANGED
|
@@ -21,10 +21,6 @@ RCT_EXTERN_METHOD(assertHardwareBacked:(NSString * _Nullable)alias
|
|
|
21
21
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
22
22
|
reject:(RCTPromiseRejectBlock)reject)
|
|
23
23
|
|
|
24
|
-
RCT_EXTERN_METHOD(calculateThumbprint:(NSString * _Nullable)alias
|
|
25
|
-
resolve:(RCTPromiseResolveBlock)resolve
|
|
26
|
-
reject:(RCTPromiseRejectBlock)reject)
|
|
27
|
-
|
|
28
24
|
RCT_EXTERN_METHOD(deleteKeyPair:(NSString * _Nullable)alias
|
|
29
25
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
30
26
|
reject:(RCTPromiseRejectBlock)reject)
|
|
@@ -45,6 +41,10 @@ RCT_EXTERN_METHOD(getPublicKeyRaw:(NSString * _Nullable)alias
|
|
|
45
41
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
46
42
|
reject:(RCTPromiseRejectBlock)reject)
|
|
47
43
|
|
|
44
|
+
RCT_EXTERN_METHOD(getPublicKeyThumbprint:(NSString * _Nullable)alias
|
|
45
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
46
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
47
|
+
|
|
48
48
|
RCT_EXTERN_METHOD(hasKeyPair:(NSString * _Nullable)alias
|
|
49
49
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
50
50
|
reject:(RCTPromiseRejectBlock)reject)
|
|
@@ -58,7 +58,7 @@ RCT_EXTERN_METHOD(rotateKeyPair:(NSString * _Nullable)alias
|
|
|
58
58
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
59
59
|
reject:(RCTPromiseRejectBlock)reject)
|
|
60
60
|
|
|
61
|
-
RCT_EXTERN_METHOD(
|
|
61
|
+
RCT_EXTERN_METHOD(signWithDPoPPrivateKey:(NSString *)payload
|
|
62
62
|
alias:(NSString * _Nullable)alias
|
|
63
63
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
64
64
|
reject:(RCTPromiseRejectBlock)reject)
|
|
@@ -72,6 +72,7 @@ RCT_EXTERN_METHOD(generateProof:(NSString *)htu
|
|
|
72
72
|
jti:(NSString * _Nullable)jti
|
|
73
73
|
iat:(id _Nullable)iat
|
|
74
74
|
alias:(NSString * _Nullable)alias
|
|
75
|
+
requireHardwareBacked:(BOOL)requireHardwareBacked
|
|
75
76
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
76
77
|
reject:(RCTPromiseRejectBlock)reject)
|
|
77
78
|
|
package/ios/DPoPUtils.swift
CHANGED
|
@@ -28,11 +28,6 @@ enum DPoPUtils {
|
|
|
28
28
|
return base64UrlEncode(sha256(data))
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
static func calculateThumbprint(kty: String, crv: String, x: String, y: String) -> String {
|
|
32
|
-
let canonical = "{\"crv\":\"\(crv)\",\"kty\":\"\(kty)\",\"x\":\"\(x)\",\"y\":\"\(y)\"}"
|
|
33
|
-
return base64UrlEncode(sha256(Data(canonical.utf8)))
|
|
34
|
-
}
|
|
35
|
-
|
|
36
31
|
static func jsonData(_ object: Any) throws -> Data {
|
|
37
32
|
if #available(iOS 11.0, *) {
|
|
38
33
|
return try JSONSerialization.data(withJSONObject: object, options: [.sortedKeys])
|
|
@@ -92,6 +87,11 @@ enum DPoPUtils {
|
|
|
92
87
|
return (base64UrlEncode(x), base64UrlEncode(y))
|
|
93
88
|
}
|
|
94
89
|
|
|
90
|
+
static func getPublicKeyThumbprint(kty: String, crv: String, x: String, y: String) -> String {
|
|
91
|
+
let canonical = "{\"crv\":\"\(crv)\",\"kty\":\"\(kty)\",\"x\":\"\(x)\",\"y\":\"\(y)\"}"
|
|
92
|
+
return base64UrlEncode(sha256(Data(canonical.utf8)))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
95
|
static func toRawPublicKey(_ publicKey: SecKey) throws -> Data {
|
|
96
96
|
var error: Unmanaged<CFError>?
|
|
97
97
|
guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, &error) as Data? else {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { NativeModules, TurboModuleRegistry } from 'react-native';
|
|
4
|
-
const
|
|
4
|
+
const nativeDPoPModule =
|
|
5
5
|
// eslint-disable-next-line dot-notation -- required by noPropertyAccessFromIndexSignature from @tsconfig/strictest
|
|
6
6
|
TurboModuleRegistry.get('ReactNativeDPoP') ?? NativeModules['ReactNativeDPoP'];
|
|
7
|
-
export default
|
|
7
|
+
export default nativeDPoPModule;
|
|
8
8
|
//# sourceMappingURL=NativeReactNativeDPoP.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","TurboModuleRegistry","
|
|
1
|
+
{"version":3,"names":["NativeModules","TurboModuleRegistry","nativeDPoPModule","get"],"sourceRoot":"../../src","sources":["NativeReactNativeDPoP.ts"],"mappings":";;AACA,SAASA,aAAa,EAAEC,mBAAmB,QAAQ,cAAc;AA6BjE,MAAMC,gBAAgB;AACpB;AACAD,mBAAmB,CAACE,GAAG,CAAO,iBAAiB,CAAC,IAAKH,aAAa,CAAC,iBAAiB,CAAsB;AAE5G,eAAeE,gBAAgB","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -7,36 +7,27 @@ export class DPoP {
|
|
|
7
7
|
this.proofContext = proofContext;
|
|
8
8
|
this.alias = alias;
|
|
9
9
|
}
|
|
10
|
-
async
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
async getPublicKey(format) {
|
|
14
|
-
if (format === 'DER') {
|
|
15
|
-
return NativeReactNativeDPoP.getPublicKeyDer(this.alias ?? null);
|
|
16
|
-
}
|
|
17
|
-
if (format === 'RAW') {
|
|
18
|
-
return NativeReactNativeDPoP.getPublicKeyRaw(this.alias ?? null);
|
|
19
|
-
}
|
|
20
|
-
return NativeReactNativeDPoP.getPublicKeyJwk(this.alias ?? null);
|
|
10
|
+
static async assertHardwareBacked(alias) {
|
|
11
|
+
await NativeReactNativeDPoP.assertHardwareBacked(alias ?? null);
|
|
21
12
|
}
|
|
22
|
-
async
|
|
23
|
-
|
|
13
|
+
static async buildDPoPHeaders(input) {
|
|
14
|
+
const dPoP = await DPoP.generateProof(input);
|
|
15
|
+
return {
|
|
16
|
+
DPoP: dPoP.proof,
|
|
17
|
+
...(input.accessToken ? {
|
|
18
|
+
Authorization: `DPoP ${input.accessToken}`
|
|
19
|
+
} : {})
|
|
20
|
+
};
|
|
24
21
|
}
|
|
25
|
-
async
|
|
26
|
-
|
|
22
|
+
static async deleteKeyPair(alias) {
|
|
23
|
+
await NativeReactNativeDPoP.deleteKeyPair(alias ?? null);
|
|
27
24
|
}
|
|
28
25
|
static async generateProof(input) {
|
|
29
26
|
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
27
|
// 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);
|
|
28
|
+
input.iat ?? Math.floor(Date.now() / 1000), input.alias ?? null, input.requireHardwareBacked ?? false);
|
|
32
29
|
return new DPoP(result.proof, result.proofContext, input.alias);
|
|
33
30
|
}
|
|
34
|
-
static async assertHardwareBacked(alias) {
|
|
35
|
-
await NativeReactNativeDPoP.assertHardwareBacked(alias ?? null);
|
|
36
|
-
}
|
|
37
|
-
static async deleteKeyPair(alias) {
|
|
38
|
-
await NativeReactNativeDPoP.deleteKeyPair(alias ?? null);
|
|
39
|
-
}
|
|
40
31
|
static async getKeyInfo(alias) {
|
|
41
32
|
return NativeReactNativeDPoP.getKeyInfo(alias ?? null);
|
|
42
33
|
}
|
|
@@ -46,5 +37,23 @@ export class DPoP {
|
|
|
46
37
|
static async rotateKeyPair(alias) {
|
|
47
38
|
await NativeReactNativeDPoP.rotateKeyPair(alias ?? null);
|
|
48
39
|
}
|
|
40
|
+
async getPublicKey(format) {
|
|
41
|
+
if (format === 'DER') {
|
|
42
|
+
return NativeReactNativeDPoP.getPublicKeyDer(this.alias ?? null);
|
|
43
|
+
}
|
|
44
|
+
if (format === 'RAW') {
|
|
45
|
+
return NativeReactNativeDPoP.getPublicKeyRaw(this.alias ?? null);
|
|
46
|
+
}
|
|
47
|
+
return NativeReactNativeDPoP.getPublicKeyJwk(this.alias ?? null);
|
|
48
|
+
}
|
|
49
|
+
async getPublicKeyThumbprint() {
|
|
50
|
+
return NativeReactNativeDPoP.getPublicKeyThumbprint(this.alias ?? null);
|
|
51
|
+
}
|
|
52
|
+
async isBoundToAlias(alias) {
|
|
53
|
+
return NativeReactNativeDPoP.isBoundToAlias(this.proof, alias ?? this.alias ?? null);
|
|
54
|
+
}
|
|
55
|
+
async signWithDPoPPrivateKey(payload) {
|
|
56
|
+
return NativeReactNativeDPoP.signWithDPoPPrivateKey(payload, this.alias ?? null);
|
|
57
|
+
}
|
|
49
58
|
}
|
|
50
59
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeReactNativeDPoP","DPoP","constructor","proof","proofContext","alias","
|
|
1
|
+
{"version":3,"names":["NativeReactNativeDPoP","DPoP","constructor","proof","proofContext","alias","assertHardwareBacked","buildDPoPHeaders","input","dPoP","generateProof","accessToken","Authorization","deleteKeyPair","result","htu","htm","nonce","additional","kid","jti","iat","Math","floor","Date","now","requireHardwareBacked","getKeyInfo","hasKeyPair","rotateKeyPair","getPublicKey","format","getPublicKeyDer","getPublicKeyRaw","getPublicKeyJwk","getPublicKeyThumbprint","isBoundToAlias","signWithDPoPPrivateKey","payload"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export default function DPoPExampleContent():
|
|
1
|
+
export default function DPoPExampleContent(): JSX.Element;
|
|
2
2
|
//# sourceMappingURL=DPoPExampleContent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DPoPExampleContent.d.ts","sourceRoot":"","sources":["../../../../examples/shared/DPoPExampleContent.tsx"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,kBAAkB,
|
|
1
|
+
{"version":3,"file":"DPoPExampleContent.d.ts","sourceRoot":"","sources":["../../../../examples/shared/DPoPExampleContent.tsx"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,kBAAkB,IAAI,GAAG,CAAC,OAAO,CA2BxD"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export default function App():
|
|
1
|
+
export default function App(): JSX.Element;
|
|
2
2
|
//# sourceMappingURL=App.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../examples/v0.75/App.tsx"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../examples/v0.75/App.tsx"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAMzC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export default function App():
|
|
1
|
+
export default function App(): JSX.Element;
|
|
2
2
|
//# sourceMappingURL=App.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../examples/v0.83/App.tsx"],"names":[],"mappings":"AAKA,MAAM,CAAC,OAAO,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../examples/v0.83/App.tsx"],"names":[],"mappings":"AAKA,MAAM,CAAC,OAAO,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAMzC"}
|
|
@@ -2,17 +2,17 @@ import type { TurboModule } from 'react-native';
|
|
|
2
2
|
import type { UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
|
|
3
3
|
export interface Spec extends TurboModule {
|
|
4
4
|
assertHardwareBacked(alias: string | null): Promise<void>;
|
|
5
|
-
calculateThumbprint(alias: string | null): Promise<string>;
|
|
6
5
|
deleteKeyPair(alias: string | null): Promise<void>;
|
|
6
|
+
generateProof(htu: string, htm: string, nonce: string | null, accessToken: string | null, additional: UnsafeObject | null, kid: string | null, jti: string | null, iat: number | null, alias: string | null, requireHardwareBacked: boolean): Promise<UnsafeObject>;
|
|
7
7
|
getKeyInfo(alias: string | null): Promise<UnsafeObject>;
|
|
8
8
|
getPublicKeyDer(alias: string | null): Promise<string>;
|
|
9
9
|
getPublicKeyJwk(alias: string | null): Promise<UnsafeObject>;
|
|
10
10
|
getPublicKeyRaw(alias: string | null): Promise<string>;
|
|
11
|
+
getPublicKeyThumbprint(alias: string | null): Promise<string>;
|
|
11
12
|
hasKeyPair(alias: string | null): Promise<boolean>;
|
|
12
13
|
isBoundToAlias(proof: string, alias: string | null): Promise<boolean>;
|
|
13
14
|
rotateKeyPair(alias: string | null): Promise<void>;
|
|
14
|
-
|
|
15
|
-
generateProof(htu: string, htm: string, nonce: string | null, accessToken: string | null, additional: UnsafeObject | null, kid: string | null, jti: string | null, iat: number | null, alias: string | null): Promise<UnsafeObject>;
|
|
15
|
+
signWithDPoPPrivateKey(payload: string, alias: string | null): Promise<string>;
|
|
16
16
|
}
|
|
17
17
|
declare const _default: Spec;
|
|
18
18
|
export default _default;
|
|
@@ -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,
|
|
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,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,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,EACpB,qBAAqB,EAAE,OAAO,GAC7B,OAAO,CAAC,YAAY,CAAC,CAAC;IACzB,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,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9D,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;CAChF;wBAMkC,IAAI;AAAvC,wBAAwC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
type AdditionalClaims = Record<string, unknown>;
|
|
2
2
|
export type PublicJwk = {
|
|
3
|
-
kty: 'EC';
|
|
4
3
|
crv: 'P-256';
|
|
4
|
+
kty: 'EC';
|
|
5
5
|
x: string;
|
|
6
6
|
y: string;
|
|
7
7
|
};
|
|
@@ -10,64 +10,70 @@ export type SecureHardwareFallbackReason = 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'P
|
|
|
10
10
|
export type AndroidSecurityLevelName = 'SOFTWARE' | 'TRUSTED_ENVIRONMENT' | 'STRONGBOX';
|
|
11
11
|
export type IOSSecurityLevelName = 'SOFTWARE' | 'SECURE_ENCLAVE';
|
|
12
12
|
export type DPoPKeyInfo = {
|
|
13
|
-
alias: string;
|
|
14
|
-
hasKeyPair: boolean;
|
|
15
13
|
algorithm?: string;
|
|
14
|
+
alias: string;
|
|
16
15
|
curve?: string;
|
|
17
|
-
insideSecureHardware?: boolean;
|
|
18
16
|
hardware?: {
|
|
19
17
|
android?: {
|
|
20
|
-
strongBoxAvailable: boolean;
|
|
21
|
-
strongBoxBacked: boolean;
|
|
22
18
|
securityLevel?: number;
|
|
23
19
|
securityLevelName?: AndroidSecurityLevelName;
|
|
20
|
+
strongBoxAvailable: boolean;
|
|
21
|
+
strongBoxBacked: boolean;
|
|
24
22
|
strongBoxFallbackReason?: SecureHardwareFallbackReason | null;
|
|
25
23
|
};
|
|
26
24
|
ios?: {
|
|
27
25
|
secureEnclaveAvailable: boolean;
|
|
28
26
|
secureEnclaveBacked: boolean;
|
|
27
|
+
secureEnclaveFallbackReason?: SecureHardwareFallbackReason | null;
|
|
29
28
|
securityLevel?: number | null;
|
|
30
29
|
securityLevelName?: IOSSecurityLevelName;
|
|
31
|
-
secureEnclaveFallbackReason?: SecureHardwareFallbackReason | null;
|
|
32
30
|
};
|
|
33
31
|
};
|
|
32
|
+
hasKeyPair: boolean;
|
|
33
|
+
insideSecureHardware?: boolean;
|
|
34
34
|
};
|
|
35
35
|
export type GenerateProofInput = {
|
|
36
|
-
htu: string;
|
|
37
|
-
htm: string;
|
|
38
|
-
nonce?: string;
|
|
39
36
|
accessToken?: string;
|
|
40
37
|
additional?: AdditionalClaims;
|
|
41
|
-
kid?: string;
|
|
42
|
-
jti?: string;
|
|
43
|
-
iat?: number;
|
|
44
38
|
alias?: string;
|
|
39
|
+
htm: string;
|
|
40
|
+
htu: string;
|
|
41
|
+
iat?: number;
|
|
42
|
+
jti?: string;
|
|
43
|
+
kid?: string;
|
|
44
|
+
nonce?: string;
|
|
45
|
+
requireHardwareBacked?: boolean;
|
|
46
|
+
};
|
|
47
|
+
export type DPoPHeaders = {
|
|
48
|
+
Authorization?: string;
|
|
49
|
+
DPoP: string;
|
|
45
50
|
};
|
|
46
51
|
export type DPoPProofContext = {
|
|
47
|
-
htu: string;
|
|
48
|
-
htm: string;
|
|
49
|
-
nonce: string | null;
|
|
50
|
-
ath: string | null;
|
|
51
52
|
additional: AdditionalClaims | null;
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
ath: string | null;
|
|
54
|
+
htm: string;
|
|
55
|
+
htu: string;
|
|
54
56
|
iat: number;
|
|
57
|
+
jti: string;
|
|
58
|
+
kid: string | null;
|
|
59
|
+
nonce: string | null;
|
|
55
60
|
};
|
|
56
61
|
export declare class DPoP {
|
|
57
|
-
readonly proof: string;
|
|
58
62
|
readonly alias: string | undefined;
|
|
63
|
+
readonly proof: string;
|
|
59
64
|
readonly proofContext: DPoPProofContext;
|
|
60
65
|
private constructor();
|
|
61
|
-
calculateThumbprint(): Promise<string>;
|
|
62
|
-
getPublicKey(format: PublicKeyFormat): Promise<PublicJwk | string>;
|
|
63
|
-
signWithDpopPrivateKey(payload: string): Promise<string>;
|
|
64
|
-
isBoundToAlias(alias?: string): Promise<boolean>;
|
|
65
|
-
static generateProof(input: GenerateProofInput): Promise<DPoP>;
|
|
66
66
|
static assertHardwareBacked(alias?: string): Promise<void>;
|
|
67
|
+
static buildDPoPHeaders(input: GenerateProofInput): Promise<DPoPHeaders>;
|
|
67
68
|
static deleteKeyPair(alias?: string): Promise<void>;
|
|
69
|
+
static generateProof(input: GenerateProofInput): Promise<DPoP>;
|
|
68
70
|
static getKeyInfo(alias?: string): Promise<DPoPKeyInfo>;
|
|
69
71
|
static hasKeyPair(alias?: string): Promise<boolean>;
|
|
70
72
|
static rotateKeyPair(alias?: string): Promise<void>;
|
|
73
|
+
getPublicKey(format: PublicKeyFormat): Promise<PublicJwk | string>;
|
|
74
|
+
getPublicKeyThumbprint(): Promise<string>;
|
|
75
|
+
isBoundToAlias(alias?: string): Promise<boolean>;
|
|
76
|
+
signWithDPoPPrivateKey(payload: string): Promise<string>;
|
|
71
77
|
}
|
|
72
78
|
export {};
|
|
73
79
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -4,16 +4,7 @@ import type { UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
|
|
|
4
4
|
|
|
5
5
|
export interface Spec extends TurboModule {
|
|
6
6
|
assertHardwareBacked(alias: string | null): Promise<void>;
|
|
7
|
-
calculateThumbprint(alias: string | null): Promise<string>;
|
|
8
7
|
deleteKeyPair(alias: string | null): Promise<void>;
|
|
9
|
-
getKeyInfo(alias: string | null): Promise<UnsafeObject>;
|
|
10
|
-
getPublicKeyDer(alias: string | null): Promise<string>;
|
|
11
|
-
getPublicKeyJwk(alias: string | null): Promise<UnsafeObject>;
|
|
12
|
-
getPublicKeyRaw(alias: string | null): Promise<string>;
|
|
13
|
-
hasKeyPair(alias: string | null): Promise<boolean>;
|
|
14
|
-
isBoundToAlias(proof: string, alias: string | null): Promise<boolean>;
|
|
15
|
-
rotateKeyPair(alias: string | null): Promise<void>;
|
|
16
|
-
signWithDpopPrivateKey(payload: string, alias: string | null): Promise<string>;
|
|
17
8
|
generateProof(
|
|
18
9
|
htu: string,
|
|
19
10
|
htm: string,
|
|
@@ -23,12 +14,22 @@ export interface Spec extends TurboModule {
|
|
|
23
14
|
kid: string | null,
|
|
24
15
|
jti: string | null,
|
|
25
16
|
iat: number | null,
|
|
26
|
-
alias: string | null
|
|
17
|
+
alias: string | null,
|
|
18
|
+
requireHardwareBacked: boolean
|
|
27
19
|
): Promise<UnsafeObject>;
|
|
20
|
+
getKeyInfo(alias: string | null): Promise<UnsafeObject>;
|
|
21
|
+
getPublicKeyDer(alias: string | null): Promise<string>;
|
|
22
|
+
getPublicKeyJwk(alias: string | null): Promise<UnsafeObject>;
|
|
23
|
+
getPublicKeyRaw(alias: string | null): Promise<string>;
|
|
24
|
+
getPublicKeyThumbprint(alias: string | null): Promise<string>;
|
|
25
|
+
hasKeyPair(alias: string | null): Promise<boolean>;
|
|
26
|
+
isBoundToAlias(proof: string, alias: string | null): Promise<boolean>;
|
|
27
|
+
rotateKeyPair(alias: string | null): Promise<void>;
|
|
28
|
+
signWithDPoPPrivateKey(payload: string, alias: string | null): Promise<string>;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
const
|
|
31
|
+
const nativeDPoPModule =
|
|
31
32
|
// eslint-disable-next-line dot-notation -- required by noPropertyAccessFromIndexSignature from @tsconfig/strictest
|
|
32
33
|
TurboModuleRegistry.get<Spec>('ReactNativeDPoP') ?? (NativeModules['ReactNativeDPoP'] as Spec | undefined);
|
|
33
34
|
|
|
34
|
-
export default
|
|
35
|
+
export default nativeDPoPModule as Spec;
|
package/src/index.tsx
CHANGED
|
@@ -3,8 +3,8 @@ import NativeReactNativeDPoP from './NativeReactNativeDPoP';
|
|
|
3
3
|
type AdditionalClaims = Record<string, unknown>;
|
|
4
4
|
|
|
5
5
|
export type PublicJwk = {
|
|
6
|
-
kty: 'EC';
|
|
7
6
|
crv: 'P-256';
|
|
7
|
+
kty: 'EC';
|
|
8
8
|
x: string;
|
|
9
9
|
y: string;
|
|
10
10
|
};
|
|
@@ -16,50 +16,56 @@ export type AndroidSecurityLevelName = 'SOFTWARE' | 'TRUSTED_ENVIRONMENT' | 'STR
|
|
|
16
16
|
export type IOSSecurityLevelName = 'SOFTWARE' | 'SECURE_ENCLAVE';
|
|
17
17
|
|
|
18
18
|
export type DPoPKeyInfo = {
|
|
19
|
-
alias: string;
|
|
20
|
-
hasKeyPair: boolean;
|
|
21
19
|
algorithm?: string;
|
|
20
|
+
alias: string;
|
|
22
21
|
curve?: string;
|
|
23
|
-
insideSecureHardware?: boolean;
|
|
24
22
|
hardware?: {
|
|
25
23
|
android?: {
|
|
26
|
-
strongBoxAvailable: boolean;
|
|
27
|
-
strongBoxBacked: boolean;
|
|
28
24
|
securityLevel?: number;
|
|
29
25
|
securityLevelName?: AndroidSecurityLevelName;
|
|
26
|
+
strongBoxAvailable: boolean;
|
|
27
|
+
strongBoxBacked: boolean;
|
|
30
28
|
strongBoxFallbackReason?: SecureHardwareFallbackReason | null;
|
|
31
29
|
};
|
|
32
30
|
ios?: {
|
|
33
31
|
secureEnclaveAvailable: boolean;
|
|
34
32
|
secureEnclaveBacked: boolean;
|
|
33
|
+
secureEnclaveFallbackReason?: SecureHardwareFallbackReason | null;
|
|
35
34
|
securityLevel?: number | null;
|
|
36
35
|
securityLevelName?: IOSSecurityLevelName;
|
|
37
|
-
secureEnclaveFallbackReason?: SecureHardwareFallbackReason | null;
|
|
38
36
|
};
|
|
39
37
|
};
|
|
38
|
+
hasKeyPair: boolean;
|
|
39
|
+
insideSecureHardware?: boolean;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
export type GenerateProofInput = {
|
|
43
|
-
htu: string;
|
|
44
|
-
htm: string;
|
|
45
|
-
nonce?: string;
|
|
46
43
|
accessToken?: string;
|
|
47
44
|
additional?: AdditionalClaims;
|
|
48
|
-
kid?: string;
|
|
49
|
-
jti?: string;
|
|
50
|
-
iat?: number;
|
|
51
45
|
alias?: string;
|
|
46
|
+
htm: string;
|
|
47
|
+
htu: string;
|
|
48
|
+
iat?: number;
|
|
49
|
+
jti?: string;
|
|
50
|
+
kid?: string;
|
|
51
|
+
nonce?: string;
|
|
52
|
+
requireHardwareBacked?: boolean;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type DPoPHeaders = {
|
|
56
|
+
Authorization?: string;
|
|
57
|
+
DPoP: string;
|
|
52
58
|
};
|
|
53
59
|
|
|
54
60
|
export type DPoPProofContext = {
|
|
55
|
-
htu: string;
|
|
56
|
-
htm: string;
|
|
57
|
-
nonce: string | null;
|
|
58
|
-
ath: string | null;
|
|
59
61
|
additional: AdditionalClaims | null;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
ath: string | null;
|
|
63
|
+
htm: string;
|
|
64
|
+
htu: string;
|
|
62
65
|
iat: number;
|
|
66
|
+
jti: string;
|
|
67
|
+
kid: string | null;
|
|
68
|
+
nonce: string | null;
|
|
63
69
|
};
|
|
64
70
|
|
|
65
71
|
type GenerateProofResult = {
|
|
@@ -68,8 +74,8 @@ type GenerateProofResult = {
|
|
|
68
74
|
};
|
|
69
75
|
|
|
70
76
|
export class DPoP {
|
|
71
|
-
public readonly proof: string;
|
|
72
77
|
public readonly alias: string | undefined;
|
|
78
|
+
public readonly proof: string;
|
|
73
79
|
public readonly proofContext: DPoPProofContext;
|
|
74
80
|
|
|
75
81
|
private constructor(proof: string, proofContext: DPoPProofContext, alias?: string) {
|
|
@@ -78,27 +84,21 @@ export class DPoP {
|
|
|
78
84
|
this.alias = alias;
|
|
79
85
|
}
|
|
80
86
|
|
|
81
|
-
public async
|
|
82
|
-
|
|
87
|
+
public static async assertHardwareBacked(alias?: string): Promise<void> {
|
|
88
|
+
await NativeReactNativeDPoP.assertHardwareBacked(alias ?? null);
|
|
83
89
|
}
|
|
84
90
|
|
|
85
|
-
public async
|
|
86
|
-
|
|
87
|
-
return NativeReactNativeDPoP.getPublicKeyDer(this.alias ?? null);
|
|
88
|
-
}
|
|
89
|
-
if (format === 'RAW') {
|
|
90
|
-
return NativeReactNativeDPoP.getPublicKeyRaw(this.alias ?? null);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return NativeReactNativeDPoP.getPublicKeyJwk(this.alias ?? null) as Promise<PublicJwk>;
|
|
94
|
-
}
|
|
91
|
+
public static async buildDPoPHeaders(input: GenerateProofInput): Promise<DPoPHeaders> {
|
|
92
|
+
const dPoP = await DPoP.generateProof(input);
|
|
95
93
|
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
return {
|
|
95
|
+
DPoP: dPoP.proof,
|
|
96
|
+
...(input.accessToken ? { Authorization: `DPoP ${input.accessToken}` } : {}),
|
|
97
|
+
};
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
public async
|
|
101
|
-
|
|
100
|
+
public static async deleteKeyPair(alias?: string): Promise<void> {
|
|
101
|
+
await NativeReactNativeDPoP.deleteKeyPair(alias ?? null);
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
public static async generateProof(input: GenerateProofInput): Promise<DPoP> {
|
|
@@ -112,20 +112,13 @@ export class DPoP {
|
|
|
112
112
|
input.jti ?? null,
|
|
113
113
|
// RN 0.75 Android bridge can crash when a nullable Double arrives as null.
|
|
114
114
|
input.iat ?? Math.floor(Date.now() / 1000),
|
|
115
|
-
input.alias ?? null
|
|
115
|
+
input.alias ?? null,
|
|
116
|
+
input.requireHardwareBacked ?? false
|
|
116
117
|
)) as GenerateProofResult;
|
|
117
118
|
|
|
118
119
|
return new DPoP(result.proof, result.proofContext, input.alias);
|
|
119
120
|
}
|
|
120
121
|
|
|
121
|
-
public static async assertHardwareBacked(alias?: string): Promise<void> {
|
|
122
|
-
await NativeReactNativeDPoP.assertHardwareBacked(alias ?? null);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
public static async deleteKeyPair(alias?: string): Promise<void> {
|
|
126
|
-
await NativeReactNativeDPoP.deleteKeyPair(alias ?? null);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
122
|
public static async getKeyInfo(alias?: string): Promise<DPoPKeyInfo> {
|
|
130
123
|
return NativeReactNativeDPoP.getKeyInfo(alias ?? null) as Promise<DPoPKeyInfo>;
|
|
131
124
|
}
|
|
@@ -137,4 +130,27 @@ export class DPoP {
|
|
|
137
130
|
public static async rotateKeyPair(alias?: string): Promise<void> {
|
|
138
131
|
await NativeReactNativeDPoP.rotateKeyPair(alias ?? null);
|
|
139
132
|
}
|
|
133
|
+
|
|
134
|
+
public async getPublicKey(format: PublicKeyFormat): Promise<PublicJwk | string> {
|
|
135
|
+
if (format === 'DER') {
|
|
136
|
+
return NativeReactNativeDPoP.getPublicKeyDer(this.alias ?? null);
|
|
137
|
+
}
|
|
138
|
+
if (format === 'RAW') {
|
|
139
|
+
return NativeReactNativeDPoP.getPublicKeyRaw(this.alias ?? null);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return NativeReactNativeDPoP.getPublicKeyJwk(this.alias ?? null) as Promise<PublicJwk>;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public async getPublicKeyThumbprint(): Promise<string> {
|
|
146
|
+
return NativeReactNativeDPoP.getPublicKeyThumbprint(this.alias ?? null);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public async isBoundToAlias(alias?: string): Promise<boolean> {
|
|
150
|
+
return NativeReactNativeDPoP.isBoundToAlias(this.proof, alias ?? this.alias ?? null);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public async signWithDPoPPrivateKey(payload: string): Promise<string> {
|
|
154
|
+
return NativeReactNativeDPoP.signWithDPoPPrivateKey(payload, this.alias ?? null);
|
|
155
|
+
}
|
|
140
156
|
}
|