@pagopa/io-react-native-wallet 0.7.4 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
};
|