@pagopa/io-react-native-wallet 1.1.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. package/lib/commonjs/credential/presentation/01-start-flow.js +7 -5
  2. package/lib/commonjs/credential/presentation/01-start-flow.js.map +1 -1
  3. package/lib/commonjs/credential/presentation/03-get-request-object.js +47 -0
  4. package/lib/commonjs/credential/presentation/03-get-request-object.js.map +1 -0
  5. package/lib/commonjs/credential/presentation/04-retrieve-rp-jwks.js +82 -0
  6. package/lib/commonjs/credential/presentation/04-retrieve-rp-jwks.js.map +1 -0
  7. package/lib/commonjs/credential/presentation/05-verify-request-object.js +35 -0
  8. package/lib/commonjs/credential/presentation/05-verify-request-object.js.map +1 -0
  9. package/lib/commonjs/credential/presentation/06-fetch-presentation-definition.js +63 -0
  10. package/lib/commonjs/credential/presentation/06-fetch-presentation-definition.js.map +1 -0
  11. package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js +169 -0
  12. package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js.map +1 -0
  13. package/lib/commonjs/credential/presentation/08-send-authorization-response.js +202 -0
  14. package/lib/commonjs/credential/presentation/08-send-authorization-response.js.map +1 -0
  15. package/lib/commonjs/credential/presentation/README.md +43 -4
  16. package/lib/commonjs/credential/presentation/errors.js +52 -1
  17. package/lib/commonjs/credential/presentation/errors.js.map +1 -1
  18. package/lib/commonjs/credential/presentation/index.js +27 -6
  19. package/lib/commonjs/credential/presentation/index.js.map +1 -1
  20. package/lib/commonjs/credential/presentation/types.js +69 -4
  21. package/lib/commonjs/credential/presentation/types.js.map +1 -1
  22. package/lib/commonjs/entity/trust/types.js +4 -1
  23. package/lib/commonjs/entity/trust/types.js.map +1 -1
  24. package/lib/module/credential/presentation/01-start-flow.js +8 -6
  25. package/lib/module/credential/presentation/01-start-flow.js.map +1 -1
  26. package/lib/module/credential/presentation/03-get-request-object.js +39 -0
  27. package/lib/module/credential/presentation/03-get-request-object.js.map +1 -0
  28. package/lib/module/credential/presentation/04-retrieve-rp-jwks.js +75 -0
  29. package/lib/module/credential/presentation/04-retrieve-rp-jwks.js.map +1 -0
  30. package/lib/module/credential/presentation/05-verify-request-object.js +28 -0
  31. package/lib/module/credential/presentation/05-verify-request-object.js.map +1 -0
  32. package/lib/module/credential/presentation/06-fetch-presentation-definition.js +56 -0
  33. package/lib/module/credential/presentation/06-fetch-presentation-definition.js.map +1 -0
  34. package/lib/module/credential/presentation/07-evaluate-input-descriptor.js +161 -0
  35. package/lib/module/credential/presentation/07-evaluate-input-descriptor.js.map +1 -0
  36. package/lib/module/credential/presentation/08-send-authorization-response.js +188 -0
  37. package/lib/module/credential/presentation/08-send-authorization-response.js.map +1 -0
  38. package/lib/module/credential/presentation/README.md +43 -4
  39. package/lib/module/credential/presentation/errors.js +48 -0
  40. package/lib/module/credential/presentation/errors.js.map +1 -1
  41. package/lib/module/credential/presentation/index.js +7 -4
  42. package/lib/module/credential/presentation/index.js.map +1 -1
  43. package/lib/module/credential/presentation/types.js +67 -3
  44. package/lib/module/credential/presentation/types.js.map +1 -1
  45. package/lib/module/entity/trust/types.js +4 -1
  46. package/lib/module/entity/trust/types.js.map +1 -1
  47. package/lib/typescript/credential/presentation/01-start-flow.d.ts.map +1 -1
  48. package/lib/typescript/credential/presentation/{04-get-request-object.d.ts → 03-get-request-object.d.ts} +3 -5
  49. package/lib/typescript/credential/presentation/03-get-request-object.d.ts.map +1 -0
  50. package/lib/typescript/credential/presentation/{03-retrieve-jwks.d.ts → 04-retrieve-rp-jwks.d.ts} +6 -5
  51. package/lib/typescript/credential/presentation/04-retrieve-rp-jwks.d.ts.map +1 -0
  52. package/lib/typescript/credential/presentation/05-verify-request-object.d.ts +8 -0
  53. package/lib/typescript/credential/presentation/05-verify-request-object.d.ts.map +1 -0
  54. package/lib/typescript/credential/presentation/06-fetch-presentation-definition.d.ts +26 -0
  55. package/lib/typescript/credential/presentation/06-fetch-presentation-definition.d.ts.map +1 -0
  56. package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts +27 -0
  57. package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts.map +1 -0
  58. package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts +99 -0
  59. package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts.map +1 -0
  60. package/lib/typescript/credential/presentation/errors.d.ts +33 -0
  61. package/lib/typescript/credential/presentation/errors.d.ts.map +1 -1
  62. package/lib/typescript/credential/presentation/index.d.ts +8 -5
  63. package/lib/typescript/credential/presentation/index.d.ts.map +1 -1
  64. package/lib/typescript/credential/presentation/types.d.ts +612 -9
  65. package/lib/typescript/credential/presentation/types.d.ts.map +1 -1
  66. package/lib/typescript/entity/trust/index.d.ts +152 -0
  67. package/lib/typescript/entity/trust/index.d.ts.map +1 -1
  68. package/lib/typescript/entity/trust/types.d.ts +2088 -0
  69. package/lib/typescript/entity/trust/types.d.ts.map +1 -1
  70. package/package.json +5 -1
  71. package/src/credential/presentation/01-start-flow.ts +10 -6
  72. package/src/credential/presentation/{04-get-request-object.ts → 03-get-request-object.ts} +6 -51
  73. package/src/credential/presentation/04-retrieve-rp-jwks.ts +88 -0
  74. package/src/credential/presentation/05-verify-request-object.ts +35 -0
  75. package/src/credential/presentation/06-fetch-presentation-definition.ts +78 -0
  76. package/src/credential/presentation/07-evaluate-input-descriptor.ts +204 -0
  77. package/src/credential/presentation/08-send-authorization-response.ts +251 -0
  78. package/src/credential/presentation/README.md +43 -4
  79. package/src/credential/presentation/errors.ts +48 -0
  80. package/src/credential/presentation/index.ts +27 -9
  81. package/src/credential/presentation/types.ts +59 -3
  82. package/src/entity/trust/types.ts +3 -0
  83. package/lib/commonjs/credential/presentation/03-retrieve-jwks.js +0 -68
  84. package/lib/commonjs/credential/presentation/03-retrieve-jwks.js.map +0 -1
  85. package/lib/commonjs/credential/presentation/04-get-request-object.js +0 -82
  86. package/lib/commonjs/credential/presentation/04-get-request-object.js.map +0 -1
  87. package/lib/commonjs/credential/presentation/05-send-authorization-response.js +0 -139
  88. package/lib/commonjs/credential/presentation/05-send-authorization-response.js.map +0 -1
  89. package/lib/module/credential/presentation/03-retrieve-jwks.js +0 -61
  90. package/lib/module/credential/presentation/03-retrieve-jwks.js.map +0 -1
  91. package/lib/module/credential/presentation/04-get-request-object.js +0 -74
  92. package/lib/module/credential/presentation/04-get-request-object.js.map +0 -1
  93. package/lib/module/credential/presentation/05-send-authorization-response.js +0 -128
  94. package/lib/module/credential/presentation/05-send-authorization-response.js.map +0 -1
  95. package/lib/typescript/credential/presentation/03-retrieve-jwks.d.ts.map +0 -1
  96. package/lib/typescript/credential/presentation/04-get-request-object.d.ts.map +0 -1
  97. package/lib/typescript/credential/presentation/05-send-authorization-response.d.ts +0 -34
  98. package/lib/typescript/credential/presentation/05-send-authorization-response.d.ts.map +0 -1
  99. package/src/credential/presentation/03-retrieve-jwks.ts +0 -73
  100. package/src/credential/presentation/05-send-authorization-response.ts +0 -168
@@ -0,0 +1,251 @@
1
+ import {
2
+ EncryptJwe,
3
+ SignJWT,
4
+ sha256ToBase64,
5
+ } from "@pagopa/io-react-native-jwt";
6
+ import uuid from "react-native-uuid";
7
+ import type { FetchJwks } from "./04-retrieve-rp-jwks";
8
+ import type { VerifyRequestObjectSignature } from "./05-verify-request-object";
9
+ import type { JWK } from "@pagopa/io-react-native-jwt/lib/typescript/types";
10
+ import { NoSuitableKeysFoundInEntityConfiguration } from "./errors";
11
+ import { hasStatusOrThrow, type Out } from "../../utils/misc";
12
+ import { disclose } from "../../sd-jwt";
13
+ import { PresentationDefinition, type Presentation } from "./types";
14
+ import * as z from "zod";
15
+
16
+ export type AuthorizationResponse = z.infer<typeof AuthorizationResponse>;
17
+ export const AuthorizationResponse = z.object({
18
+ status: z.string().optional(),
19
+ response_code: z
20
+ .string() /**
21
+ FIXME: [SIW-627] we expect this value from every RP implementation
22
+ Actually some RP does not return the value
23
+ We make it optional to not break the flow.
24
+ */
25
+ .optional(),
26
+ redirect_uri: z.string().optional(),
27
+ });
28
+
29
+ /**
30
+ * Selects an RSA public key (with `use = enc` and `kty = RSA`) from the set of JWK keys
31
+ * offered by the Relying Party (RP) for encryption.
32
+ *
33
+ * @param rpJwkKeys - The array of JWKs retrieved from the RP entity configuration.
34
+ * @returns The first suitable RSA public key found in the list.
35
+ * @throws {NoSuitableKeysFoundInEntityConfiguration} If no suitable RSA encryption key is found.
36
+ */
37
+ export const chooseRSAPublicKeyToEncrypt = (
38
+ rpJwkKeys: Out<FetchJwks>["keys"]
39
+ ): JWK => {
40
+ const [rsaEncKey] = rpJwkKeys.filter(
41
+ (jwk) => jwk.use === "enc" && jwk.kty === "RSA"
42
+ );
43
+
44
+ if (rsaEncKey) {
45
+ return rsaEncKey;
46
+ }
47
+
48
+ // No suitable key found
49
+ throw new NoSuitableKeysFoundInEntityConfiguration(
50
+ "No suitable RSA public key found for encryption."
51
+ );
52
+ };
53
+
54
+ /**
55
+ * Prepares a Verified Presentation (VP) token to be sent as part of an
56
+ * authorization response in an OpenID 4 Verifiable Presentations flow.
57
+ *
58
+ * @param requestObject - The request object containing the nonce, response URI, and other necessary info.
59
+ * @param presentationTuple - A tuple containing a verifiable credential, the claims to disclose,
60
+ * and a cryptographic context for signing.
61
+ * @returns An object containing the signed VP token (`vp_token`) and a `presentation_submission` object.
62
+ * @param presentationDefinition - Definition outlining presentation requirements.
63
+ * @param presentationTuple - Tuple containing:
64
+ * - A verifiable credential.
65
+ * - Claims that should be disclosed.
66
+ * - Cryptographic context for signing.
67
+ * @returns An object with:
68
+ * - `vp_token`: The signed VP token.
69
+ * - `presentation_submission`: Object mapping disclosed credentials to the request.
70
+ *
71
+ * @remarks
72
+ * 1. The `disclose()` function is used to produce a token with only the requested claims.
73
+ * 2. A new JWT is then signed, including the VP, `jti`, `iss`, `nonce`, audience, and expiration.
74
+ * 3. The `presentation_submission` object follows the OpenID 4 VP specification for describing
75
+ * how the disclosed credentials map to the request.
76
+ *
77
+ * @todo [SIW-353] Support multiple verifiable credentials in a single request.
78
+ */
79
+ export const prepareVpToken = async (
80
+ requestObject: Out<VerifyRequestObjectSignature>["requestObject"],
81
+ presentationDefinition: PresentationDefinition,
82
+ [verifiableCredential, requestedClaims, cryptoContext]: Presentation
83
+ ): Promise<{
84
+ vp_token: string;
85
+ presentation_submission: Record<string, unknown>;
86
+ }> => {
87
+ // Produce a VP token with only requested claims from the verifiable credential
88
+ const { token: vp } = await disclose(verifiableCredential, requestedClaims);
89
+
90
+ // <Issuer-signed JWT>~<Disclosure 1>~<Disclosure N>~
91
+ const sd_hash = await sha256ToBase64(`${vp}~`);
92
+
93
+ const kbJwt = await new SignJWT(cryptoContext)
94
+ .setProtectedHeader({
95
+ typ: "kb+jwt",
96
+ alg: "ES256",
97
+ })
98
+ .setPayload({
99
+ sd_hash,
100
+ nonce: requestObject.nonce,
101
+ })
102
+ .setAudience(requestObject.client_id)
103
+ .setIssuedAt()
104
+ .sign();
105
+
106
+ // <Issuer-signed JWT>~<Disclosure 1>~...~<Disclosure N>~<KB-JWT>
107
+ const vp_token = [vp, kbJwt].join("~");
108
+
109
+ // Determine the descriptor ID to use for mapping. Fallback to first input descriptor ID if not specified
110
+ // We support only one credential for now, so we get first input_descriptor and create just one descriptor_map
111
+ const presentation_submission = {
112
+ id: uuid.v4(),
113
+ definition_id: presentationDefinition.id,
114
+ descriptor_map: [
115
+ {
116
+ id: presentationDefinition?.input_descriptors[0]?.id,
117
+ path: `$`,
118
+ format: "vc+sd-jwt",
119
+ },
120
+ ],
121
+ };
122
+
123
+ return { vp_token, presentation_submission };
124
+ };
125
+
126
+ /**
127
+ * Builds a URL-encoded form body for a direct POST response without encryption.
128
+ *
129
+ * @param requestObject - Contains state, nonce, and other relevant info.
130
+ * @param vpToken - The signed VP token to include.
131
+ * @param presentationSubmission - Object mapping credential disclosures.
132
+ * @returns A URL-encoded string suitable for an `application/x-www-form-urlencoded` POST body.
133
+ */
134
+ export const buildDirectPostBody = async (
135
+ requestObject: Out<VerifyRequestObjectSignature>["requestObject"],
136
+ vpToken: string,
137
+ presentationSubmission: Record<string, unknown>
138
+ ): Promise<string> => {
139
+ const formUrlEncodedBody = new URLSearchParams({
140
+ state: requestObject.state,
141
+ presentation_submission: JSON.stringify(presentationSubmission),
142
+ vp_token: vpToken,
143
+ });
144
+
145
+ return formUrlEncodedBody.toString();
146
+ };
147
+
148
+ /**
149
+ * Builds a URL-encoded form body for a direct POST response using JWT encryption.
150
+ *
151
+ * @param jwkKeys - Array of JWKs from the Relying Party for encryption.
152
+ * @param requestObject - Contains state, nonce, and other relevant info.
153
+ * @param vpToken - The signed VP token to encrypt.
154
+ * @param presentationSubmission - Object mapping credential disclosures.
155
+ * @returns A URL-encoded string for an `application/x-www-form-urlencoded` POST body,
156
+ * where `response` contains the encrypted JWE.
157
+ */
158
+ export const buildDirectPostJwtBody = async (
159
+ jwkKeys: Out<FetchJwks>["keys"],
160
+ requestObject: Out<VerifyRequestObjectSignature>["requestObject"],
161
+ vpToken: string,
162
+ presentationSubmission: Record<string, unknown>
163
+ ): Promise<string> => {
164
+ // Prepare the authorization response payload to be encrypted
165
+ const authzResponsePayload = JSON.stringify({
166
+ state: requestObject.state,
167
+ presentation_submission: presentationSubmission,
168
+ vp_token: vpToken,
169
+ });
170
+
171
+ // Choose a suitable RSA public key for encryption
172
+ const rsaPublicJwk = chooseRSAPublicKeyToEncrypt(jwkKeys);
173
+
174
+ // Encrypt the authorization payload
175
+ const encryptedResponse = await new EncryptJwe(authzResponsePayload, {
176
+ alg: "RSA-OAEP-256",
177
+ enc: "A256CBC-HS512",
178
+ kid: rsaPublicJwk.kid,
179
+ }).encrypt(rsaPublicJwk);
180
+
181
+ // Build the x-www-form-urlencoded form body
182
+ const formBody = new URLSearchParams({ response: encryptedResponse });
183
+ return formBody.toString();
184
+ };
185
+
186
+ /**
187
+ * Type definition for the function that sends the authorization response
188
+ * to the Relying Party, completing the presentation flow.
189
+ */
190
+ export type SendAuthorizationResponse = (
191
+ requestObject: Out<VerifyRequestObjectSignature>["requestObject"],
192
+ presentationDefinition: PresentationDefinition,
193
+ jwkKeys: Out<FetchJwks>["keys"],
194
+ presentation: Presentation, // TODO: [SIW-353] support multiple presentations
195
+ context?: {
196
+ appFetch?: GlobalFetch["fetch"];
197
+ }
198
+ ) => Promise<AuthorizationResponse>;
199
+
200
+ /**
201
+ * Sends the authorization response to the Relying Party (RP) using the specified `response_mode`.
202
+ * This function completes the presentation flow in an OpenID 4 Verifiable Presentations scenario.
203
+ *
204
+ * @param requestObject - The request details, including presentation requirements.
205
+ * @param presentationDefinition - The definition of the expected presentation.
206
+ * @param jwkKeys - Array of JWKs from the Relying Party for optional encryption.
207
+ * @param presentation - Tuple with verifiable credential, claims, and crypto context.
208
+ * @param context - Contains optional custom fetch implementation.
209
+ * @returns Parsed and validated authorization response from the Relying Party.
210
+ */
211
+ export const sendAuthorizationResponse: SendAuthorizationResponse = async (
212
+ requestObject,
213
+ presentationDefinition,
214
+ jwkKeys,
215
+ presentation,
216
+ { appFetch = fetch } = {}
217
+ ): Promise<AuthorizationResponse> => {
218
+ // 1. Create the VP token and associated submission mapping
219
+ const { vp_token, presentation_submission } = await prepareVpToken(
220
+ requestObject,
221
+ presentationDefinition,
222
+ presentation
223
+ );
224
+
225
+ // 2. Choose the appropriate request body builder based on response mode
226
+ const requestBody =
227
+ requestObject.response_mode === "direct_post.jwt"
228
+ ? await buildDirectPostJwtBody(
229
+ jwkKeys,
230
+ requestObject,
231
+ vp_token,
232
+ presentation_submission
233
+ )
234
+ : await buildDirectPostBody(
235
+ requestObject,
236
+ vp_token,
237
+ presentation_submission
238
+ );
239
+
240
+ // 3. Send the authorization response via HTTP POST and validate the response
241
+ return await appFetch(requestObject.response_uri, {
242
+ method: "POST",
243
+ headers: {
244
+ "Content-Type": "application/x-www-form-urlencoded",
245
+ },
246
+ body: requestBody,
247
+ })
248
+ .then(hasStatusOrThrow(200))
249
+ .then((res) => res.json())
250
+ .then(AuthorizationResponse.parse);
251
+ };
@@ -60,15 +60,54 @@ const { requestURI, clientId } = Credential.Presentation.startFlowFromQR(qrcode)
60
60
  // If use trust federation: Evaluate issuer trust
61
61
  const { rpConf } = await Credential.Presentation.evaluateRelyingPartyTrust(clientId);
62
62
 
63
+ const { requestObjectEncodedJwt } =
64
+ await Credential.Presentation.getRequestObject(requestURI, {
65
+ wiaCryptoContext: wiaCryptoContext,
66
+ appFetch: appFetch,
67
+ walletInstanceAttestation: walletInstanceAttestation,
68
+ });
69
+
70
+ // Retrieve RP JWK
63
71
  // If use trust federation: Fetch Jwks from rpConf
64
72
  const jwks = await Credential.Presentation.fetchJwksFromConfig(rpConf);
65
73
 
66
- // If not use trust: Fetch Jwks from well-know
67
- const jwks = await Credential.Presentation.fetchJwksFromUri(
68
- requestURI,
69
- appFetch,
74
+ // If not use trust: Fetch Jwks from request object
75
+ const jwks = await Credential.Presentation.fetchJwksFromRequestObject(
76
+ requestObjectEncodedJwt,
77
+ { context: { appFetch } }
70
78
  );
71
79
 
80
+ // Verify signature Request Object
81
+ const { requestObject } =
82
+ await Credential.Presentation.verifyRequestObjectSignature(
83
+ requestObjectEncodedJwt,
84
+ jwks.keys
85
+ );
86
+
87
+
88
+ const { presentationDefinition } = await Credential.Presentation.fetchPresentDefinition(
89
+ requestObject,
90
+ {
91
+ appFetch: appFetch,
92
+ },
93
+ rpConf // If trust federation is used
94
+ );
95
+
96
+ // For each credential, find it and evaluate input descriptor and disclosures
97
+ const { requiredDisclosures } = Credential.Presentation.evaluateInputDescriptionForSdJwt4VC(
98
+ inputDescriptor,
99
+ credential.payload,
100
+ disclosures
101
+ );
102
+
103
+ // After confirm disclosures in app
104
+ const authResponse = Credential.Presentation.sendAuthorizationResponse(
105
+ requestObject,
106
+ presentationDefinition,
107
+ jwks,
108
+ [credential, disclosuresRequested, { appFetch: appFetch }]
109
+ );
110
+
72
111
 
73
112
  ```
74
113
 
@@ -39,3 +39,51 @@ export class NoSuitableKeysFoundInEntityConfiguration extends IoWalletError {
39
39
  super(message);
40
40
  }
41
41
  }
42
+
43
+ /**
44
+ * When a QR code is not valid.
45
+ *
46
+ */
47
+ export class InvalidQRCodeError extends IoWalletError {
48
+ code = "ERR_INVALID_QR_CODE";
49
+
50
+ /**
51
+ * @param detail A description of why the QR code is considered invalid.
52
+ */
53
+ constructor(detail: string) {
54
+ const message = `QR code is not valid: ${detail}.`;
55
+ super(message);
56
+ }
57
+ }
58
+
59
+ /**
60
+ * When the entity is unverified because the Relying Party is not trusted.
61
+ *
62
+ */
63
+ export class UnverifiedEntityError extends IoWalletError {
64
+ code = "ERR_UNVERIFIED_RP_ENTITY";
65
+
66
+ /**
67
+ * @param reason A description of why the entity cannot be verified.
68
+ */
69
+ constructor(reason: string) {
70
+ const message = `Unverified entity: ${reason}.`;
71
+ super(message);
72
+ }
73
+ }
74
+
75
+ /**
76
+ * When some required data is missing to continue because certain attributes are not contained inside the wallet.
77
+ *
78
+ */
79
+ export class MissingDataError extends IoWalletError {
80
+ code = "ERR_MISSING_DATA";
81
+
82
+ /**
83
+ * @param missingAttributes An array or description of the attributes that are missing.
84
+ */
85
+ constructor(missingAttributes: string) {
86
+ const message = `Some required data is missing: ${missingAttributes}.`;
87
+ super(message);
88
+ }
89
+ }
@@ -4,33 +4,51 @@ import {
4
4
  type EvaluateRelyingPartyTrust,
5
5
  } from "./02-evaluate-rp-trust";
6
6
  import {
7
- fetchJwksFromUri,
7
+ getRequestObject,
8
+ type GetRequestObject,
9
+ } from "./03-get-request-object";
10
+ import {
11
+ fetchJwksFromRequestObject,
8
12
  fetchJwksFromConfig,
9
13
  type FetchJwks,
10
- } from "./03-retrieve-jwks";
14
+ } from "./04-retrieve-rp-jwks";
11
15
  import {
12
- getRequestObject,
13
- type GetRequestObject,
14
- } from "./04-get-request-object";
16
+ verifyRequestObjectSignature,
17
+ type VerifyRequestObjectSignature,
18
+ } from "./05-verify-request-object";
19
+ import {
20
+ fetchPresentDefinition,
21
+ type FetchPresentationDefinition,
22
+ } from "./06-fetch-presentation-definition";
23
+ import {
24
+ evaluateInputDescriptorForSdJwt4VC,
25
+ type EvaluateInputDescriptorSdJwt4VC,
26
+ } from "./07-evaluate-input-descriptor";
15
27
  import {
16
28
  sendAuthorizationResponse,
17
29
  type SendAuthorizationResponse,
18
- } from "./05-send-authorization-response";
30
+ } from "./08-send-authorization-response";
19
31
  import * as Errors from "./errors";
20
32
 
21
33
  export {
22
34
  startFlowFromQR,
23
35
  evaluateRelyingPartyTrust,
24
- fetchJwksFromUri,
25
- fetchJwksFromConfig,
26
36
  getRequestObject,
37
+ fetchJwksFromRequestObject,
38
+ fetchJwksFromConfig,
39
+ verifyRequestObjectSignature,
40
+ fetchPresentDefinition,
41
+ evaluateInputDescriptorForSdJwt4VC,
27
42
  sendAuthorizationResponse,
28
43
  Errors,
29
44
  };
30
45
  export type {
31
46
  StartFlow,
32
47
  EvaluateRelyingPartyTrust,
33
- FetchJwks,
34
48
  GetRequestObject,
49
+ FetchJwks,
50
+ VerifyRequestObjectSignature,
51
+ FetchPresentationDefinition,
52
+ EvaluateInputDescriptorSdJwt4VC,
35
53
  SendAuthorizationResponse,
36
54
  };
@@ -11,17 +11,73 @@ export type Presentation = [
11
11
  /* the context for the key associated to the credential */ CryptoContext
12
12
  ];
13
13
 
14
+ const Fields = z.object({
15
+ path: z.array(z.string().min(1)), // Array of JSONPath string expressions
16
+ id: z.string().optional(), // Unique string ID
17
+ purpose: z.string().optional(), // Purpose of the field
18
+ name: z.string().optional(), // Human-friendly name
19
+ filter: z.any().optional(), // JSON Schema descriptor for filtering
20
+ optional: z.boolean().optional(), // Boolean indicating if the field is optional
21
+ intent_to_retain: z.boolean().optional(), // Boolean indicating that the Verifier intends to retain the Claim's data being requested
22
+ });
23
+
24
+ // Define the Constraints Object Schema
25
+ const Constraints = z.object({
26
+ fields: z.array(Fields).optional(), // Array of Field Objects
27
+ limit_disclosure: z.enum(["required", "preferred"]).optional(), // Limit disclosure property
28
+ });
29
+
30
+ // Define the Input Descriptor Object Schema
31
+ export type InputDescriptor = z.infer<typeof InputDescriptor>;
32
+ export const InputDescriptor = z.object({
33
+ id: z.string().min(1), // Mandatory unique string ID
34
+ name: z.string().optional(), // Human-friendly name
35
+ purpose: z.string().optional(), // Purpose of the schema
36
+ format: z.record(z.string(), z.any()).optional(), // Object with Claim Format Designations
37
+ constraints: Constraints, // Constraints Object (mandatory)
38
+ group: z.string().optional(), // Match one of the grouping strings listed in the "from" values of a Submission Requirement Rule
39
+ });
40
+
41
+ const SubmissionRequirement = z.object({
42
+ name: z.string().optional(),
43
+ purpose: z.string().optional(),
44
+ rule: z.string(), // "all": all group's rules must be present, or "pick": at least group's "count" rules must be present
45
+ from: z.string().optional(), // MUST contain either a "from" or "from_nested" property
46
+ from_nested: z
47
+ .array(
48
+ z.object({
49
+ name: z.string().optional(),
50
+ purpose: z.string().optional(),
51
+ rule: z.string(),
52
+ from: z.string(),
53
+ })
54
+ )
55
+ .optional(),
56
+ count: z.number().optional(),
57
+ //"count", "min", and "max" may be present with a "pick" rule
58
+ });
59
+
60
+ export type PresentationDefinition = z.infer<typeof PresentationDefinition>;
61
+ export const PresentationDefinition = z.object({
62
+ id: z.string(),
63
+ name: z.string().optional(),
64
+ purpose: z.string().optional(),
65
+ input_descriptors: z.array(InputDescriptor),
66
+ submission_requirements: z.array(SubmissionRequirement).optional(),
67
+ });
68
+
14
69
  export type RequestObject = z.infer<typeof RequestObject>;
15
70
  export const RequestObject = z.object({
16
71
  iss: z.string().optional(), //optional by RFC 7519, mandatory for Potential
17
- iat: UnixTime,
72
+ iat: UnixTime.optional(),
18
73
  exp: UnixTime.optional(),
19
74
  state: z.string(),
20
75
  nonce: z.string(),
21
76
  response_uri: z.string(),
22
77
  response_type: z.literal("vp_token"),
23
- response_mode: z.literal("direct_post.jwt"),
78
+ response_mode: z.enum(["direct_post.jwt", "direct_post"]),
24
79
  client_id: z.string(),
25
80
  client_id_scheme: z.string(), // previous z.literal("entity_id"),
26
- scope: z.string(),
81
+ scope: z.string().optional(),
82
+ presentation_definition: PresentationDefinition.optional(),
27
83
  });
@@ -1,6 +1,7 @@
1
1
  import { UnixTime } from "../../sd-jwt/types";
2
2
  import { JWK } from "../../utils/jwk";
3
3
  import * as z from "zod";
4
+ import { PresentationDefinition } from "../../credential/presentation/types";
4
5
 
5
6
  export const TrustMark = z.object({ id: z.string(), trust_mark: z.string() });
6
7
  export type TrustMark = z.infer<typeof TrustMark>;
@@ -11,6 +12,8 @@ const RelyingPartyMetadata = z.object({
11
12
  client_name: z.string().optional(),
12
13
  jwks: z.object({ keys: z.array(JWK) }),
13
14
  contacts: z.array(z.string()).optional(),
15
+ presentation_definition: PresentationDefinition.optional(),
16
+ presentation_definition_uri: z.string().optional(),
14
17
  });
15
18
  //.passthrough();
16
19
 
@@ -1,68 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.fetchJwksFromUri = exports.fetchJwksFromConfig = void 0;
7
- var _jwk = require("../../utils/jwk");
8
- var _misc = require("../../utils/misc");
9
- var _types = require("../../entity/trust/types");
10
- /**
11
- * Defines the signature for a function that retrieves JSON Web Key Sets (JWKS) from a client.
12
- *
13
- * @template T - The tuple type representing the function arguments.
14
- * @param args - The arguments passed to the function.
15
- * @returns A promise resolving to an object containing an array of JWKs.
16
- */
17
-
18
- /**
19
- * Retrieves the JSON Web Key Set (JWKS) from the specified client's well-known endpoint.
20
- *
21
- * @param clientUrl - The base URL of the client entity from which to retrieve the JWKS.
22
- * @param options - Optional context containing a custom fetch implementation.
23
- * @param options.context - Optional context object.
24
- * @param options.context.appFetch - Optional custom fetch function to use instead of the global `fetch`.
25
- * @returns A promise resolving to an object containing an array of JWKs.
26
- * @throws Will throw an error if the JWKS retrieval fails.
27
- */
28
- const fetchJwksFromUri = async function (clientUrl) {
29
- let {
30
- context = {}
31
- } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
32
- const {
33
- appFetch = fetch
34
- } = context;
35
- const wellKnownUrl = new URL("/.well-known/jar-issuer/jwk", clientUrl).toString();
36
-
37
- // Fetches the JWKS from a specific endpoint of the entity's well-known configuration
38
- const jwks = await appFetch(wellKnownUrl, {
39
- method: "GET"
40
- }).then((0, _misc.hasStatusOrThrow)(200)).then(raw => raw.json()).then(json => _jwk.JWKS.parse(json));
41
- return {
42
- keys: jwks.keys
43
- };
44
- };
45
-
46
- /**
47
- * Retrieves the JSON Web Key Set (JWKS) from a Relying Party's entity configuration.
48
- *
49
- * @param rpConfig - The configuration object of the Relying Party entity.
50
- * @returns An object containing an array of JWKs.
51
- * @throws Will throw an error if the configuration is invalid or if JWKS is not found.
52
- */
53
- exports.fetchJwksFromUri = fetchJwksFromUri;
54
- const fetchJwksFromConfig = async rpConfig => {
55
- const parsedConfig = _types.RelyingPartyEntityConfiguration.safeParse(rpConfig);
56
- if (!parsedConfig.success) {
57
- throw new Error("Invalid Relying Party configuration.");
58
- }
59
- const jwks = parsedConfig.data.payload.metadata.wallet_relying_party.jwks;
60
- if (!jwks || !Array.isArray(jwks.keys)) {
61
- throw new Error("JWKS not found in Relying Party configuration.");
62
- }
63
- return {
64
- keys: jwks.keys
65
- };
66
- };
67
- exports.fetchJwksFromConfig = fetchJwksFromConfig;
68
- //# sourceMappingURL=03-retrieve-jwks.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["_jwk","require","_misc","_types","fetchJwksFromUri","clientUrl","context","arguments","length","undefined","appFetch","fetch","wellKnownUrl","URL","toString","jwks","method","then","hasStatusOrThrow","raw","json","JWKS","parse","keys","exports","fetchJwksFromConfig","rpConfig","parsedConfig","RelyingPartyEntityConfiguration","safeParse","success","Error","data","payload","metadata","wallet_relying_party","Array","isArray"],"sourceRoot":"../../../../src","sources":["credential/presentation/03-retrieve-jwks.ts"],"mappings":";;;;;;AAAA,IAAAA,IAAA,GAAAC,OAAA;AACA,IAAAC,KAAA,GAAAD,OAAA;AACA,IAAAE,MAAA,GAAAF,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMG,gBAEZ,GAAG,eAAAA,CAAOC,SAAS,EAA4B;EAAA,IAA1B;IAAEC,OAAO,GAAG,CAAC;EAAE,CAAC,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EACzC,MAAM;IAAEG,QAAQ,GAAGC;EAAM,CAAC,GAAGL,OAAO;EAEpC,MAAMM,YAAY,GAAG,IAAIC,GAAG,CAC1B,6BAA6B,EAC7BR,SACF,CAAC,CAACS,QAAQ,CAAC,CAAC;;EAEZ;EACA,MAAMC,IAAI,GAAG,MAAML,QAAQ,CAACE,YAAY,EAAE;IACxCI,MAAM,EAAE;EACV,CAAC,CAAC,CACCC,IAAI,CAAC,IAAAC,sBAAgB,EAAC,GAAG,CAAC,CAAC,CAC3BD,IAAI,CAAEE,GAAG,IAAKA,GAAG,CAACC,IAAI,CAAC,CAAC,CAAC,CACzBH,IAAI,CAAEG,IAAI,IAAKC,SAAI,CAACC,KAAK,CAACF,IAAI,CAAC,CAAC;EAEnC,OAAO;IACLG,IAAI,EAAER,IAAI,CAACQ;EACb,CAAC;AACH,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AANAC,OAAA,CAAApB,gBAAA,GAAAA,gBAAA;AAOO,MAAMqB,mBAEZ,GAAG,MAAOC,QAAQ,IAAK;EACtB,MAAMC,YAAY,GAAGC,sCAA+B,CAACC,SAAS,CAACH,QAAQ,CAAC;EACxE,IAAI,CAACC,YAAY,CAACG,OAAO,EAAE;IACzB,MAAM,IAAIC,KAAK,CAAC,sCAAsC,CAAC;EACzD;EAEA,MAAMhB,IAAI,GAAGY,YAAY,CAACK,IAAI,CAACC,OAAO,CAACC,QAAQ,CAACC,oBAAoB,CAACpB,IAAI;EAEzE,IAAI,CAACA,IAAI,IAAI,CAACqB,KAAK,CAACC,OAAO,CAACtB,IAAI,CAACQ,IAAI,CAAC,EAAE;IACtC,MAAM,IAAIQ,KAAK,CAAC,gDAAgD,CAAC;EACnE;EAEA,OAAO;IACLR,IAAI,EAAER,IAAI,CAACQ;EACb,CAAC;AACH,CAAC;AAACC,OAAA,CAAAC,mBAAA,GAAAA,mBAAA"}
@@ -1,82 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.getRequestObject = void 0;
7
- var _reactNativeUuid = _interopRequireDefault(require("react-native-uuid"));
8
- var _ioReactNativeJwt = require("@pagopa/io-react-native-jwt");
9
- var _dpop = require("../../utils/dpop");
10
- var _errors = require("./errors");
11
- var _misc = require("../../utils/misc");
12
- var _types = require("./types");
13
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
- /**
15
- * Obtain the Request Object for RP authentication
16
- * @see https://italia.github.io/eudi-wallet-it-docs/versione-corrente/en/relying-party-solution.html
17
- *
18
- * @param requestUri The url for the Relying Party to connect with
19
- * @param rpConf The Relying Party's configuration
20
- * @param context.wiaCryptoContext The context to access the key associated with the Wallet Instance Attestation
21
- * @param context.walletInstanceAttestation The Wallet Instance Attestation token
22
- * @param context.appFetch (optional) fetch api implementation. Default: built-in fetch
23
- * @returns The Request Object that describes the presentation
24
- */
25
- const getRequestObject = async (requestUri, _ref, jwkKeys) => {
26
- let {
27
- wiaCryptoContext,
28
- appFetch = fetch,
29
- walletInstanceAttestation
30
- } = _ref;
31
- const signedWalletInstanceDPoP = await (0, _dpop.createDPopToken)({
32
- jti: `${_reactNativeUuid.default.v4()}`,
33
- htm: "GET",
34
- htu: requestUri,
35
- ath: await (0, _ioReactNativeJwt.sha256ToBase64)(walletInstanceAttestation)
36
- }, wiaCryptoContext);
37
- const responseEncodedJwt = await appFetch(requestUri, {
38
- method: "GET",
39
- headers: {
40
- Authorization: `DPoP ${walletInstanceAttestation}`,
41
- DPoP: signedWalletInstanceDPoP
42
- }
43
- }).then((0, _misc.hasStatusOrThrow)(200)).then(res => res.json()).then(responseJson => responseJson.response);
44
- const responseJwt = (0, _ioReactNativeJwt.decode)(responseEncodedJwt);
45
- await verifyTokenSignature(jwkKeys, responseJwt);
46
-
47
- // Ensure that the request object conforms to the expected specification.
48
- const requestObject = _types.RequestObject.parse(responseJwt.payload);
49
- return {
50
- requestObject
51
- };
52
- };
53
- exports.getRequestObject = getRequestObject;
54
- const verifyTokenSignature = async (jwkKeys, responseJwt) => {
55
- var _responseJwt$protecte;
56
- // verify token signature to ensure the request object is authentic
57
- // 1. according to entity configuration if present
58
- if (jwkKeys) {
59
- const pubKey = jwkKeys.find(_ref2 => {
60
- let {
61
- kid
62
- } = _ref2;
63
- return kid === responseJwt.protectedHeader.kid;
64
- });
65
- if (!pubKey) {
66
- throw new _errors.NoSuitableKeysFoundInEntityConfiguration("Request Object signature verification");
67
- }
68
- await (0, _ioReactNativeJwt.verify)(responseJwt, pubKey);
69
- return;
70
- }
71
-
72
- // 2. If jwk is not retrieved from entity config, check if the token contains the 'jwk' attribute
73
- if ((_responseJwt$protecte = responseJwt.protectedHeader) !== null && _responseJwt$protecte !== void 0 && _responseJwt$protecte.jwk) {
74
- const pubKey = responseJwt.protectedHeader.jwk;
75
- await (0, _ioReactNativeJwt.verify)(responseJwt, pubKey);
76
- return;
77
- }
78
-
79
- // No verification condition matched: skipping signature verification for now.
80
- // TODO: [EUDIW-215] Remove skipping signature verification
81
- };
82
- //# sourceMappingURL=04-get-request-object.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["_reactNativeUuid","_interopRequireDefault","require","_ioReactNativeJwt","_dpop","_errors","_misc","_types","obj","__esModule","default","getRequestObject","requestUri","_ref","jwkKeys","wiaCryptoContext","appFetch","fetch","walletInstanceAttestation","signedWalletInstanceDPoP","createDPopToken","jti","uuid","v4","htm","htu","ath","sha256ToBase64","responseEncodedJwt","method","headers","Authorization","DPoP","then","hasStatusOrThrow","res","json","responseJson","response","responseJwt","decodeJwt","verifyTokenSignature","requestObject","RequestObject","parse","payload","exports","_responseJwt$protecte","pubKey","find","_ref2","kid","protectedHeader","NoSuitableKeysFoundInEntityConfiguration","verify","jwk"],"sourceRoot":"../../../../src","sources":["credential/presentation/04-get-request-object.ts"],"mappings":";;;;;;AAAA,IAAAA,gBAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,iBAAA,GAAAD,OAAA;AAOA,IAAAE,KAAA,GAAAF,OAAA;AACA,IAAAG,OAAA,GAAAH,OAAA;AAEA,IAAAI,KAAA,GAAAJ,OAAA;AAEA,IAAAK,MAAA,GAAAL,OAAA;AAAwC,SAAAD,uBAAAO,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAYxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMG,gBAAkC,GAAG,MAAAA,CAChDC,UAAU,EAAAC,IAAA,EAEVC,OAAO,KACJ;EAAA,IAFH;IAAEC,gBAAgB;IAAEC,QAAQ,GAAGC,KAAK;IAAEC;EAA0B,CAAC,GAAAL,IAAA;EAGjE,MAAMM,wBAAwB,GAAG,MAAM,IAAAC,qBAAe,EACpD;IACEC,GAAG,EAAG,GAAEC,wBAAI,CAACC,EAAE,CAAC,CAAE,EAAC;IACnBC,GAAG,EAAE,KAAK;IACVC,GAAG,EAAEb,UAAU;IACfc,GAAG,EAAE,MAAM,IAAAC,gCAAc,EAACT,yBAAyB;EACrD,CAAC,EACDH,gBACF,CAAC;EAED,MAAMa,kBAAkB,GAAG,MAAMZ,QAAQ,CAACJ,UAAU,EAAE;IACpDiB,MAAM,EAAE,KAAK;IACbC,OAAO,EAAE;MACPC,aAAa,EAAG,QAAOb,yBAA0B,EAAC;MAClDc,IAAI,EAAEb;IACR;EACF,CAAC,CAAC,CACCc,IAAI,CAAC,IAAAC,sBAAgB,EAAC,GAAG,CAAC,CAAC,CAC3BD,IAAI,CAAEE,GAAG,IAAKA,GAAG,CAACC,IAAI,CAAC,CAAC,CAAC,CACzBH,IAAI,CAAEI,YAAY,IAAKA,YAAY,CAACC,QAAQ,CAAC;EAEhD,MAAMC,WAAW,GAAG,IAAAC,wBAAS,EAACZ,kBAAkB,CAAC;EAEjD,MAAMa,oBAAoB,CAAC3B,OAAO,EAAEyB,WAAW,CAAC;;EAEhD;EACA,MAAMG,aAAa,GAAGC,oBAAa,CAACC,KAAK,CAACL,WAAW,CAACM,OAAO,CAAC;EAE9D,OAAO;IACLH;EACF,CAAC;AACH,CAAC;AAACI,OAAA,CAAAnC,gBAAA,GAAAA,gBAAA;AAEF,MAAM8B,oBAAoB,GAAG,MAAAA,CAC3B3B,OAAgC,EAChCyB,WAAiB,KACC;EAAA,IAAAQ,qBAAA;EAClB;EACA;EACA,IAAIjC,OAAO,EAAE;IACX,MAAMkC,MAAM,GAAGlC,OAAO,CAACmC,IAAI,CACzBC,KAAA;MAAA,IAAC;QAAEC;MAAI,CAAC,GAAAD,KAAA;MAAA,OAAKC,GAAG,KAAKZ,WAAW,CAACa,eAAe,CAACD,GAAG;IAAA,CACtD,CAAC;IACD,IAAI,CAACH,MAAM,EAAE;MACX,MAAM,IAAIK,gDAAwC,CAChD,uCACF,CAAC;IACH;IACA,MAAM,IAAAC,wBAAM,EAACf,WAAW,EAAES,MAAM,CAAC;IACjC;EACF;;EAEA;EACA,KAAAD,qBAAA,GAAIR,WAAW,CAACa,eAAe,cAAAL,qBAAA,eAA3BA,qBAAA,CAA6BQ,GAAG,EAAE;IACpC,MAAMP,MAAM,GAAGT,WAAW,CAACa,eAAe,CAACG,GAAG;IAC9C,MAAM,IAAAD,wBAAM,EAACf,WAAW,EAAES,MAAM,CAAC;IACjC;EACF;;EAEA;EACA;AACF,CAAC"}