@pagopa/io-react-native-wallet 0.28.2 → 0.30.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 +43 -0
- package/lib/commonjs/credential/issuance/03-start-user-authorization.js +5 -0
- package/lib/commonjs/credential/issuance/03-start-user-authorization.js.map +1 -1
- package/lib/commonjs/credential/issuance/04-complete-user-authorization.js +12 -0
- package/lib/commonjs/credential/issuance/04-complete-user-authorization.js.map +1 -1
- package/lib/commonjs/credential/issuance/05-authorize-access.js +5 -0
- package/lib/commonjs/credential/issuance/05-authorize-access.js.map +1 -1
- package/lib/commonjs/credential/issuance/06-obtain-credential.js +13 -2
- package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -1
- package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js +10 -0
- package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
- package/lib/commonjs/credential/presentation/01-start-flow.js +9 -8
- package/lib/commonjs/credential/presentation/01-start-flow.js.map +1 -1
- package/lib/commonjs/credential/presentation/03-get-request-object.js +3 -2
- package/lib/commonjs/credential/presentation/03-get-request-object.js.map +1 -1
- package/lib/commonjs/credential/presentation/05-verify-request-object.js +57 -22
- package/lib/commonjs/credential/presentation/05-verify-request-object.js.map +1 -1
- package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js +43 -16
- package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js.map +1 -1
- package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js +16 -4
- package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
- package/lib/commonjs/credential/presentation/08-send-authorization-response.js +85 -3
- package/lib/commonjs/credential/presentation/08-send-authorization-response.js.map +1 -1
- package/lib/commonjs/credential/presentation/README.md +27 -9
- package/lib/commonjs/credential/presentation/errors.js +28 -23
- package/lib/commonjs/credential/presentation/errors.js.map +1 -1
- package/lib/commonjs/credential/presentation/index.js +6 -0
- package/lib/commonjs/credential/presentation/index.js.map +1 -1
- package/lib/commonjs/credential/presentation/types.js +14 -7
- package/lib/commonjs/credential/presentation/types.js.map +1 -1
- package/lib/commonjs/credential/status/02-status-attestation.js +2 -0
- package/lib/commonjs/credential/status/02-status-attestation.js.map +1 -1
- package/lib/commonjs/credential/status/03-verify-and-parse-status-attestation.js +3 -0
- package/lib/commonjs/credential/status/03-verify-and-parse-status-attestation.js.map +1 -1
- package/lib/commonjs/credential/trustmark/get-credential-trustmark.js +5 -0
- package/lib/commonjs/credential/trustmark/get-credential-trustmark.js.map +1 -1
- package/lib/commonjs/index.js +3 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/utils/decoder.js +2 -0
- package/lib/commonjs/utils/decoder.js.map +1 -1
- package/lib/commonjs/utils/error-codes.js +9 -1
- package/lib/commonjs/utils/error-codes.js.map +1 -1
- package/lib/commonjs/utils/errors.js +31 -14
- package/lib/commonjs/utils/errors.js.map +1 -1
- package/lib/commonjs/utils/logging.js +68 -0
- package/lib/commonjs/utils/logging.js.map +1 -0
- package/lib/commonjs/utils/misc.js +2 -0
- package/lib/commonjs/utils/misc.js.map +1 -1
- package/lib/commonjs/utils/par.js +2 -0
- package/lib/commonjs/utils/par.js.map +1 -1
- package/lib/commonjs/wallet-instance/index.js +4 -0
- package/lib/commonjs/wallet-instance/index.js.map +1 -1
- package/lib/commonjs/wallet-instance-attestation/issuing.js +5 -0
- package/lib/commonjs/wallet-instance-attestation/issuing.js.map +1 -1
- package/lib/module/credential/issuance/03-start-user-authorization.js +5 -0
- package/lib/module/credential/issuance/03-start-user-authorization.js.map +1 -1
- package/lib/module/credential/issuance/04-complete-user-authorization.js +12 -0
- package/lib/module/credential/issuance/04-complete-user-authorization.js.map +1 -1
- package/lib/module/credential/issuance/05-authorize-access.js +5 -0
- package/lib/module/credential/issuance/05-authorize-access.js.map +1 -1
- package/lib/module/credential/issuance/06-obtain-credential.js +13 -2
- package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -1
- package/lib/module/credential/issuance/07-verify-and-parse-credential.js +10 -0
- package/lib/module/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
- package/lib/module/credential/presentation/01-start-flow.js +9 -8
- package/lib/module/credential/presentation/01-start-flow.js.map +1 -1
- package/lib/module/credential/presentation/03-get-request-object.js +3 -2
- package/lib/module/credential/presentation/03-get-request-object.js.map +1 -1
- package/lib/module/credential/presentation/05-verify-request-object.js +58 -23
- package/lib/module/credential/presentation/05-verify-request-object.js.map +1 -1
- package/lib/module/credential/presentation/07-evaluate-dcql-query.js +44 -17
- package/lib/module/credential/presentation/07-evaluate-dcql-query.js.map +1 -1
- package/lib/module/credential/presentation/07-evaluate-input-descriptor.js +17 -5
- package/lib/module/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
- package/lib/module/credential/presentation/08-send-authorization-response.js +82 -1
- package/lib/module/credential/presentation/08-send-authorization-response.js.map +1 -1
- package/lib/module/credential/presentation/README.md +27 -9
- package/lib/module/credential/presentation/errors.js +17 -19
- package/lib/module/credential/presentation/errors.js.map +1 -1
- package/lib/module/credential/presentation/index.js +2 -2
- package/lib/module/credential/presentation/index.js.map +1 -1
- package/lib/module/credential/presentation/types.js +12 -6
- package/lib/module/credential/presentation/types.js.map +1 -1
- package/lib/module/credential/status/02-status-attestation.js +2 -0
- package/lib/module/credential/status/02-status-attestation.js.map +1 -1
- package/lib/module/credential/status/03-verify-and-parse-status-attestation.js +3 -0
- package/lib/module/credential/status/03-verify-and-parse-status-attestation.js.map +1 -1
- package/lib/module/credential/trustmark/get-credential-trustmark.js +5 -0
- package/lib/module/credential/trustmark/get-credential-trustmark.js.map +1 -1
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/decoder.js +2 -0
- package/lib/module/utils/decoder.js.map +1 -1
- package/lib/module/utils/error-codes.js +7 -0
- package/lib/module/utils/error-codes.js.map +1 -1
- package/lib/module/utils/errors.js +23 -14
- package/lib/module/utils/errors.js.map +1 -1
- package/lib/module/utils/logging.js +62 -0
- package/lib/module/utils/logging.js.map +1 -0
- package/lib/module/utils/misc.js +2 -0
- package/lib/module/utils/misc.js.map +1 -1
- package/lib/module/utils/par.js +2 -0
- package/lib/module/utils/par.js.map +1 -1
- package/lib/module/wallet-instance/index.js +4 -0
- package/lib/module/wallet-instance/index.js.map +1 -1
- package/lib/module/wallet-instance-attestation/issuing.js +5 -0
- package/lib/module/wallet-instance-attestation/issuing.js.map +1 -1
- package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/05-authorize-access.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/06-obtain-credential.d.ts +1 -1
- package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/01-start-flow.d.ts +17 -14
- package/lib/typescript/credential/presentation/01-start-flow.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/03-get-request-object.d.ts +1 -3
- package/lib/typescript/credential/presentation/03-get-request-object.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/05-verify-request-object.d.ts +2 -1
- package/lib/typescript/credential/presentation/05-verify-request-object.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/07-evaluate-dcql-query.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts +30 -2
- package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/errors.d.ts +17 -12
- package/lib/typescript/credential/presentation/errors.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/index.d.ts +3 -3
- package/lib/typescript/credential/presentation/index.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/types.d.ts +24 -17
- package/lib/typescript/credential/presentation/types.d.ts.map +1 -1
- package/lib/typescript/credential/status/02-status-attestation.d.ts.map +1 -1
- package/lib/typescript/credential/status/03-verify-and-parse-status-attestation.d.ts.map +1 -1
- package/lib/typescript/credential/trustmark/get-credential-trustmark.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +2 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/utils/decoder.d.ts.map +1 -1
- package/lib/typescript/utils/error-codes.d.ts +8 -0
- package/lib/typescript/utils/error-codes.d.ts.map +1 -1
- package/lib/typescript/utils/errors.d.ts +32 -18
- package/lib/typescript/utils/errors.d.ts.map +1 -1
- package/lib/typescript/utils/logging.d.ts +35 -0
- package/lib/typescript/utils/logging.d.ts.map +1 -0
- package/lib/typescript/utils/misc.d.ts.map +1 -1
- package/lib/typescript/utils/par.d.ts.map +1 -1
- package/lib/typescript/wallet-instance/index.d.ts.map +1 -1
- package/lib/typescript/wallet-instance-attestation/issuing.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/credential/issuance/03-start-user-authorization.ts +18 -0
- package/src/credential/issuance/04-complete-user-authorization.ts +51 -0
- package/src/credential/issuance/05-authorize-access.ts +16 -0
- package/src/credential/issuance/06-obtain-credential.ts +31 -2
- package/src/credential/issuance/07-verify-and-parse-credential.ts +27 -1
- package/src/credential/presentation/01-start-flow.ts +12 -11
- package/src/credential/presentation/03-get-request-object.ts +5 -5
- package/src/credential/presentation/05-verify-request-object.ts +73 -15
- package/src/credential/presentation/07-evaluate-dcql-query.ts +43 -18
- package/src/credential/presentation/07-evaluate-input-descriptor.ts +25 -13
- package/src/credential/presentation/08-send-authorization-response.ts +110 -3
- package/src/credential/presentation/README.md +27 -9
- package/src/credential/presentation/errors.ts +24 -17
- package/src/credential/presentation/index.ts +4 -0
- package/src/credential/presentation/types.ts +22 -10
- package/src/credential/status/02-status-attestation.ts +3 -0
- package/src/credential/status/03-verify-and-parse-status-attestation.ts +10 -0
- package/src/credential/trustmark/get-credential-trustmark.ts +19 -0
- package/src/index.ts +2 -0
- package/src/utils/decoder.ts +5 -0
- package/src/utils/error-codes.ts +11 -0
- package/src/utils/errors.ts +59 -29
- package/src/utils/logging.ts +68 -0
- package/src/utils/misc.ts +5 -0
- package/src/utils/par.ts +6 -0
- package/src/wallet-instance/index.ts +17 -1
- package/src/wallet-instance-attestation/issuing.ts +19 -0
@@ -7,12 +7,18 @@ import { hasStatusOrThrow, type Out } from "../../utils/misc";
|
|
7
7
|
import {
|
8
8
|
type RemotePresentation,
|
9
9
|
DirectAuthorizationBodyPayload,
|
10
|
+
ErrorResponse,
|
10
11
|
type LegacyRemotePresentation,
|
11
|
-
LegacyDirectAuthorizationBodyPayload,
|
12
12
|
} from "./types";
|
13
13
|
import * as z from "zod";
|
14
14
|
import type { JWK } from "../../utils/jwk";
|
15
15
|
import type { RelyingPartyEntityConfiguration } from "../../trust";
|
16
|
+
import {
|
17
|
+
RelyingPartyResponseError,
|
18
|
+
ResponseErrorBuilder,
|
19
|
+
UnexpectedStatusCodeError,
|
20
|
+
RelyingPartyResponseErrorCodes,
|
21
|
+
} from "../../utils/errors";
|
16
22
|
|
17
23
|
export type AuthorizationResponse = z.infer<typeof AuthorizationResponse>;
|
18
24
|
export const AuthorizationResponse = z.object({
|
@@ -61,7 +67,7 @@ export const choosePublicKeyToEncrypt = (
|
|
61
67
|
export const buildDirectPostJwtBody = async (
|
62
68
|
requestObject: Out<VerifyRequestObject>["requestObject"],
|
63
69
|
rpConf: RelyingPartyEntityConfiguration["payload"]["metadata"],
|
64
|
-
payload: DirectAuthorizationBodyPayload
|
70
|
+
payload: DirectAuthorizationBodyPayload
|
65
71
|
): Promise<string> => {
|
66
72
|
type Jwe = ConstructorParameters<typeof EncryptJwe>[1];
|
67
73
|
|
@@ -98,6 +104,34 @@ export const buildDirectPostJwtBody = async (
|
|
98
104
|
return formBody.toString();
|
99
105
|
};
|
100
106
|
|
107
|
+
/**
|
108
|
+
* Builds a URL-encoded form body for a direct POST response without encryption.
|
109
|
+
*
|
110
|
+
* @param requestObject - Contains state, nonce, and other relevant info.
|
111
|
+
* @param payload - Object that contains either the VP token to encrypt and the stringified mapping of the credential disclosures or the error code
|
112
|
+
* @returns A URL-encoded string suitable for an `application/x-www-form-urlencoded` POST body.
|
113
|
+
*/
|
114
|
+
export const buildDirectPostBody = async (
|
115
|
+
requestObject: Out<VerifyRequestObject>["requestObject"],
|
116
|
+
payload: DirectAuthorizationBodyPayload
|
117
|
+
): Promise<string> => {
|
118
|
+
const formUrlEncodedBody = new URLSearchParams({
|
119
|
+
...(requestObject.state && { state: requestObject.state }),
|
120
|
+
...Object.entries(payload).reduce(
|
121
|
+
(acc, [key, value]) => ({
|
122
|
+
...acc,
|
123
|
+
[key]:
|
124
|
+
Array.isArray(value) || typeof value === "object"
|
125
|
+
? JSON.stringify(value)
|
126
|
+
: value,
|
127
|
+
}),
|
128
|
+
{} as Record<string, string>
|
129
|
+
),
|
130
|
+
});
|
131
|
+
|
132
|
+
return formUrlEncodedBody.toString();
|
133
|
+
};
|
134
|
+
|
101
135
|
/**
|
102
136
|
* Type definition for the function that sends the authorization response
|
103
137
|
* to the Relying Party, completing the presentation flow.
|
@@ -218,5 +252,78 @@ export const sendAuthorizationResponse: SendAuthorizationResponse = async (
|
|
218
252
|
})
|
219
253
|
.then(hasStatusOrThrow(200))
|
220
254
|
.then((res) => res.json())
|
221
|
-
.then(AuthorizationResponse.parse)
|
255
|
+
.then(AuthorizationResponse.parse)
|
256
|
+
.catch(handleAuthorizationResponseError);
|
257
|
+
};
|
258
|
+
|
259
|
+
/**
|
260
|
+
* Type definition for the function that sends the authorization response
|
261
|
+
* to the Relying Party, completing the presentation flow.
|
262
|
+
*/
|
263
|
+
export type SendAuthorizationErrorResponse = (
|
264
|
+
requestObject: Out<VerifyRequestObject>["requestObject"],
|
265
|
+
error: { error: ErrorResponse; errorDescription: string },
|
266
|
+
context?: {
|
267
|
+
appFetch?: GlobalFetch["fetch"];
|
268
|
+
}
|
269
|
+
) => Promise<AuthorizationResponse>;
|
270
|
+
|
271
|
+
/**
|
272
|
+
* Sends the authorization error response to the Relying Party (RP) using the specified `response_mode`.
|
273
|
+
* This function completes the presentation flow in an OpenID 4 Verifiable Presentations scenario.
|
274
|
+
*
|
275
|
+
* @param requestObject - The request details, including presentation requirements.
|
276
|
+
* @param error - The response error value, with description
|
277
|
+
* @param context - Contains optional custom fetch implementation.
|
278
|
+
* @returns Parsed and validated authorization response from the Relying Party.
|
279
|
+
*/
|
280
|
+
export const sendAuthorizationErrorResponse: SendAuthorizationErrorResponse =
|
281
|
+
async (
|
282
|
+
requestObject,
|
283
|
+
{ error, errorDescription },
|
284
|
+
{ appFetch = fetch } = {}
|
285
|
+
): Promise<AuthorizationResponse> => {
|
286
|
+
const requestBody = await buildDirectPostBody(requestObject, {
|
287
|
+
error,
|
288
|
+
error_description: errorDescription,
|
289
|
+
});
|
290
|
+
|
291
|
+
return await appFetch(requestObject.response_uri, {
|
292
|
+
method: "POST",
|
293
|
+
headers: {
|
294
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
295
|
+
},
|
296
|
+
body: requestBody,
|
297
|
+
})
|
298
|
+
.then(hasStatusOrThrow(200, RelyingPartyResponseError))
|
299
|
+
.then((res) => res.json())
|
300
|
+
.then(AuthorizationResponse.parse);
|
301
|
+
};
|
302
|
+
|
303
|
+
/**
|
304
|
+
* Handle the the presentation error by mapping it to a custom exception.
|
305
|
+
* If the error is not an instance of {@link UnexpectedStatusCodeError}, it is thrown as is.
|
306
|
+
* @param e - The error to be handled
|
307
|
+
* @throws {RelyingPartyResponseError} with a specific code for more context
|
308
|
+
*/
|
309
|
+
const handleAuthorizationResponseError = (e: unknown) => {
|
310
|
+
if (!(e instanceof UnexpectedStatusCodeError)) {
|
311
|
+
throw e;
|
312
|
+
}
|
313
|
+
|
314
|
+
throw new ResponseErrorBuilder(RelyingPartyResponseError)
|
315
|
+
.handle(400, {
|
316
|
+
code: RelyingPartyResponseErrorCodes.InvalidAuthorizationResponse,
|
317
|
+
message:
|
318
|
+
"The Authorization Response contains invalid parameters or it is malformed",
|
319
|
+
})
|
320
|
+
.handle(403, {
|
321
|
+
code: RelyingPartyResponseErrorCodes.InvalidAuthorizationResponse,
|
322
|
+
message: "The Authorization Response was forbidden",
|
323
|
+
})
|
324
|
+
.handle("*", {
|
325
|
+
code: RelyingPartyResponseErrorCodes.RelyingPartyGenericError,
|
326
|
+
message: "Unable to successfully send the Authorization Response",
|
327
|
+
})
|
328
|
+
.buildFrom(e);
|
222
329
|
};
|
@@ -15,12 +15,30 @@ sequenceDiagram
|
|
15
15
|
O->>+I: QR-CODE: Authorization Request (`request_uri`)
|
16
16
|
I->>+O: GET: Verifier's Entity Configuration
|
17
17
|
O->>+I: Respond with metadata (including public keys)
|
18
|
-
I->>+O: GET: Request Object, resolved from
|
18
|
+
I->>+O: GET: Request Object, resolved from `request_uri`
|
19
19
|
O->>+I: Respond with the Request Object
|
20
|
-
I->>+
|
21
|
-
O
|
20
|
+
I->>+I: Validate Request Object and give consent
|
21
|
+
I->>+O: POST: Authorization Response with encrypted VP token
|
22
|
+
O->>+I: Respond with optional `redirect_uri`
|
22
23
|
```
|
23
24
|
|
25
|
+
## Mapped results
|
26
|
+
|
27
|
+
| Error | Description|
|
28
|
+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
29
|
+
| `InvalidRequestObject` | The Request Object is not valid, for instance it is malformed or its signature cannot be verified. |
|
30
|
+
| `DcqlError` | The DCQL query cannot be evaluated because it contains errors. |
|
31
|
+
| `CredentialsNotFoundError` | The presentation cannot be completed because the Wallet does not contain all requested credentials. The missing credentials can be found in `details`. |
|
32
|
+
| `RelyingPartyResponseError` | Error in the Relying Party's response. See the next table for more details. |
|
33
|
+
|
34
|
+
#### RelyingPartyResponseError
|
35
|
+
The following HTTP errors are mapped to a `RelyingPartyResponseError` with specific codes.
|
36
|
+
|
37
|
+
| HTTP Status | Error Code | Description |
|
38
|
+
| ------------ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
39
|
+
| `400`, `403` | `ERR_RP_INVALID_AUTHORIZATION_RESPONSE` | The Relying Party rejected the Authorization Response sent by the Wallet because it was deemed invalid. |
|
40
|
+
| `*` | `ERR_RP_GENERIC_ERROR` | This is a generic error code to map unexpected errors that occurred when interacting with the Relying Party. |
|
41
|
+
|
24
42
|
|
25
43
|
## Examples
|
26
44
|
|
@@ -35,23 +53,23 @@ const qrCodeParams = decodeQrCode(qrCode)
|
|
35
53
|
|
36
54
|
// Start the issuance flow
|
37
55
|
const {
|
38
|
-
|
39
|
-
|
40
|
-
|
56
|
+
request_uri,
|
57
|
+
client_id,
|
58
|
+
request_uri_method,
|
41
59
|
state
|
42
60
|
} = Credential.Presentation.startFlowFromQR(qrCodeParams);
|
43
61
|
|
44
62
|
// Get the Relying Party's Entity Configuration and evaluate trust
|
45
|
-
const { rpConf } = await Credential.Presentation.evaluateRelyingPartyTrust(
|
63
|
+
const { rpConf } = await Credential.Presentation.evaluateRelyingPartyTrust(client_id);
|
46
64
|
|
47
65
|
// Get the Request Object from the RP
|
48
66
|
const { requestObjectEncodedJwt } =
|
49
|
-
await Credential.Presentation.getRequestObject(
|
67
|
+
await Credential.Presentation.getRequestObject(request_uri);
|
50
68
|
|
51
69
|
// Validate the Request Object
|
52
70
|
const { requestObject } = await Credential.Presentation.verifyRequestObject(
|
53
71
|
requestObjectEncodedJwt,
|
54
|
-
{ clientId, rpConf }
|
72
|
+
{ clientId: client_id, rpConf }
|
55
73
|
);
|
56
74
|
|
57
75
|
// All the credentials that might be requested by the Relying Party
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { IoWalletError, serializeAttrs } from "../../utils/errors";
|
2
|
+
export { DcqlError } from "dcql";
|
2
3
|
|
3
4
|
/**
|
4
5
|
* An error subclass thrown when auth request decode fail
|
@@ -57,18 +58,17 @@ export class InvalidQRCodeError extends IoWalletError {
|
|
57
58
|
}
|
58
59
|
|
59
60
|
/**
|
60
|
-
* When the
|
61
|
-
*
|
61
|
+
* When the Request Object sent by the Relying Party is not valid
|
62
62
|
*/
|
63
|
-
export class
|
64
|
-
code = "
|
63
|
+
export class InvalidRequestObjectError extends IoWalletError {
|
64
|
+
code = "ERR_INVALID_REQUEST_OBJECT";
|
65
65
|
|
66
|
-
/**
|
67
|
-
|
68
|
-
|
69
|
-
constructor(
|
70
|
-
const message = `Unverified entity: ${reason}.`;
|
66
|
+
/** Detailed reason for the Request Object validation failure. */
|
67
|
+
reason: string;
|
68
|
+
|
69
|
+
constructor(message: string, reason = "unspecified") {
|
71
70
|
super(message);
|
71
|
+
this.reason = reason;
|
72
72
|
}
|
73
73
|
}
|
74
74
|
|
@@ -88,18 +88,25 @@ export class MissingDataError extends IoWalletError {
|
|
88
88
|
}
|
89
89
|
}
|
90
90
|
|
91
|
+
export type NotFoundDetail = {
|
92
|
+
id: string;
|
93
|
+
reason?: string;
|
94
|
+
vctValues?: string[];
|
95
|
+
};
|
96
|
+
|
91
97
|
/**
|
92
|
-
*
|
93
|
-
*
|
98
|
+
* Error thrown when one or more credentials cannot be found in the wallet
|
99
|
+
* and the presentation request cannot be satisfied.
|
94
100
|
*/
|
95
|
-
export class
|
96
|
-
code = "
|
101
|
+
export class CredentialsNotFoundError extends IoWalletError {
|
102
|
+
code = "ERR_CREDENTIALS_NOT_FOUND";
|
103
|
+
details: NotFoundDetail[];
|
97
104
|
|
98
105
|
/**
|
99
|
-
* @param
|
106
|
+
* @param details The details of the credentials that could not be found.
|
100
107
|
*/
|
101
|
-
constructor(
|
102
|
-
|
103
|
-
|
108
|
+
constructor(details: NotFoundDetail[]) {
|
109
|
+
super("One or more credentials cannot be found in the wallet");
|
110
|
+
this.details = details;
|
104
111
|
}
|
105
112
|
}
|
@@ -33,6 +33,8 @@ import {
|
|
33
33
|
type SendAuthorizationResponse,
|
34
34
|
sendLegacyAuthorizationResponse,
|
35
35
|
type SendLegacyAuthorizationResponse,
|
36
|
+
sendAuthorizationErrorResponse,
|
37
|
+
type SendAuthorizationErrorResponse,
|
36
38
|
} from "./08-send-authorization-response";
|
37
39
|
import * as Errors from "./errors";
|
38
40
|
|
@@ -49,6 +51,7 @@ export {
|
|
49
51
|
prepareRemotePresentations,
|
50
52
|
sendAuthorizationResponse,
|
51
53
|
sendLegacyAuthorizationResponse,
|
54
|
+
sendAuthorizationErrorResponse,
|
52
55
|
Errors,
|
53
56
|
};
|
54
57
|
export type {
|
@@ -64,4 +67,5 @@ export type {
|
|
64
67
|
PrepareRemotePresentations,
|
65
68
|
SendAuthorizationResponse,
|
66
69
|
SendLegacyAuthorizationResponse,
|
70
|
+
SendAuthorizationErrorResponse,
|
67
71
|
};
|
@@ -133,26 +133,38 @@ export const RequestObjectWalletCapabilities = z.object({
|
|
133
133
|
});
|
134
134
|
|
135
135
|
/**
|
136
|
-
*
|
137
|
-
*
|
136
|
+
* This type models the possible error responses the OpenID4VP protocol allows for a presentation of a credential.
|
137
|
+
* When the Wallet encounters one of these errors, it will notify the Relying Party through the `response_uri` endpoint.
|
138
|
+
* See https://italia.github.io/eid-wallet-it-docs/versione-corrente/en/pid-eaa-presentation.html#authorization-response-errors for more information.
|
138
139
|
*/
|
139
|
-
export type
|
140
|
-
|
141
|
-
|
140
|
+
export type ErrorResponse = z.infer<typeof ErrorResponse>;
|
141
|
+
export const ErrorResponse = z.enum([
|
142
|
+
"invalid_request_object",
|
143
|
+
"invalid_request_uri",
|
144
|
+
"vp_formats_not_supported",
|
145
|
+
"invalid_request",
|
146
|
+
"access_denied",
|
147
|
+
"invalid_client",
|
148
|
+
]);
|
149
|
+
|
142
150
|
/**
|
143
151
|
* @deprecated Use `DirectAuthorizationBodyPayload`
|
144
152
|
*/
|
145
|
-
|
153
|
+
const LegacyDirectAuthorizationBodyPayload = z.object({
|
146
154
|
vp_token: z.union([z.string(), z.array(z.string())]).optional(),
|
147
155
|
presentation_submission: z.record(z.string(), z.unknown()),
|
148
156
|
});
|
149
157
|
|
150
158
|
/**
|
151
|
-
* Authorization Response payload
|
159
|
+
* Authorization Response payload sent to the Relying Party.
|
152
160
|
*/
|
153
161
|
export type DirectAuthorizationBodyPayload = z.infer<
|
154
162
|
typeof DirectAuthorizationBodyPayload
|
155
163
|
>;
|
156
|
-
export const DirectAuthorizationBodyPayload = z.
|
157
|
-
|
158
|
-
|
164
|
+
export const DirectAuthorizationBodyPayload = z.union([
|
165
|
+
z.object({
|
166
|
+
vp_token: z.record(z.string(), z.string()),
|
167
|
+
}),
|
168
|
+
z.object({ error: ErrorResponse, error_description: z.string() }),
|
169
|
+
LegacyDirectAuthorizationBodyPayload,
|
170
|
+
]);
|
@@ -13,6 +13,7 @@ import {
|
|
13
13
|
ResponseErrorBuilder,
|
14
14
|
UnexpectedStatusCodeError,
|
15
15
|
} from "../../utils/errors";
|
16
|
+
import { LogLevel, Logger } from "../../utils/logging";
|
16
17
|
|
17
18
|
export type StatusAttestation = (
|
18
19
|
issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
|
@@ -63,6 +64,8 @@ export const statusAttestation: StatusAttestation = async (
|
|
63
64
|
credential_pop: credentialPop,
|
64
65
|
};
|
65
66
|
|
67
|
+
Logger.log(LogLevel.DEBUG, `Credential pop: ${credentialPop}`);
|
68
|
+
|
66
69
|
const result = await appFetch(statusAttUrl, {
|
67
70
|
method: "POST",
|
68
71
|
headers: {
|
@@ -4,6 +4,7 @@ import { verify, type CryptoContext } from "@pagopa/io-react-native-jwt";
|
|
4
4
|
import type { EvaluateIssuerTrust, StatusAttestation } from "../status";
|
5
5
|
import { ParsedStatusAttestation } from "./types";
|
6
6
|
import { decode as decodeJwt } from "@pagopa/io-react-native-jwt";
|
7
|
+
import { LogLevel, Logger } from "../../utils/logging";
|
7
8
|
|
8
9
|
export type VerifyAndParseStatusAttestation = (
|
9
10
|
issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
|
@@ -43,9 +44,18 @@ export const verifyAndParseStatusAttestation: VerifyAndParseStatusAttestation =
|
|
43
44
|
payload: decodedJwt.payload,
|
44
45
|
});
|
45
46
|
|
47
|
+
Logger.log(
|
48
|
+
LogLevel.DEBUG,
|
49
|
+
`Parsed status attestation: ${JSON.stringify(parsedStatusAttestation)}`
|
50
|
+
);
|
51
|
+
|
46
52
|
const holderBindingKey = await credentialCryptoContext.getPublicKey();
|
47
53
|
const { cnf } = parsedStatusAttestation.payload;
|
48
54
|
if (!cnf.jwk.kid || cnf.jwk.kid !== holderBindingKey.kid) {
|
55
|
+
Logger.log(
|
56
|
+
LogLevel.ERROR,
|
57
|
+
`Failed to verify holder binding for status attestation, expected kid: ${holderBindingKey.kid}, got: ${parsedStatusAttestation.payload.cnf.jwk.kid}`
|
58
|
+
);
|
49
59
|
throw new IoWalletError(
|
50
60
|
`Failed to verify holder binding for status attestation, expected kid: ${holderBindingKey.kid}, got: ${parsedStatusAttestation.payload.cnf.jwk.kid}`
|
51
61
|
);
|
@@ -7,6 +7,7 @@ import {
|
|
7
7
|
import * as WalletInstanceAttestation from "../../wallet-instance-attestation";
|
8
8
|
import { IoWalletError } from "../../utils/errors";
|
9
9
|
import { obfuscateString } from "../../utils/string";
|
10
|
+
import { LogLevel, Logger } from "../../utils/logging";
|
10
11
|
|
11
12
|
export type GetCredentialTrustmarkJwt = (params: {
|
12
13
|
/**
|
@@ -73,10 +74,19 @@ export const getCredentialTrustmark: GetCredentialTrustmarkJwt = async ({
|
|
73
74
|
walletInstanceAttestation
|
74
75
|
);
|
75
76
|
|
77
|
+
Logger.log(
|
78
|
+
LogLevel.DEBUG,
|
79
|
+
`Decoded wia ${JSON.stringify(decodedWia.payload)} with holder binding key ${JSON.stringify(holderBindingKey)}`
|
80
|
+
);
|
81
|
+
|
76
82
|
/**
|
77
83
|
* Check that the WIA is not expired
|
78
84
|
*/
|
79
85
|
if (decodedWia.payload.exp * 1000 < Date.now()) {
|
86
|
+
Logger.log(
|
87
|
+
LogLevel.ERROR,
|
88
|
+
`Wallet Instance Attestation expired with exp: ${decodedWia.payload.exp}`
|
89
|
+
);
|
80
90
|
throw new IoWalletError("Wallet Instance Attestation expired");
|
81
91
|
}
|
82
92
|
|
@@ -87,11 +97,20 @@ export const getCredentialTrustmark: GetCredentialTrustmarkJwt = async ({
|
|
87
97
|
const cryptoContextThumbprint = await thumbprint(holderBindingKey);
|
88
98
|
|
89
99
|
if (wiaThumbprint !== cryptoContextThumbprint) {
|
100
|
+
Logger.log(
|
101
|
+
LogLevel.ERROR,
|
102
|
+
`Failed to verify holder binding for status attestation, expected thumbprint: ${cryptoContextThumbprint}, got: ${wiaThumbprint}`
|
103
|
+
);
|
90
104
|
throw new IoWalletError(
|
91
105
|
`Failed to verify holder binding for status attestation, expected thumbprint: ${cryptoContextThumbprint}, got: ${wiaThumbprint}`
|
92
106
|
);
|
93
107
|
}
|
94
108
|
|
109
|
+
Logger.log(
|
110
|
+
LogLevel.DEBUG,
|
111
|
+
`Wia thumbprint: ${wiaThumbprint} CryptoContext thumbprint: ${cryptoContextThumbprint}`
|
112
|
+
);
|
113
|
+
|
95
114
|
/**
|
96
115
|
* Generate Trustmark signed JWT
|
97
116
|
*/
|
package/src/index.ts
CHANGED
@@ -11,6 +11,7 @@ import * as Errors from "./utils/errors";
|
|
11
11
|
import * as WalletInstanceAttestation from "./wallet-instance-attestation";
|
12
12
|
import * as Trust from "./trust";
|
13
13
|
import * as WalletInstance from "./wallet-instance";
|
14
|
+
import * as Logging from "./utils/logging";
|
14
15
|
import { AuthorizationDetail, AuthorizationDetails } from "./utils/par";
|
15
16
|
import { createCryptoContextFor } from "./utils/crypto";
|
16
17
|
import type { IntegrityContext } from "./utils/integrity";
|
@@ -27,6 +28,7 @@ export {
|
|
27
28
|
AuthorizationDetail,
|
28
29
|
AuthorizationDetails,
|
29
30
|
fixBase64EncodingOnKey,
|
31
|
+
Logging,
|
30
32
|
};
|
31
33
|
|
32
34
|
export type { IntegrityContext, AuthorizationContext };
|
package/src/utils/decoder.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import { decode as decodeJwt } from "@pagopa/io-react-native-jwt";
|
2
2
|
import type { JWTDecodeResult } from "./jwk";
|
3
3
|
import { ValidationFailed } from "./errors";
|
4
|
+
import { LogLevel, Logger } from "./logging";
|
4
5
|
|
5
6
|
/*
|
6
7
|
* Decode a form_post.jwt and return the final JWT.
|
@@ -47,6 +48,10 @@ export const getJwtFromFormPost = async (
|
|
47
48
|
}
|
48
49
|
}
|
49
50
|
|
51
|
+
Logger.log(
|
52
|
+
LogLevel.ERROR,
|
53
|
+
`Unable to obtain JWT from form_post.jwt. Form data: ${formData}`
|
54
|
+
);
|
50
55
|
throw new ValidationFailed({
|
51
56
|
message: `Unable to obtain JWT from form_post.jwt. Form data: ${formData}`,
|
52
57
|
});
|
package/src/utils/error-codes.ts
CHANGED
@@ -43,8 +43,19 @@ export const WalletProviderResponseErrorCodes = {
|
|
43
43
|
WalletInstanceNotFound: "ERR_IO_WALLET_INSTANCE_NOT_FOUND",
|
44
44
|
} as const;
|
45
45
|
|
46
|
+
export const RelyingPartyResponseErrorCodes = {
|
47
|
+
RelyingPartyGenericError: "ERR_RP_GENERIC_ERROR",
|
48
|
+
/**
|
49
|
+
* An error code thrown then the Relying Party rejects the Wallet's Authorization Response.
|
50
|
+
*/
|
51
|
+
InvalidAuthorizationResponse: "ERR_RP_INVALID_AUTHORIZATION_RESPONSE",
|
52
|
+
} as const;
|
53
|
+
|
46
54
|
export type IssuerResponseErrorCode =
|
47
55
|
(typeof IssuerResponseErrorCodes)[keyof typeof IssuerResponseErrorCodes];
|
48
56
|
|
49
57
|
export type WalletProviderResponseErrorCode =
|
50
58
|
(typeof WalletProviderResponseErrorCodes)[keyof typeof WalletProviderResponseErrorCodes];
|
59
|
+
|
60
|
+
export type RelyingPartyResponseErrorCode =
|
61
|
+
(typeof RelyingPartyResponseErrorCodes)[keyof typeof RelyingPartyResponseErrorCodes];
|
package/src/utils/errors.ts
CHANGED
@@ -3,11 +3,17 @@ import type { CredentialIssuerEntityConfiguration } from "../trust";
|
|
3
3
|
import {
|
4
4
|
IssuerResponseErrorCodes,
|
5
5
|
WalletProviderResponseErrorCodes,
|
6
|
+
RelyingPartyResponseErrorCodes,
|
6
7
|
type IssuerResponseErrorCode,
|
7
8
|
type WalletProviderResponseErrorCode,
|
9
|
+
type RelyingPartyResponseErrorCode,
|
8
10
|
} from "./error-codes";
|
9
11
|
|
10
|
-
export {
|
12
|
+
export {
|
13
|
+
IssuerResponseErrorCodes,
|
14
|
+
WalletProviderResponseErrorCodes,
|
15
|
+
RelyingPartyResponseErrorCodes,
|
16
|
+
};
|
11
17
|
|
12
18
|
// An error reason that supports both a string and a generic JSON object
|
13
19
|
type GenericErrorReason = string | Record<string, unknown>;
|
@@ -110,8 +116,6 @@ export class UnexpectedStatusCodeError extends IoWalletError {
|
|
110
116
|
/**
|
111
117
|
* An error subclass thrown when an Issuer HTTP request fails.
|
112
118
|
* The specific error can be found in the `code` property.
|
113
|
-
*
|
114
|
-
* The class is generic over the error code to narrow down the reason.
|
115
119
|
*/
|
116
120
|
export class IssuerResponseError extends UnexpectedStatusCodeError {
|
117
121
|
code: IssuerResponseErrorCode;
|
@@ -149,6 +153,25 @@ export class WalletProviderResponseError extends UnexpectedStatusCodeError {
|
|
149
153
|
}
|
150
154
|
}
|
151
155
|
|
156
|
+
/**
|
157
|
+
* An error subclass thrown when a Relying Party HTTP request fails.
|
158
|
+
* The specific error can be found in the `code` property.
|
159
|
+
*/
|
160
|
+
export class RelyingPartyResponseError extends UnexpectedStatusCodeError {
|
161
|
+
code: RelyingPartyResponseErrorCode;
|
162
|
+
|
163
|
+
constructor(params: {
|
164
|
+
code?: RelyingPartyResponseErrorCode;
|
165
|
+
message: string;
|
166
|
+
reason: GenericErrorReason;
|
167
|
+
statusCode: number;
|
168
|
+
}) {
|
169
|
+
super(params);
|
170
|
+
this.code =
|
171
|
+
params.code ?? RelyingPartyResponseErrorCodes.RelyingPartyGenericError;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
152
175
|
type LocalizedIssuanceError = {
|
153
176
|
[locale: string]: {
|
154
177
|
title: string;
|
@@ -200,36 +223,43 @@ export function extractErrorMessageFromIssuerConf(
|
|
200
223
|
}
|
201
224
|
|
202
225
|
/**
|
203
|
-
*
|
204
|
-
*
|
205
|
-
* @param
|
226
|
+
* Factory function to create a type guard for specific error classes.
|
227
|
+
*
|
228
|
+
* @param errorClass The error class to create the type guard for
|
229
|
+
* @returns A type guard that checks if the error is an instance of the given class and has the expected code
|
206
230
|
*/
|
207
|
-
|
208
|
-
|
209
|
-
code?:
|
210
|
-
|
211
|
-
|
231
|
+
const makeErrorTypeGuard =
|
232
|
+
<T extends typeof UnexpectedStatusCodeError>(ErrorClass: T) =>
|
233
|
+
(error: unknown, code?: ExtractErrorCode<T>): error is InstanceType<T> =>
|
234
|
+
error instanceof ErrorClass && error.code === (code ?? error.code);
|
235
|
+
|
236
|
+
export const isIssuerResponseError = makeErrorTypeGuard(IssuerResponseError);
|
237
|
+
export const isWalletProviderResponseError = makeErrorTypeGuard(
|
238
|
+
WalletProviderResponseError
|
239
|
+
);
|
240
|
+
export const isRelyingPartyResponseError = makeErrorTypeGuard(
|
241
|
+
RelyingPartyResponseError
|
242
|
+
);
|
243
|
+
|
244
|
+
// Mapping type between error classes and their allowed codes
|
245
|
+
type ErrorCodeMap =
|
246
|
+
| {
|
247
|
+
type: typeof IssuerResponseError;
|
248
|
+
code: IssuerResponseErrorCode;
|
249
|
+
}
|
250
|
+
| {
|
251
|
+
type: typeof WalletProviderResponseError;
|
252
|
+
code: WalletProviderResponseErrorCode;
|
253
|
+
}
|
254
|
+
| {
|
255
|
+
type: typeof RelyingPartyResponseError;
|
256
|
+
code: RelyingPartyResponseErrorCode;
|
257
|
+
};
|
212
258
|
|
213
|
-
|
214
|
-
* Type guard for wallet provider errors.
|
215
|
-
* @param error The error to check
|
216
|
-
* @param code Optional code to narrow down the wallet provider error
|
217
|
-
*/
|
218
|
-
export const isWalletProviderResponseError = (
|
219
|
-
error: unknown,
|
220
|
-
code?: WalletProviderResponseErrorCode
|
221
|
-
): error is WalletProviderResponseError =>
|
222
|
-
error instanceof WalletProviderResponseError &&
|
223
|
-
error.code === (code ?? error.code);
|
224
|
-
|
225
|
-
type ErrorCodeMap<T> = T extends typeof IssuerResponseError
|
226
|
-
? IssuerResponseErrorCode
|
227
|
-
: T extends typeof WalletProviderResponseError
|
228
|
-
? WalletProviderResponseErrorCode
|
229
|
-
: never;
|
259
|
+
type ExtractErrorCode<T> = Extract<ErrorCodeMap, { type: T }>["code"];
|
230
260
|
|
231
261
|
type ErrorCase<T> = {
|
232
|
-
code:
|
262
|
+
code: ExtractErrorCode<T>;
|
233
263
|
message: string;
|
234
264
|
reason?: GenericErrorReason;
|
235
265
|
};
|