@pagopa/io-react-native-wallet 0.7.4 → 0.9.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 +49 -31
- package/lib/commonjs/credential/index.js +13 -0
- package/lib/commonjs/credential/index.js.map +1 -0
- package/lib/commonjs/credential/issuance/01-start-flow.js +2 -0
- package/lib/commonjs/credential/issuance/01-start-flow.js.map +1 -0
- package/lib/commonjs/credential/issuance/02-evaluate-issuer-trust.js +26 -0
- package/lib/commonjs/credential/issuance/02-evaluate-issuer-trust.js.map +1 -0
- package/lib/commonjs/credential/issuance/03-start-user-authorization.js +119 -0
- package/lib/commonjs/credential/issuance/03-start-user-authorization.js.map +1 -0
- package/lib/commonjs/credential/issuance/04-complete-user-authorization.js +6 -0
- package/lib/commonjs/credential/issuance/04-complete-user-authorization.js.map +1 -0
- package/lib/commonjs/credential/issuance/05-authorize-access.js +63 -0
- package/lib/commonjs/credential/issuance/05-authorize-access.js.map +1 -0
- package/lib/commonjs/credential/issuance/06-obtain-credential.js +128 -0
- package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -0
- package/lib/commonjs/credential/issuance/07-confirm-credential.js +6 -0
- package/lib/commonjs/credential/issuance/07-confirm-credential.js.map +1 -0
- package/lib/commonjs/credential/issuance/const.js +9 -0
- package/lib/commonjs/credential/issuance/const.js.map +1 -0
- package/lib/commonjs/credential/issuance/index.js +34 -0
- package/lib/commonjs/credential/issuance/index.js.map +1 -0
- package/lib/commonjs/credential/presentation/01-start-flow.js +55 -0
- package/lib/commonjs/credential/presentation/01-start-flow.js.map +1 -0
- package/lib/commonjs/credential/presentation/02-evaluate-rp-trust.js +32 -0
- package/lib/commonjs/credential/presentation/02-evaluate-rp-trust.js.map +1 -0
- package/lib/commonjs/credential/presentation/03-get-request-object.js +68 -0
- package/lib/commonjs/credential/presentation/03-get-request-object.js.map +1 -0
- package/lib/commonjs/credential/presentation/04-send-authorization-response.js +139 -0
- package/lib/commonjs/credential/presentation/04-send-authorization-response.js.map +1 -0
- package/lib/commonjs/credential/presentation/index.js +34 -0
- package/lib/commonjs/credential/presentation/index.js.map +1 -0
- package/lib/commonjs/{rp → credential/presentation}/types.js +17 -34
- package/lib/commonjs/credential/presentation/types.js.map +1 -0
- package/lib/commonjs/index.js +10 -61
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/pid/index.js +1 -3
- package/lib/commonjs/pid/index.js.map +1 -1
- package/lib/commonjs/sd-jwt/index.js +1 -1
- package/lib/commonjs/sd-jwt/index.js.map +1 -1
- package/lib/commonjs/sd-jwt/types.js +1 -1
- package/lib/commonjs/sd-jwt/types.js.map +1 -1
- package/lib/commonjs/trust/chain.js +32 -4
- package/lib/commonjs/trust/chain.js.map +1 -1
- package/lib/commonjs/trust/index.js +105 -20
- package/lib/commonjs/trust/index.js.map +1 -1
- package/lib/commonjs/trust/types.js +54 -35
- package/lib/commonjs/trust/types.js.map +1 -1
- package/lib/commonjs/utils/crypto.js +5 -18
- package/lib/commonjs/utils/crypto.js.map +1 -1
- package/lib/commonjs/utils/misc.js +23 -0
- package/lib/commonjs/utils/misc.js.map +1 -0
- package/lib/commonjs/utils/par.js +86 -0
- package/lib/commonjs/utils/par.js.map +1 -0
- package/lib/module/credential/index.js +4 -0
- package/lib/module/credential/index.js.map +1 -0
- package/lib/module/credential/issuance/01-start-flow.js +2 -0
- package/lib/module/credential/issuance/01-start-flow.js.map +1 -0
- package/lib/module/credential/issuance/02-evaluate-issuer-trust.js +19 -0
- package/lib/module/credential/issuance/02-evaluate-issuer-trust.js.map +1 -0
- package/lib/module/credential/issuance/03-start-user-authorization.js +109 -0
- package/lib/module/credential/issuance/03-start-user-authorization.js.map +1 -0
- package/lib/module/credential/issuance/04-complete-user-authorization.js +2 -0
- package/lib/module/credential/issuance/04-complete-user-authorization.js.map +1 -0
- package/lib/module/credential/issuance/05-authorize-access.js +55 -0
- package/lib/module/credential/issuance/05-authorize-access.js.map +1 -0
- package/lib/module/credential/issuance/06-obtain-credential.js +117 -0
- package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -0
- package/lib/module/credential/issuance/07-confirm-credential.js +2 -0
- package/lib/module/credential/issuance/07-confirm-credential.js.map +1 -0
- package/lib/module/credential/issuance/const.js +2 -0
- package/lib/module/credential/issuance/const.js.map +1 -0
- package/lib/module/credential/issuance/index.js +6 -0
- package/lib/module/credential/issuance/index.js.map +1 -0
- package/lib/module/credential/presentation/01-start-flow.js +46 -0
- package/lib/module/credential/presentation/01-start-flow.js.map +1 -0
- package/lib/module/credential/presentation/02-evaluate-rp-trust.js +25 -0
- package/lib/module/credential/presentation/02-evaluate-rp-trust.js.map +1 -0
- package/lib/module/credential/presentation/03-get-request-object.js +60 -0
- package/lib/module/credential/presentation/03-get-request-object.js.map +1 -0
- package/lib/module/credential/presentation/04-send-authorization-response.js +128 -0
- package/lib/module/credential/presentation/04-send-authorization-response.js.map +1 -0
- package/lib/module/credential/presentation/index.js +6 -0
- package/lib/module/credential/presentation/index.js.map +1 -0
- package/lib/module/credential/presentation/types.js +21 -0
- package/lib/module/credential/presentation/types.js.map +1 -0
- package/lib/module/index.js +4 -5
- package/lib/module/index.js.map +1 -1
- package/lib/module/pid/index.js +1 -2
- package/lib/module/pid/index.js.map +1 -1
- package/lib/module/sd-jwt/index.js +1 -1
- package/lib/module/sd-jwt/index.js.map +1 -1
- package/lib/module/sd-jwt/types.js +1 -1
- package/lib/module/sd-jwt/types.js.map +1 -1
- package/lib/module/trust/chain.js +30 -3
- package/lib/module/trust/chain.js.map +1 -1
- package/lib/module/trust/index.js +99 -16
- package/lib/module/trust/index.js.map +1 -1
- package/lib/module/trust/types.js +50 -31
- package/lib/module/trust/types.js.map +1 -1
- package/lib/module/utils/crypto.js +2 -15
- package/lib/module/utils/crypto.js.map +1 -1
- package/lib/module/utils/misc.js +17 -0
- package/lib/module/utils/misc.js.map +1 -0
- package/lib/module/utils/par.js +74 -0
- package/lib/module/utils/par.js.map +1 -0
- package/lib/typescript/credential/index.d.ts +4 -0
- package/lib/typescript/credential/index.d.ts.map +1 -0
- package/lib/typescript/credential/issuance/01-start-flow.d.ts +11 -0
- package/lib/typescript/credential/issuance/01-start-flow.d.ts.map +1 -0
- package/lib/typescript/credential/issuance/02-evaluate-issuer-trust.d.ts +18 -0
- package/lib/typescript/credential/issuance/02-evaluate-issuer-trust.d.ts.map +1 -0
- package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts +31 -0
- package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts.map +1 -0
- package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts +16 -0
- package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts.map +1 -0
- package/lib/typescript/credential/issuance/05-authorize-access.d.ts +26 -0
- package/lib/typescript/credential/issuance/05-authorize-access.d.ts.map +1 -0
- package/lib/typescript/credential/issuance/06-obtain-credential.d.ts +32 -0
- package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -0
- package/lib/typescript/credential/issuance/07-confirm-credential.d.ts +11 -0
- package/lib/typescript/credential/issuance/07-confirm-credential.d.ts.map +1 -0
- package/lib/typescript/credential/issuance/const.d.ts +2 -0
- package/lib/typescript/credential/issuance/const.d.ts.map +1 -0
- package/lib/typescript/credential/issuance/index.d.ts +10 -0
- package/lib/typescript/credential/issuance/index.d.ts.map +1 -0
- package/lib/typescript/credential/presentation/01-start-flow.d.ts +20 -0
- package/lib/typescript/credential/presentation/01-start-flow.d.ts.map +1 -0
- package/lib/typescript/credential/presentation/02-evaluate-rp-trust.d.ts +18 -0
- package/lib/typescript/credential/presentation/02-evaluate-rp-trust.d.ts.map +1 -0
- package/lib/typescript/credential/presentation/03-get-request-object.d.ts +25 -0
- package/lib/typescript/credential/presentation/03-get-request-object.d.ts.map +1 -0
- package/lib/typescript/credential/presentation/04-send-authorization-response.d.ts +34 -0
- package/lib/typescript/credential/presentation/04-send-authorization-response.d.ts.map +1 -0
- package/lib/typescript/credential/presentation/index.d.ts +7 -0
- package/lib/typescript/credential/presentation/index.d.ts.map +1 -0
- package/lib/typescript/credential/presentation/types.d.ts +49 -0
- package/lib/typescript/credential/presentation/types.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +4 -5
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/pid/index.d.ts +1 -2
- package/lib/typescript/pid/index.d.ts.map +1 -1
- package/lib/typescript/sd-jwt/index.d.ts +2 -2
- package/lib/typescript/sd-jwt/index.d.ts.map +1 -1
- package/lib/typescript/sd-jwt/types.d.ts +5 -5
- package/lib/typescript/trust/chain.d.ts +12 -3
- package/lib/typescript/trust/chain.d.ts.map +1 -1
- package/lib/typescript/trust/index.d.ts +198 -24
- package/lib/typescript/trust/index.d.ts.map +1 -1
- package/lib/typescript/trust/types.d.ts +1299 -623
- package/lib/typescript/trust/types.d.ts.map +1 -1
- package/lib/typescript/utils/crypto.d.ts +1 -1
- package/lib/typescript/utils/crypto.d.ts.map +1 -1
- package/lib/typescript/utils/dpop.d.ts +2 -2
- package/lib/typescript/utils/misc.d.ts +8 -0
- package/lib/typescript/utils/misc.d.ts.map +1 -0
- package/lib/typescript/utils/par.d.ts +68 -0
- package/lib/typescript/utils/par.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/credential/index.ts +4 -0
- package/src/credential/issuance/01-start-flow.ts +10 -0
- package/src/credential/issuance/02-evaluate-issuer-trust.ts +31 -0
- package/src/credential/issuance/03-start-user-authorization.ts +138 -0
- package/src/credential/issuance/04-complete-user-authorization.ts +17 -0
- package/src/credential/issuance/05-authorize-access.ts +92 -0
- package/src/credential/issuance/06-obtain-credential.ts +179 -0
- package/src/credential/issuance/07-confirm-credential.ts +14 -0
- package/src/credential/issuance/const.ts +2 -0
- package/src/credential/issuance/index.ts +32 -0
- package/src/credential/presentation/01-start-flow.ts +51 -0
- package/src/credential/presentation/02-evaluate-rp-trust.ts +33 -0
- package/src/credential/presentation/03-get-request-object.ts +85 -0
- package/src/credential/presentation/04-send-authorization-response.ts +168 -0
- package/src/credential/presentation/index.ts +26 -0
- package/src/credential/presentation/types.ts +27 -0
- package/src/index.ts +7 -28
- package/src/pid/index.ts +1 -2
- package/src/sd-jwt/index.ts +2 -2
- package/src/sd-jwt/types.ts +1 -1
- package/src/trust/chain.ts +45 -3
- package/src/trust/index.ts +136 -19
- package/src/trust/types.ts +57 -35
- package/src/utils/crypto.ts +2 -20
- package/src/utils/misc.ts +23 -0
- package/src/utils/par.ts +103 -0
- package/lib/commonjs/pid/issuing.js +0 -276
- package/lib/commonjs/pid/issuing.js.map +0 -1
- package/lib/commonjs/rp/__test__/index.test.js +0 -172
- package/lib/commonjs/rp/__test__/index.test.js.map +0 -1
- package/lib/commonjs/rp/index.js +0 -239
- package/lib/commonjs/rp/index.js.map +0 -1
- package/lib/commonjs/rp/types.js.map +0 -1
- package/lib/module/pid/issuing.js +0 -266
- package/lib/module/pid/issuing.js.map +0 -1
- package/lib/module/rp/__test__/index.test.js +0 -168
- package/lib/module/rp/__test__/index.test.js.map +0 -1
- package/lib/module/rp/index.js +0 -228
- package/lib/module/rp/index.js.map +0 -1
- package/lib/module/rp/types.js +0 -36
- package/lib/module/rp/types.js.map +0 -1
- package/lib/typescript/pid/issuing.d.ts +0 -57
- package/lib/typescript/pid/issuing.d.ts.map +0 -1
- package/lib/typescript/rp/__test__/index.test.d.ts +0 -2
- package/lib/typescript/rp/__test__/index.test.d.ts.map +0 -1
- package/lib/typescript/rp/index.d.ts +0 -43
- package/lib/typescript/rp/index.d.ts.map +0 -1
- package/lib/typescript/rp/types.d.ts +0 -122
- package/lib/typescript/rp/types.d.ts.map +0 -1
- package/src/pid/issuing.ts +0 -405
- package/src/rp/__test__/index.test.ts +0 -250
- package/src/rp/index.ts +0 -287
- package/src/rp/types.ts +0 -42
package/src/trust/index.ts
CHANGED
|
@@ -5,11 +5,74 @@ import {
|
|
|
5
5
|
CredentialIssuerEntityConfiguration,
|
|
6
6
|
RelyingPartyEntityConfiguration,
|
|
7
7
|
EntityConfiguration,
|
|
8
|
+
EntityStatement,
|
|
8
9
|
} from "./types";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
10
|
+
import { validateTrustChain, renewTrustChain } from "./chain";
|
|
11
|
+
import { hasStatus } from "../utils/misc";
|
|
11
12
|
|
|
12
|
-
export {
|
|
13
|
+
export type {
|
|
14
|
+
WalletProviderEntityConfiguration,
|
|
15
|
+
TrustAnchorEntityConfiguration,
|
|
16
|
+
CredentialIssuerEntityConfiguration,
|
|
17
|
+
RelyingPartyEntityConfiguration,
|
|
18
|
+
EntityConfiguration,
|
|
19
|
+
EntityStatement,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Verify a given trust chain is actually valid.
|
|
24
|
+
* It can handle fast chain renewal, which means we try to fetch a fresh version of each statement.
|
|
25
|
+
*
|
|
26
|
+
* @param trustAnchorEntity The entity configuration of the known trust anchor
|
|
27
|
+
* @param chain The chain of statements to be validate
|
|
28
|
+
* @param options.renewOnFail Whether to renew the provided chain if the validation fails at first. Default: true
|
|
29
|
+
* @param options.appFetch Fetch api implementation. Default: the built-in implementation
|
|
30
|
+
* @returns The result of the chain validation
|
|
31
|
+
* @throws {IoWalletError} When either validation or renewal fail
|
|
32
|
+
*/
|
|
33
|
+
export async function verifyTrustChain(
|
|
34
|
+
trustAnchorEntity: TrustAnchorEntityConfiguration,
|
|
35
|
+
chain: string[],
|
|
36
|
+
{
|
|
37
|
+
appFetch = fetch,
|
|
38
|
+
renewOnFail = true,
|
|
39
|
+
}: { appFetch?: GlobalFetch["fetch"]; renewOnFail?: boolean } = {}
|
|
40
|
+
): Promise<ReturnType<typeof validateTrustChain>> {
|
|
41
|
+
try {
|
|
42
|
+
return validateTrustChain(trustAnchorEntity, chain);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
if (renewOnFail) {
|
|
45
|
+
const renewedChain = await renewTrustChain(chain, appFetch);
|
|
46
|
+
return validateTrustChain(trustAnchorEntity, renewedChain);
|
|
47
|
+
} else {
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Fetch the signed entity configuration token for an entity
|
|
55
|
+
*
|
|
56
|
+
* @param entityBaseUrl The url of the entity to fetch
|
|
57
|
+
* @param param.appFetch (optional) fetch api implemention
|
|
58
|
+
* @returns The signed Entity Configuration token
|
|
59
|
+
*/
|
|
60
|
+
export async function getSignedEntityConfiguration(
|
|
61
|
+
entityBaseUrl: string,
|
|
62
|
+
{
|
|
63
|
+
appFetch = fetch,
|
|
64
|
+
}: {
|
|
65
|
+
appFetch?: GlobalFetch["fetch"];
|
|
66
|
+
} = {}
|
|
67
|
+
): Promise<string> {
|
|
68
|
+
const wellKnownUrl = `${entityBaseUrl}/.well-known/openid-federation`;
|
|
69
|
+
|
|
70
|
+
return await appFetch(wellKnownUrl, {
|
|
71
|
+
method: "GET",
|
|
72
|
+
})
|
|
73
|
+
.then(hasStatus(200))
|
|
74
|
+
.then((res) => res.text());
|
|
75
|
+
}
|
|
13
76
|
|
|
14
77
|
/**
|
|
15
78
|
* Fetch and parse the entity configuration document for a given federation entity.
|
|
@@ -77,24 +140,15 @@ async function fetchAndParseEntityConfiguration(
|
|
|
77
140
|
appFetch?: GlobalFetch["fetch"];
|
|
78
141
|
} = {}
|
|
79
142
|
) {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
const response = await appFetch(wellKnownUrl, {
|
|
83
|
-
method: "GET",
|
|
143
|
+
const responseText = await getSignedEntityConfiguration(entityBaseUrl, {
|
|
144
|
+
appFetch,
|
|
84
145
|
});
|
|
85
146
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
payload: responseJwt.payload,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
throw new IoWalletError(
|
|
96
|
-
`Unable to obtain Entity Configuration at ${wellKnownUrl}. Response code: ${response.status}`
|
|
97
|
-
);
|
|
147
|
+
const responseJwt = decodeJwt(responseText);
|
|
148
|
+
return schema.parse({
|
|
149
|
+
header: responseJwt.protectedHeader,
|
|
150
|
+
payload: responseJwt.payload,
|
|
151
|
+
});
|
|
98
152
|
}
|
|
99
153
|
|
|
100
154
|
export const getWalletProviderEntityConfiguration = (
|
|
@@ -142,3 +196,66 @@ export const getEntityConfiguration = (
|
|
|
142
196
|
options?: Parameters<typeof fetchAndParseEntityConfiguration>[2]
|
|
143
197
|
) =>
|
|
144
198
|
fetchAndParseEntityConfiguration(entityBaseUrl, EntityConfiguration, options);
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Fetch and parse the entity statement document for a given federation entity.
|
|
202
|
+
*
|
|
203
|
+
* @param accreditationBodyBaseUrl The base url of the accreditaion body which holds and signs the required entity statement
|
|
204
|
+
* @param subordinatedEntityBaseUrl The url that identifies the subordinate entity
|
|
205
|
+
* @param options.appFetch An optional instance of the http client to be used.
|
|
206
|
+
* @returns The parsed entity configuration object
|
|
207
|
+
* @throws {IoWalletError} If the http request fails
|
|
208
|
+
* @throws Parse error if the document is not in the expected shape.
|
|
209
|
+
*/
|
|
210
|
+
export async function getEntityStatement(
|
|
211
|
+
accreditationBodyBaseUrl: string,
|
|
212
|
+
subordinatedEntityBaseUrl: string,
|
|
213
|
+
{
|
|
214
|
+
appFetch = fetch,
|
|
215
|
+
}: {
|
|
216
|
+
appFetch?: GlobalFetch["fetch"];
|
|
217
|
+
} = {}
|
|
218
|
+
) {
|
|
219
|
+
const responseText = await getSignedEntityStatement(
|
|
220
|
+
accreditationBodyBaseUrl,
|
|
221
|
+
subordinatedEntityBaseUrl,
|
|
222
|
+
{
|
|
223
|
+
appFetch,
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
const responseJwt = decodeJwt(responseText);
|
|
228
|
+
return EntityStatement.parse({
|
|
229
|
+
header: responseJwt.protectedHeader,
|
|
230
|
+
payload: responseJwt.payload,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Fetch the entity statement document for a given federation entity.
|
|
236
|
+
*
|
|
237
|
+
* @param accreditationBodyBaseUrl The base url of the accreditaion body which holds and signs the required entity statement
|
|
238
|
+
* @param subordinatedEntityBaseUrl The url that identifies the subordinate entity
|
|
239
|
+
* @param options.appFetch An optional instance of the http client to be used.
|
|
240
|
+
* @returns The signed entity statement token
|
|
241
|
+
* @throws {IoWalletError} If the http request fails
|
|
242
|
+
*/
|
|
243
|
+
export async function getSignedEntityStatement(
|
|
244
|
+
accreditationBodyBaseUrl: string,
|
|
245
|
+
subordinatedEntityBaseUrl: string,
|
|
246
|
+
{
|
|
247
|
+
appFetch = fetch,
|
|
248
|
+
}: {
|
|
249
|
+
appFetch?: GlobalFetch["fetch"];
|
|
250
|
+
} = {}
|
|
251
|
+
) {
|
|
252
|
+
const url = `${accreditationBodyBaseUrl}/fetch?${new URLSearchParams({
|
|
253
|
+
sub: subordinatedEntityBaseUrl,
|
|
254
|
+
})}`;
|
|
255
|
+
|
|
256
|
+
return await appFetch(url, {
|
|
257
|
+
method: "GET",
|
|
258
|
+
})
|
|
259
|
+
.then(hasStatus(200))
|
|
260
|
+
.then((res) => res.text());
|
|
261
|
+
}
|
package/src/trust/types.ts
CHANGED
|
@@ -5,6 +5,15 @@ import * as z from "zod";
|
|
|
5
5
|
export const TrustMark = z.object({ id: z.string(), trust_mark: z.string() });
|
|
6
6
|
export type TrustMark = z.infer<typeof TrustMark>;
|
|
7
7
|
|
|
8
|
+
const RelyingPartyMetadata = z.object({
|
|
9
|
+
application_type: z.string().optional(),
|
|
10
|
+
client_id: z.string().optional(),
|
|
11
|
+
client_name: z.string().optional(),
|
|
12
|
+
jwks: z.object({ keys: z.array(JWK) }),
|
|
13
|
+
contacts: z.array(z.string()).optional(),
|
|
14
|
+
});
|
|
15
|
+
//.passthrough();
|
|
16
|
+
|
|
8
17
|
// Display metadata for a credential, used by the issuer to
|
|
9
18
|
// instruct the Wallet Solution on how to render the credential correctly
|
|
10
19
|
type CredentialDisplayMetadata = z.infer<typeof CredentialDisplayMetadata>;
|
|
@@ -19,13 +28,28 @@ const CredentialDisplayMetadata = z.object({
|
|
|
19
28
|
text_color: z.string(),
|
|
20
29
|
});
|
|
21
30
|
|
|
31
|
+
type CredentialDefinitionMetadata = z.infer<
|
|
32
|
+
typeof CredentialDefinitionMetadata
|
|
33
|
+
>;
|
|
34
|
+
const CredentialDefinitionMetadata = z.object({
|
|
35
|
+
type: z.array(z.string()),
|
|
36
|
+
credentialSubject: z.record(
|
|
37
|
+
z.object({
|
|
38
|
+
mandatory: z.boolean(),
|
|
39
|
+
display: z.array(z.object({ name: z.string(), locale: z.string() })),
|
|
40
|
+
})
|
|
41
|
+
),
|
|
42
|
+
});
|
|
43
|
+
|
|
22
44
|
// Metadata for a credentia which i supported by a Issuer
|
|
23
45
|
type SupportedCredentialMetadata = z.infer<typeof SupportedCredentialMetadata>;
|
|
24
46
|
const SupportedCredentialMetadata = z.object({
|
|
47
|
+
id: z.string(),
|
|
25
48
|
format: z.literal("vc+sd-jwt"),
|
|
26
49
|
cryptographic_binding_methods_supported: z.array(z.string()),
|
|
27
50
|
cryptographic_suites_supported: z.array(z.string()),
|
|
28
51
|
display: z.array(CredentialDisplayMetadata),
|
|
52
|
+
credential_definition: CredentialDefinitionMetadata,
|
|
29
53
|
});
|
|
30
54
|
|
|
31
55
|
export type EntityStatement = z.infer<typeof EntityStatement>;
|
|
@@ -54,6 +78,20 @@ export const EntityConfigurationHeader = z.object({
|
|
|
54
78
|
kid: z.string(),
|
|
55
79
|
});
|
|
56
80
|
|
|
81
|
+
const FederationEntityMetadata = z
|
|
82
|
+
.object({
|
|
83
|
+
federation_fetch_endpoint: z.string().optional(),
|
|
84
|
+
federation_list_endpoint: z.string().optional(),
|
|
85
|
+
federation_resolve_endpoint: z.string().optional(),
|
|
86
|
+
federation_trust_mark_status_endpoint: z.string().optional(),
|
|
87
|
+
federation_trust_mark_list_endpoint: z.string().optional(),
|
|
88
|
+
homepage_uri: z.string().optional(),
|
|
89
|
+
policy_uri: z.string().optional(),
|
|
90
|
+
logo_uri: z.string().optional(),
|
|
91
|
+
contacts: z.array(z.string()).optional(),
|
|
92
|
+
})
|
|
93
|
+
.passthrough();
|
|
94
|
+
|
|
57
95
|
// Structuire common to every Entity Configuration document
|
|
58
96
|
const BaseEntityConfiguration = z.object({
|
|
59
97
|
header: EntityConfigurationHeader,
|
|
@@ -68,19 +106,7 @@ const BaseEntityConfiguration = z.object({
|
|
|
68
106
|
}),
|
|
69
107
|
metadata: z
|
|
70
108
|
.object({
|
|
71
|
-
federation_entity:
|
|
72
|
-
.object({
|
|
73
|
-
federation_fetch_endpoint: z.string().optional(),
|
|
74
|
-
federation_list_endpoint: z.string().optional(),
|
|
75
|
-
federation_resolve_endpoint: z.string().optional(),
|
|
76
|
-
federation_trust_mark_status_endpoint: z.string().optional(),
|
|
77
|
-
federation_trust_mark_list_endpoint: z.string().optional(),
|
|
78
|
-
homepage_uri: z.string().optional(),
|
|
79
|
-
policy_uri: z.string().optional(),
|
|
80
|
-
logo_uri: z.string().optional(),
|
|
81
|
-
contacts: z.array(z.string()).optional(),
|
|
82
|
-
})
|
|
83
|
-
.passthrough(),
|
|
109
|
+
federation_entity: FederationEntityMetadata,
|
|
84
110
|
})
|
|
85
111
|
.passthrough(),
|
|
86
112
|
authority_hints: z.array(z.string()).optional(),
|
|
@@ -113,6 +139,24 @@ export const CredentialIssuerEntityConfiguration = BaseEntityConfiguration.and(
|
|
|
113
139
|
credentials_supported: z.array(SupportedCredentialMetadata),
|
|
114
140
|
jwks: z.object({ keys: z.array(JWK) }),
|
|
115
141
|
}),
|
|
142
|
+
/** Credential Issuers act as Relying Party
|
|
143
|
+
when they require the presentation of other credentials.
|
|
144
|
+
This does not apply for PID issuance, which requires CIE authz. */
|
|
145
|
+
wallet_relying_party: RelyingPartyMetadata.optional(),
|
|
146
|
+
}),
|
|
147
|
+
}),
|
|
148
|
+
})
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// Entity configuration for a Relying Party
|
|
152
|
+
export type RelyingPartyEntityConfiguration = z.infer<
|
|
153
|
+
typeof RelyingPartyEntityConfiguration
|
|
154
|
+
>;
|
|
155
|
+
export const RelyingPartyEntityConfiguration = BaseEntityConfiguration.and(
|
|
156
|
+
z.object({
|
|
157
|
+
payload: z.object({
|
|
158
|
+
metadata: z.object({
|
|
159
|
+
wallet_relying_party: RelyingPartyMetadata,
|
|
116
160
|
}),
|
|
117
161
|
}),
|
|
118
162
|
})
|
|
@@ -145,28 +189,6 @@ export const WalletProviderEntityConfiguration = BaseEntityConfiguration.and(
|
|
|
145
189
|
})
|
|
146
190
|
);
|
|
147
191
|
|
|
148
|
-
// Entity configuration for a Relying Party
|
|
149
|
-
export type RelyingPartyEntityConfiguration = z.infer<
|
|
150
|
-
typeof RelyingPartyEntityConfiguration
|
|
151
|
-
>;
|
|
152
|
-
export const RelyingPartyEntityConfiguration = BaseEntityConfiguration.and(
|
|
153
|
-
z.object({
|
|
154
|
-
payload: z.object({
|
|
155
|
-
metadata: z.object({
|
|
156
|
-
wallet_relying_party: z
|
|
157
|
-
.object({
|
|
158
|
-
application_type: z.string().optional(),
|
|
159
|
-
client_id: z.string().optional(),
|
|
160
|
-
client_name: z.string().optional(),
|
|
161
|
-
jwks: z.object({ keys: z.array(JWK) }),
|
|
162
|
-
contacts: z.array(z.string()).optional(),
|
|
163
|
-
})
|
|
164
|
-
.passthrough(),
|
|
165
|
-
}),
|
|
166
|
-
}),
|
|
167
|
-
})
|
|
168
|
-
);
|
|
169
|
-
|
|
170
192
|
// Maps any entity configuration by the union of every possible shapes
|
|
171
193
|
export type EntityConfiguration = z.infer<typeof EntityConfiguration>;
|
|
172
194
|
export const EntityConfiguration = z.union(
|
package/src/utils/crypto.ts
CHANGED
|
@@ -46,24 +46,6 @@ export const createCryptoContextFor = (keytag: string): CryptoContext => {
|
|
|
46
46
|
};
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
// Wraps finally for async expressions
|
|
50
|
-
const asyncFinally =
|
|
51
|
-
<A extends Array<unknown>, R>(
|
|
52
|
-
fn: (...args: A) => Promise<R>,
|
|
53
|
-
onFinally: () => void | Promise<void>
|
|
54
|
-
) =>
|
|
55
|
-
async (...args: A): Promise<R> => {
|
|
56
|
-
try {
|
|
57
|
-
return await fn(...args);
|
|
58
|
-
// ^^^^^ return await is usually to be avoided,
|
|
59
|
-
// in this case is needed for the finally{} statement to be executed correctly
|
|
60
|
-
} catch (error) {
|
|
61
|
-
throw error;
|
|
62
|
-
} finally {
|
|
63
|
-
await onFinally();
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
49
|
/**
|
|
68
50
|
* Executes the input function injecting an ephemeral crypto context.
|
|
69
51
|
* An ephemeral crypto context is a context which is bound to a key
|
|
@@ -72,12 +54,12 @@ const asyncFinally =
|
|
|
72
54
|
* @param fn The procedure to be executed
|
|
73
55
|
* @returns The returned value of the input procedure.
|
|
74
56
|
*/
|
|
75
|
-
export const
|
|
57
|
+
export const withEphemeralKey = async <R>(
|
|
76
58
|
fn: (ephemeralContext: CryptoContext) => Promise<R>
|
|
77
59
|
): Promise<R> => {
|
|
78
60
|
// Use an ephemeral key to be destroyed after use
|
|
79
61
|
const keytag = `ephemeral-${uuid.v4()}`;
|
|
80
62
|
await generate(keytag);
|
|
81
63
|
const ephemeralContext = createCryptoContextFor(keytag);
|
|
82
|
-
return
|
|
64
|
+
return fn(ephemeralContext).finally(() => deleteKey(keytag));
|
|
83
65
|
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { IoWalletError } from "./errors";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Check if a response is in the expected status, other
|
|
5
|
+
* @param status The expected status
|
|
6
|
+
* @returns The given response object
|
|
7
|
+
*/
|
|
8
|
+
export const hasStatus =
|
|
9
|
+
(status: number) =>
|
|
10
|
+
(res: Response): Response => {
|
|
11
|
+
if (res.status !== status) {
|
|
12
|
+
throw new IoWalletError(
|
|
13
|
+
`Http request failed. Expected ${status}, got ${res.status}, url: ${res.url}`
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
return res;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// extract a type from an async function output
|
|
20
|
+
// helpful to bind the input of a function to the output of another
|
|
21
|
+
export type Out<FN> = FN extends (...args: any[]) => Promise<any>
|
|
22
|
+
? Awaited<ReturnType<FN>>
|
|
23
|
+
: never;
|
package/src/utils/par.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sha256ToBase64,
|
|
3
|
+
type CryptoContext,
|
|
4
|
+
SignJWT,
|
|
5
|
+
} from "@pagopa/io-react-native-jwt";
|
|
6
|
+
import uuid from "react-native-uuid";
|
|
7
|
+
import * as z from "zod";
|
|
8
|
+
import * as WalletInstanceAttestation from "../wallet-instance-attestation";
|
|
9
|
+
import { hasStatus } from "./misc";
|
|
10
|
+
|
|
11
|
+
export type AuthorizationDetail = z.infer<typeof AuthorizationDetail>;
|
|
12
|
+
export const AuthorizationDetail = z.object({
|
|
13
|
+
credential_definition: z.object({
|
|
14
|
+
type: z.string(),
|
|
15
|
+
}),
|
|
16
|
+
format: z.literal("vc+sd-jwt"),
|
|
17
|
+
type: z.literal("openid_credential"),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export type AuthorizationDetails = z.infer<typeof AuthorizationDetails>;
|
|
21
|
+
export const AuthorizationDetails = z.array(AuthorizationDetail);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Make a PAR request to the issuer and return the response url
|
|
25
|
+
*/
|
|
26
|
+
export const makeParRequest =
|
|
27
|
+
({
|
|
28
|
+
wiaCryptoContext,
|
|
29
|
+
appFetch = fetch,
|
|
30
|
+
}: {
|
|
31
|
+
wiaCryptoContext: CryptoContext;
|
|
32
|
+
appFetch?: GlobalFetch["fetch"];
|
|
33
|
+
}) =>
|
|
34
|
+
async (
|
|
35
|
+
clientId: string,
|
|
36
|
+
codeVerifier: string,
|
|
37
|
+
walletProviderBaseUrl: string,
|
|
38
|
+
parEndpoint: string,
|
|
39
|
+
walletInstanceAttestation: string,
|
|
40
|
+
authorizationDetails: AuthorizationDetails,
|
|
41
|
+
assertionType: string
|
|
42
|
+
): Promise<string> => {
|
|
43
|
+
const wiaPublicKey = await wiaCryptoContext.getPublicKey();
|
|
44
|
+
|
|
45
|
+
const parUrl = new URL(parEndpoint);
|
|
46
|
+
const aud = `${parUrl.protocol}//${parUrl.hostname}`;
|
|
47
|
+
|
|
48
|
+
const iss = WalletInstanceAttestation.decode(walletInstanceAttestation)
|
|
49
|
+
.payload.cnf.jwk.kid;
|
|
50
|
+
|
|
51
|
+
/** A code challenge is provided so that the PAR is bound
|
|
52
|
+
to the subsequent authorization code request
|
|
53
|
+
@see https://datatracker.ietf.org/doc/html/rfc9126#name-request */
|
|
54
|
+
const codeChallengeMethod = "s256";
|
|
55
|
+
const codeChallenge = await sha256ToBase64(codeVerifier);
|
|
56
|
+
|
|
57
|
+
/** The PAR request token is signed used the Wallet Instance Attestation key.
|
|
58
|
+
The signature can be verified by reading the public key from the key set shippet
|
|
59
|
+
with the it will ship the Wallet Instance Attestation.
|
|
60
|
+
The key is matched by its kid */
|
|
61
|
+
const signedJwtForPar = await new SignJWT(wiaCryptoContext)
|
|
62
|
+
.setProtectedHeader({
|
|
63
|
+
kid: wiaPublicKey.kid,
|
|
64
|
+
})
|
|
65
|
+
.setPayload({
|
|
66
|
+
iss,
|
|
67
|
+
aud,
|
|
68
|
+
jti: `${uuid.v4()}`,
|
|
69
|
+
client_assertion_type: assertionType,
|
|
70
|
+
authorization_details: authorizationDetails,
|
|
71
|
+
response_type: "code",
|
|
72
|
+
redirect_uri: walletProviderBaseUrl,
|
|
73
|
+
state: `${uuid.v4()}`,
|
|
74
|
+
client_id: clientId,
|
|
75
|
+
code_challenge_method: codeChallengeMethod,
|
|
76
|
+
code_challenge: codeChallenge,
|
|
77
|
+
})
|
|
78
|
+
.setIssuedAt()
|
|
79
|
+
.setExpirationTime("1h")
|
|
80
|
+
.sign();
|
|
81
|
+
|
|
82
|
+
/** The request body for the Pushed Authorization Request */
|
|
83
|
+
var formBody = new URLSearchParams({
|
|
84
|
+
response_type: "code",
|
|
85
|
+
client_id: clientId,
|
|
86
|
+
code_challenge: codeChallenge,
|
|
87
|
+
code_challenge_method: "S256",
|
|
88
|
+
client_assertion_type: assertionType,
|
|
89
|
+
client_assertion: walletInstanceAttestation,
|
|
90
|
+
request: signedJwtForPar,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return await appFetch(parEndpoint, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: {
|
|
96
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
97
|
+
},
|
|
98
|
+
body: formBody.toString(),
|
|
99
|
+
})
|
|
100
|
+
.then(hasStatus(201))
|
|
101
|
+
.then((res) => res.json())
|
|
102
|
+
.then((result) => result.request_uri);
|
|
103
|
+
};
|