react-native-dpop 0.1.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.
@@ -0,0 +1,302 @@
1
+ package com.dpop
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.Promise
5
+ import com.facebook.react.bridge.ReadableMap
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import java.security.Signature
8
+ import java.util.UUID
9
+ import org.json.JSONObject
10
+
11
+ class DpopModule(reactContext: ReactApplicationContext) :
12
+ NativeDpopSpec(reactContext) {
13
+ private val keyStore = DPoPKeyStore(reactContext)
14
+
15
+ private fun resolveAlias(alias: String?): String {
16
+ return alias ?: DEFAULT_ALIAS
17
+ }
18
+
19
+ override fun assertHardwareBacked(alias: String?, promise: Promise) {
20
+ try {
21
+ val effectiveAlias = resolveAlias(alias)
22
+ if (!keyStore.hasKeyPair(effectiveAlias)) {
23
+ promise.reject("ERR_DPOP_ASSERT_HARDWARE_BACKED", "Key pair not found for alias: $effectiveAlias")
24
+ return
25
+ }
26
+
27
+ if (!keyStore.isHardwareBacked(effectiveAlias)) {
28
+ promise.reject("ERR_DPOP_ASSERT_HARDWARE_BACKED", "Key pair is not hardware-backed for alias: $effectiveAlias")
29
+ return
30
+ }
31
+
32
+ promise.resolve(null)
33
+ } catch (e: Exception) {
34
+ promise.reject("ERR_DPOP_ASSERT_HARDWARE_BACKED", e.message, e)
35
+ }
36
+ }
37
+
38
+ override fun calculateThumbprint(alias: String?, promise: Promise) {
39
+ try {
40
+ val effectiveAlias = resolveAlias(alias)
41
+ if (!keyStore.hasKeyPair(effectiveAlias)) {
42
+ keyStore.generateKeyPair(effectiveAlias)
43
+ }
44
+
45
+ val keyPair = keyStore.getKeyPair(effectiveAlias)
46
+ val coordinates = DPoPUtils.getPublicCoordinates(keyPair.publicKey)
47
+ val thumbprint = DPoPUtils.calculateThumbprint(
48
+ kty = "EC",
49
+ crv = "P-256",
50
+ x = coordinates.first,
51
+ y = coordinates.second
52
+ )
53
+ promise.resolve(thumbprint)
54
+ } catch (e: Exception) {
55
+ promise.reject("ERR_DPOP_CALCULATE_THUMBPRINT", e.message, e)
56
+ }
57
+ }
58
+
59
+ override fun deleteKeyPair(alias: String?, promise: Promise) {
60
+ try {
61
+ val effectiveAlias = resolveAlias(alias)
62
+ keyStore.deleteKeyPair(effectiveAlias)
63
+ promise.resolve(null)
64
+ } catch (e: Exception) {
65
+ promise.reject("ERR_DPOP_DELETE_KEY_PAIR", e.message, e)
66
+ }
67
+ }
68
+
69
+ override fun getKeyInfo(alias: String?, promise: Promise) {
70
+ try {
71
+ val effectiveAlias = resolveAlias(alias)
72
+ if (!keyStore.hasKeyPair(effectiveAlias)) {
73
+ val result = Arguments.createMap().apply {
74
+ putString("alias", effectiveAlias)
75
+ putBoolean("hasKeyPair", false)
76
+ }
77
+ promise.resolve(result)
78
+ return
79
+ }
80
+
81
+ val keyInfo = keyStore.getKeyInfo(effectiveAlias)
82
+ val result = Arguments.createMap().apply {
83
+ putString("alias", keyInfo.alias)
84
+ putString("algorithm", keyInfo.algorithm)
85
+ putString("curve", keyInfo.curve)
86
+ putBoolean("hasKeyPair", true)
87
+ 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
+ }
93
+ }
94
+ promise.resolve(result)
95
+ } catch (e: Exception) {
96
+ promise.reject("ERR_DPOP_GET_KEY_INFO", e.message, e)
97
+ }
98
+ }
99
+
100
+ override fun getPublicKeyDer(alias: String?, promise: Promise) {
101
+ try {
102
+ val effectiveAlias = resolveAlias(alias)
103
+ if (!keyStore.hasKeyPair(effectiveAlias)) {
104
+ keyStore.generateKeyPair(effectiveAlias)
105
+ }
106
+
107
+ val keyPair = keyStore.getKeyPair(effectiveAlias)
108
+ promise.resolve(DPoPUtils.base64UrlEncode(keyPair.publicKey.encoded))
109
+ } catch (e: Exception) {
110
+ promise.reject("ERR_DPOP_PUBLIC_KEY", e.message, e)
111
+ }
112
+ }
113
+
114
+ override fun getPublicKeyJwk(alias: String?, promise: Promise) {
115
+ try {
116
+ val effectiveAlias = resolveAlias(alias)
117
+ if (!keyStore.hasKeyPair(effectiveAlias)) {
118
+ keyStore.generateKeyPair(effectiveAlias)
119
+ }
120
+
121
+ val keyPair = keyStore.getKeyPair(effectiveAlias)
122
+ val coordinates = DPoPUtils.getPublicCoordinates(keyPair.publicKey)
123
+ val jwk = Arguments.createMap().apply {
124
+ putString("kty", "EC")
125
+ putString("crv", "P-256")
126
+ putString("x", coordinates.first)
127
+ putString("y", coordinates.second)
128
+ }
129
+ promise.resolve(jwk)
130
+ } catch (e: Exception) {
131
+ promise.reject("ERR_DPOP_PUBLIC_KEY", e.message, e)
132
+ }
133
+ }
134
+
135
+ override fun getPublicKeyRaw(alias: String?, promise: Promise) {
136
+ try {
137
+ val effectiveAlias = resolveAlias(alias)
138
+ if (!keyStore.hasKeyPair(effectiveAlias)) {
139
+ keyStore.generateKeyPair(effectiveAlias)
140
+ }
141
+
142
+ val keyPair = keyStore.getKeyPair(effectiveAlias)
143
+ val raw = DPoPUtils.toRawPublicKey(keyPair.publicKey)
144
+ promise.resolve(DPoPUtils.base64UrlEncode(raw))
145
+ } catch (e: Exception) {
146
+ promise.reject("ERR_DPOP_PUBLIC_KEY", e.message, e)
147
+ }
148
+ }
149
+
150
+ override fun hasKeyPair(alias: String?, promise: Promise) {
151
+ try {
152
+ val effectiveAlias = resolveAlias(alias)
153
+ promise.resolve(keyStore.hasKeyPair(effectiveAlias))
154
+ } catch (e: Exception) {
155
+ promise.reject("ERR_DPOP_HAS_KEY_PAIR", e.message, e)
156
+ }
157
+ }
158
+
159
+ override fun isBoundToAlias(proof: String, alias: String?, promise: Promise) {
160
+ try {
161
+ val effectiveAlias = resolveAlias(alias)
162
+ if (!keyStore.hasKeyPair(effectiveAlias)) {
163
+ keyStore.generateKeyPair(effectiveAlias)
164
+ }
165
+
166
+ val keyPair = keyStore.getKeyPair(effectiveAlias)
167
+ promise.resolve(DPoPUtils.isProofBoundToPublicKey(proof, keyPair.publicKey))
168
+ } catch (e: Exception) {
169
+ promise.reject("ERR_DPOP_IS_BOUND_TO_ALIAS", e.message, e)
170
+ }
171
+ }
172
+
173
+ override fun rotateKeyPair(alias: String?, promise: Promise) {
174
+ try {
175
+ val effectiveAlias = resolveAlias(alias)
176
+ keyStore.generateKeyPair(effectiveAlias)
177
+ promise.resolve(null)
178
+ } catch (e: Exception) {
179
+ promise.reject("ERR_DPOP_ROTATE_KEY_PAIR", e.message, e)
180
+ }
181
+ }
182
+
183
+ override fun signWithDpopPrivateKey(payload: String, alias: String?, promise: Promise) {
184
+ try {
185
+ val effectiveAlias = resolveAlias(alias)
186
+ if (!keyStore.hasKeyPair(effectiveAlias)) {
187
+ keyStore.generateKeyPair(effectiveAlias)
188
+ }
189
+
190
+ val keyPair = keyStore.getKeyPair(effectiveAlias)
191
+ val signature = Signature.getInstance("SHA256withECDSA").apply {
192
+ initSign(keyPair.privateKey)
193
+ update(payload.toByteArray(Charsets.UTF_8))
194
+ }
195
+ val joseSignature = DPoPUtils.derToJose(signature.sign(), partLength = 32)
196
+ promise.resolve(DPoPUtils.base64UrlEncode(joseSignature))
197
+ } catch (e: Exception) {
198
+ promise.reject("ERR_DPOP_SIGN_WITH_PRIVATE_KEY", e.message, e)
199
+ }
200
+ }
201
+
202
+ override fun generateProof(
203
+ htu: String,
204
+ htm: String,
205
+ nonce: String?,
206
+ accessToken: String?,
207
+ additional: ReadableMap?,
208
+ kid: String?,
209
+ jti: String?,
210
+ iat: Double?,
211
+ alias: String?,
212
+ promise: Promise
213
+ ) {
214
+ try {
215
+ val effectiveAlias = resolveAlias(alias)
216
+ if (!keyStore.hasKeyPair(effectiveAlias)) {
217
+ keyStore.generateKeyPair(effectiveAlias)
218
+ }
219
+
220
+ val keyPair = keyStore.getKeyPair(effectiveAlias)
221
+ val coordinates = DPoPUtils.getPublicCoordinates(keyPair.publicKey)
222
+ val jwk = JSONObject().apply {
223
+ put("kty", "EC")
224
+ put("crv", "P-256")
225
+ put("x", coordinates.first)
226
+ put("y", coordinates.second)
227
+ }
228
+
229
+ val header = JSONObject().apply {
230
+ put("typ", "dpop+jwt")
231
+ put("alg", "ES256")
232
+ put("jwk", jwk)
233
+ if (!kid.isNullOrBlank()) {
234
+ put("kid", kid)
235
+ }
236
+ }
237
+
238
+ val payload = JSONObject().apply {
239
+ put("jti", if (jti.isNullOrBlank()) UUID.randomUUID().toString() else jti)
240
+ put("htm", htm.uppercase())
241
+ put("htu", htu)
242
+ put("iat", iat?.toLong() ?: (System.currentTimeMillis() / 1000L))
243
+ }
244
+
245
+ if (!nonce.isNullOrBlank()) {
246
+ payload.put("nonce", nonce)
247
+ }
248
+
249
+ if (!accessToken.isNullOrBlank()) {
250
+ payload.put("ath", DPoPUtils.hashAccessToken(accessToken))
251
+ }
252
+
253
+ if (additional != null) {
254
+ val additionalJson = DPoPUtils.toJsonObject(additional)
255
+ val keys = additionalJson.keys()
256
+ while (keys.hasNext()) {
257
+ val key = keys.next()
258
+ payload.put(key, additionalJson.get(key))
259
+ }
260
+ }
261
+
262
+ val headerSegment = DPoPUtils.base64UrlEncode(header.toString().toByteArray(Charsets.UTF_8))
263
+ val payloadSegment = DPoPUtils.base64UrlEncode(payload.toString().toByteArray(Charsets.UTF_8))
264
+ val signingInput = "$headerSegment.$payloadSegment"
265
+
266
+ val signature = Signature.getInstance("SHA256withECDSA").apply {
267
+ initSign(keyPair.privateKey)
268
+ update(signingInput.toByteArray(Charsets.UTF_8))
269
+ }
270
+ val joseSignature = DPoPUtils.derToJose(signature.sign(), partLength = 32)
271
+ val jwt = "$signingInput.${DPoPUtils.base64UrlEncode(joseSignature)}"
272
+
273
+ val proofContext = Arguments.createMap().apply {
274
+ putString("htu", payload.optString("htu"))
275
+ putString("htm", payload.optString("htm"))
276
+ putString("nonce", if (payload.has("nonce")) payload.optString("nonce") else null)
277
+ putString("ath", if (payload.has("ath")) payload.optString("ath") else null)
278
+ putString("kid", if (header.has("kid")) header.optString("kid") else null)
279
+ putString("jti", payload.optString("jti"))
280
+ putDouble("iat", payload.optLong("iat").toDouble())
281
+ if (additional != null) {
282
+ putMap("additional", DPoPUtils.readableMapToWritableMap(additional))
283
+ } else {
284
+ putNull("additional")
285
+ }
286
+ }
287
+
288
+ val result = Arguments.createMap().apply {
289
+ putString("proof", jwt)
290
+ putMap("proofContext", proofContext)
291
+ }
292
+ promise.resolve(result)
293
+ } catch (e: Exception) {
294
+ promise.reject("ERR_DPOP_GENERATE_PROOF", e.message, e)
295
+ }
296
+ }
297
+
298
+ companion object {
299
+ private const val DEFAULT_ALIAS = "react-native-dpop"
300
+ const val NAME = NativeDpopSpec.NAME
301
+ }
302
+ }
@@ -0,0 +1,31 @@
1
+ package com.dpop
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
8
+ import java.util.HashMap
9
+
10
+ class DpopPackage : BaseReactPackage() {
11
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
12
+ return if (name == DpopModule.NAME) {
13
+ DpopModule(reactContext)
14
+ } else {
15
+ null
16
+ }
17
+ }
18
+
19
+ override fun getReactModuleInfoProvider() = ReactModuleInfoProvider {
20
+ mapOf(
21
+ DpopModule.NAME to ReactModuleInfo(
22
+ name = DpopModule.NAME,
23
+ className = DpopModule.NAME,
24
+ canOverrideExistingModule = false,
25
+ needsEagerInit = false,
26
+ isCxxModule = false,
27
+ isTurboModule = true
28
+ )
29
+ )
30
+ }
31
+ }
package/ios/Dpop.h ADDED
@@ -0,0 +1,5 @@
1
+ #import <DpopSpec/DpopSpec.h>
2
+
3
+ @interface Dpop : NSObject <NativeDpopSpec>
4
+
5
+ @end
package/ios/Dpop.mm ADDED
@@ -0,0 +1,21 @@
1
+ #import "Dpop.h"
2
+
3
+ @implementation Dpop
4
+ - (NSNumber *)multiply:(double)a b:(double)b {
5
+ NSNumber *result = @(a * b);
6
+
7
+ return result;
8
+ }
9
+
10
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
11
+ (const facebook::react::ObjCTurboModule::InitParams &)params
12
+ {
13
+ return std::make_shared<facebook::react::NativeDpopSpecJSI>(params);
14
+ }
15
+
16
+ + (NSString *)moduleName
17
+ {
18
+ return @"Dpop";
19
+ }
20
+
21
+ @end
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ import { TurboModuleRegistry } from 'react-native';
4
+ export default TurboModuleRegistry.getEnforcing('Dpop');
5
+ //# sourceMappingURL=NativeDpop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeDpop.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AA4BlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,MAAM,CAAC","ignoreList":[]}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+
3
+ import { Platform } from 'react-native';
4
+ import Dpop from "./NativeDpop.js";
5
+ const LINKING_ERROR = 'Dpop module nao encontrado. Verifique se o app Android foi recompilado apos adicionar o modulo nativo.';
6
+ function requireAndroid() {
7
+ if (Platform.OS !== 'android') {
8
+ throw new Error('react-native-dpop (MVP atual) suporta somente Android.');
9
+ }
10
+ if (!Dpop) {
11
+ throw new Error(LINKING_ERROR);
12
+ }
13
+ }
14
+ export class DPoP {
15
+ constructor(proof, proofContext, alias) {
16
+ this.proof = proof;
17
+ this.proofContext = proofContext;
18
+ this.alias = alias;
19
+ }
20
+ async calculateThumbprint() {
21
+ requireAndroid();
22
+ return Dpop.calculateThumbprint(this.alias ?? null);
23
+ }
24
+ async getPublicKey(format) {
25
+ requireAndroid();
26
+ if (format === 'DER') {
27
+ return Dpop.getPublicKeyDer(this.alias ?? null);
28
+ }
29
+ if (format === 'RAW') {
30
+ return Dpop.getPublicKeyRaw(this.alias ?? null);
31
+ }
32
+ return Dpop.getPublicKeyJwk(this.alias ?? null);
33
+ }
34
+ async signWithDpopPrivateKey(payload) {
35
+ requireAndroid();
36
+ return Dpop.signWithDpopPrivateKey(payload, this.alias ?? null);
37
+ }
38
+ async isBoundToAlias(alias) {
39
+ requireAndroid();
40
+ return Dpop.isBoundToAlias(this.proof, alias ?? this.alias ?? null);
41
+ }
42
+ static async generateProof(input) {
43
+ requireAndroid();
44
+ const result = await Dpop.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);
45
+ return new DPoP(result.proof, result.proofContext, input.alias);
46
+ }
47
+ static async assertHardwareBacked(alias) {
48
+ requireAndroid();
49
+ await Dpop.assertHardwareBacked(alias ?? null);
50
+ }
51
+ static async deleteKeyPair(alias) {
52
+ requireAndroid();
53
+ await Dpop.deleteKeyPair(alias ?? null);
54
+ }
55
+ static async getKeyInfo(alias) {
56
+ requireAndroid();
57
+ return Dpop.getKeyInfo(alias ?? null);
58
+ }
59
+ static async hasKeyPair(alias) {
60
+ requireAndroid();
61
+ return Dpop.hasKeyPair(alias ?? null);
62
+ }
63
+ static async rotateKeyPair(alias) {
64
+ requireAndroid();
65
+ await Dpop.rotateKeyPair(alias ?? null);
66
+ }
67
+ }
68
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Platform","Dpop","LINKING_ERROR","requireAndroid","OS","Error","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":"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","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,19 @@
1
+ import type { TurboModule } from 'react-native';
2
+ import type { UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
3
+ export interface Spec extends TurboModule {
4
+ assertHardwareBacked(alias: string | null): Promise<void>;
5
+ calculateThumbprint(alias: string | null): Promise<string>;
6
+ deleteKeyPair(alias: string | null): Promise<void>;
7
+ getKeyInfo(alias: string | null): Promise<UnsafeObject>;
8
+ getPublicKeyDer(alias: string | null): Promise<string>;
9
+ getPublicKeyJwk(alias: string | null): Promise<UnsafeObject>;
10
+ getPublicKeyRaw(alias: string | null): Promise<string>;
11
+ hasKeyPair(alias: string | null): Promise<boolean>;
12
+ isBoundToAlias(proof: string, alias: string | null): Promise<boolean>;
13
+ rotateKeyPair(alias: string | null): Promise<void>;
14
+ signWithDpopPrivateKey(payload: string, alias: string | null): Promise<string>;
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>;
16
+ }
17
+ declare const _default: Spec;
18
+ export default _default;
19
+ //# sourceMappingURL=NativeDpop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeDpop.d.ts","sourceRoot":"","sources":["../../../src/NativeDpop.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;;AAED,wBAA8D"}
@@ -0,0 +1,57 @@
1
+ type AdditionalClaims = Record<string, unknown>;
2
+ export type PublicJwk = {
3
+ kty: 'EC';
4
+ crv: 'P-256';
5
+ x: string;
6
+ y: string;
7
+ };
8
+ export type PublicKeyFormat = 'JWK' | 'DER' | 'RAW';
9
+ export type DPoPKeyInfo = {
10
+ alias: string;
11
+ hasKeyPair: boolean;
12
+ algorithm?: string;
13
+ curve?: string;
14
+ insideSecureHardware?: boolean;
15
+ securityLevel?: number;
16
+ strongBoxAvailable?: boolean;
17
+ strongBoxBacked?: boolean;
18
+ };
19
+ export type GenerateProofInput = {
20
+ htu: string;
21
+ htm: string;
22
+ nonce?: string;
23
+ accessToken?: string;
24
+ additional?: AdditionalClaims;
25
+ kid?: string;
26
+ jti?: string;
27
+ iat?: number;
28
+ alias?: string;
29
+ };
30
+ export type DPoPProofContext = {
31
+ htu: string;
32
+ htm: string;
33
+ nonce: string | null;
34
+ ath: string | null;
35
+ additional: AdditionalClaims | null;
36
+ kid: string | null;
37
+ jti: string;
38
+ iat: number;
39
+ };
40
+ export declare class DPoP {
41
+ readonly proof: string;
42
+ readonly alias?: string;
43
+ readonly proofContext: DPoPProofContext;
44
+ private constructor();
45
+ calculateThumbprint(): Promise<string>;
46
+ getPublicKey(format: PublicKeyFormat): Promise<PublicJwk | string>;
47
+ signWithDpopPrivateKey(payload: string): Promise<string>;
48
+ isBoundToAlias(alias?: string): Promise<boolean>;
49
+ static generateProof(input: GenerateProofInput): Promise<DPoP>;
50
+ static assertHardwareBacked(alias?: string): Promise<void>;
51
+ static deleteKeyPair(alias?: string): Promise<void>;
52
+ static getKeyInfo(alias?: string): Promise<DPoPKeyInfo>;
53
+ static hasKeyPair(alias?: string): Promise<boolean>;
54
+ static rotateKeyPair(alias?: string): Promise<void>;
55
+ }
56
+ export {};
57
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAGA,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;AAmBF,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;IAKtC,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC;IAYlE,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKxD,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAKzC,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;WAiBvD,oBAAoB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAKnD,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAK5C,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;WAKhD,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAK5C,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAIjE"}
package/package.json ADDED
@@ -0,0 +1,120 @@
1
+ {
2
+ "name": "react-native-dpop",
3
+ "version": "0.1.0",
4
+ "description": "React Native library for DPoP proof generation and key management.",
5
+ "keywords": [
6
+ "android",
7
+ "ios",
8
+ "react-native"
9
+ ],
10
+ "homepage": "https://github.com/Cirilord/react-native-dpop#readme",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/Cirilord/react-native-dpop.git"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/Cirilord/react-native-dpop/issues"
17
+ },
18
+ "license": "MIT",
19
+ "author": "Pedro Cirilo <phscirilo123@gmail.com> (https://github.com/Cirilord)",
20
+ "main": "./lib/module/index.js",
21
+ "types": "./lib/typescript/src/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "source": "./src/index.tsx",
25
+ "types": "./lib/typescript/src/index.d.ts",
26
+ "default": "./lib/module/index.js"
27
+ },
28
+ "./package.json": "./package.json"
29
+ },
30
+ "files": [
31
+ "src",
32
+ "lib",
33
+ "android",
34
+ "ios",
35
+ "cpp",
36
+ "*.podspec",
37
+ "react-native.config.js",
38
+ "!ios/build",
39
+ "!android/build",
40
+ "!android/gradle",
41
+ "!android/gradlew",
42
+ "!android/gradlew.bat",
43
+ "!android/local.properties",
44
+ "!**/__tests__",
45
+ "!**/__fixtures__",
46
+ "!**/__mocks__",
47
+ "!**/.*"
48
+ ],
49
+ "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",
52
+ "lint": "eslint \"**/*.{js,ts,tsx}\"",
53
+ "prepare": "bob build",
54
+ "release": "release-it --only-version",
55
+ "test": "jest",
56
+ "typecheck": "tsc"
57
+ },
58
+ "publishConfig": {
59
+ "registry": "https://registry.npmjs.org/"
60
+ },
61
+ "peerDependencies": {
62
+ "react": "*",
63
+ "react-native": "*"
64
+ },
65
+ "devDependencies": {
66
+ "@commitlint/config-conventional": "^19.8.1",
67
+ "@eslint/compat": "^1.3.2",
68
+ "@eslint/eslintrc": "^3.3.1",
69
+ "@eslint/js": "^9.35.0",
70
+ "@react-native/babel-preset": "0.83.0",
71
+ "@react-native/eslint-config": "0.83.0",
72
+ "@release-it/conventional-changelog": "^10.0.1",
73
+ "@types/jest": "^29.5.14",
74
+ "@types/react": "^19.2.0",
75
+ "commitlint": "^19.8.1",
76
+ "del-cli": "^6.0.0",
77
+ "eslint": "^9.35.0",
78
+ "eslint-config-prettier": "^10.1.8",
79
+ "eslint-plugin-prettier": "^5.5.4",
80
+ "jest": "^29.7.0",
81
+ "lefthook": "^2.0.3",
82
+ "prettier": "^2.8.8",
83
+ "react": "19.2.0",
84
+ "react-native": "0.83.0",
85
+ "react-native-builder-bob": "^0.40.18",
86
+ "release-it": "^19.0.4",
87
+ "turbo": "^2.5.6",
88
+ "typescript": "^5.9.2"
89
+ },
90
+ "workspaces": [
91
+ "example"
92
+ ],
93
+ "packageManager": "yarn@4.11.0",
94
+ "react-native-builder-bob": {
95
+ "source": "src",
96
+ "output": "lib",
97
+ "targets": [
98
+ [
99
+ "module",
100
+ {
101
+ "esm": true
102
+ }
103
+ ],
104
+ [
105
+ "typescript",
106
+ {
107
+ "project": "tsconfig.build.json"
108
+ }
109
+ ]
110
+ ]
111
+ },
112
+ "codegenConfig": {
113
+ "name": "DpopSpec",
114
+ "type": "modules",
115
+ "jsSrcsDir": "src",
116
+ "android": {
117
+ "javaPackageName": "com.dpop"
118
+ }
119
+ }
120
+ }