@pagopa/io-react-native-wallet 0.28.1 → 0.29.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 +17 -3
- 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 +14 -14
- package/lib/commonjs/credential/presentation/01-start-flow.js.map +1 -1
- package/lib/commonjs/credential/presentation/02-evaluate-rp-trust.js +4 -2
- package/lib/commonjs/credential/presentation/02-evaluate-rp-trust.js.map +1 -1
- package/lib/commonjs/credential/presentation/03-get-request-object.js +2 -2
- package/lib/commonjs/credential/presentation/03-get-request-object.js.map +1 -1
- package/lib/commonjs/credential/presentation/05-verify-request-object.js +11 -4
- package/lib/commonjs/credential/presentation/05-verify-request-object.js.map +1 -1
- package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js +54 -14
- package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js.map +1 -1
- package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js +26 -7
- package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
- package/lib/commonjs/credential/presentation/08-send-authorization-response.js +4 -4
- package/lib/commonjs/credential/presentation/08-send-authorization-response.js.map +1 -1
- package/lib/commonjs/credential/presentation/README.md +96 -2
- package/lib/commonjs/credential/presentation/errors.js +16 -19
- package/lib/commonjs/credential/presentation/errors.js.map +1 -1
- package/lib/commonjs/credential/presentation/index.js +27 -2
- package/lib/commonjs/credential/presentation/index.js.map +1 -1
- package/lib/commonjs/credential/presentation/types.js +1 -1
- 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/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 +17 -3
- 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 +14 -14
- package/lib/module/credential/presentation/01-start-flow.js.map +1 -1
- package/lib/module/credential/presentation/02-evaluate-rp-trust.js +4 -2
- package/lib/module/credential/presentation/02-evaluate-rp-trust.js.map +1 -1
- package/lib/module/credential/presentation/03-get-request-object.js +2 -2
- package/lib/module/credential/presentation/03-get-request-object.js.map +1 -1
- package/lib/module/credential/presentation/05-verify-request-object.js +11 -4
- package/lib/module/credential/presentation/05-verify-request-object.js.map +1 -1
- package/lib/module/credential/presentation/07-evaluate-dcql-query.js +55 -14
- package/lib/module/credential/presentation/07-evaluate-dcql-query.js.map +1 -1
- package/lib/module/credential/presentation/07-evaluate-input-descriptor.js +25 -6
- package/lib/module/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
- package/lib/module/credential/presentation/08-send-authorization-response.js +4 -4
- package/lib/module/credential/presentation/08-send-authorization-response.js.map +1 -1
- package/lib/module/credential/presentation/README.md +96 -2
- package/lib/module/credential/presentation/errors.js +13 -16
- package/lib/module/credential/presentation/errors.js.map +1 -1
- package/lib/module/credential/presentation/index.js +4 -3
- package/lib/module/credential/presentation/index.js.map +1 -1
- package/lib/module/credential/presentation/types.js +1 -1
- 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/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 +2 -2
- 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 -19
- package/lib/typescript/credential/presentation/01-start-flow.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/02-evaluate-rp-trust.d.ts +1 -0
- package/lib/typescript/credential/presentation/02-evaluate-rp-trust.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/03-get-request-object.d.ts +1 -4
- 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 +4 -2
- 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 +13 -5
- 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 +7 -2
- 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 +3 -3
- package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/errors.d.ts +14 -9
- package/lib/typescript/credential/presentation/errors.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/index.d.ts +5 -4
- package/lib/typescript/credential/presentation/index.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/types.d.ts +3 -3
- 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/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 +3 -3
- package/src/credential/issuance/03-start-user-authorization.ts +18 -0
- package/src/credential/issuance/04-complete-user-authorization.ts +57 -3
- 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 +18 -20
- package/src/credential/presentation/02-evaluate-rp-trust.ts +3 -2
- package/src/credential/presentation/03-get-request-object.ts +4 -6
- package/src/credential/presentation/05-verify-request-object.ts +17 -6
- package/src/credential/presentation/07-evaluate-dcql-query.ts +60 -17
- package/src/credential/presentation/07-evaluate-input-descriptor.ts +53 -39
- package/src/credential/presentation/08-send-authorization-response.ts +9 -7
- package/src/credential/presentation/README.md +96 -2
- package/src/credential/presentation/errors.ts +21 -14
- package/src/credential/presentation/index.ts +22 -4
- package/src/credential/presentation/types.ts +1 -1
- 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/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
@@ -60,7 +60,7 @@ export const choosePublicKeyToEncrypt = (
|
|
60
60
|
*/
|
61
61
|
export const buildDirectPostJwtBody = async (
|
62
62
|
requestObject: Out<VerifyRequestObject>["requestObject"],
|
63
|
-
rpConf: RelyingPartyEntityConfiguration["payload"],
|
63
|
+
rpConf: RelyingPartyEntityConfiguration["payload"]["metadata"],
|
64
64
|
payload: DirectAuthorizationBodyPayload | LegacyDirectAuthorizationBodyPayload
|
65
65
|
): Promise<string> => {
|
66
66
|
type Jwe = ConstructorParameters<typeof EncryptJwe>[1];
|
@@ -70,19 +70,21 @@ export const buildDirectPostJwtBody = async (
|
|
70
70
|
state: requestObject.state,
|
71
71
|
...payload,
|
72
72
|
});
|
73
|
-
|
74
73
|
// Choose a suitable public key for encryption
|
75
|
-
const { keys } = getJwksFromConfig(rpConf
|
74
|
+
const { keys } = getJwksFromConfig(rpConf);
|
76
75
|
const encPublicJwk = choosePublicKeyToEncrypt(keys);
|
77
76
|
|
78
77
|
// Encrypt the authorization payload
|
79
78
|
const {
|
80
79
|
authorization_encrypted_response_alg,
|
81
80
|
authorization_encrypted_response_enc,
|
82
|
-
} = rpConf.
|
81
|
+
} = rpConf.openid_credential_verifier;
|
82
|
+
|
83
|
+
const defaultAlg: Jwe["alg"] =
|
84
|
+
encPublicJwk.kty === "EC" ? "ECDH-ES" : "RSA-OAEP-256";
|
83
85
|
|
84
86
|
const encryptedResponse = await new EncryptJwe(authzResponsePayload, {
|
85
|
-
alg: (authorization_encrypted_response_alg as Jwe["alg"]) ||
|
87
|
+
alg: (authorization_encrypted_response_alg as Jwe["alg"]) || defaultAlg,
|
86
88
|
enc:
|
87
89
|
(authorization_encrypted_response_enc as Jwe["enc"]) || "A256CBC-HS512",
|
88
90
|
kid: encPublicJwk.kid,
|
@@ -106,7 +108,7 @@ export type SendLegacyAuthorizationResponse = (
|
|
106
108
|
requestObject: Out<VerifyRequestObject>["requestObject"],
|
107
109
|
presentationDefinitionId: string,
|
108
110
|
remotePresentations: LegacyRemotePresentation[],
|
109
|
-
rpConf: RelyingPartyEntityConfiguration["payload"],
|
111
|
+
rpConf: RelyingPartyEntityConfiguration["payload"]["metadata"],
|
110
112
|
context?: {
|
111
113
|
appFetch?: GlobalFetch["fetch"];
|
112
114
|
}
|
@@ -183,7 +185,7 @@ export const sendLegacyAuthorizationResponse: SendLegacyAuthorizationResponse =
|
|
183
185
|
export type SendAuthorizationResponse = (
|
184
186
|
requestObject: Out<VerifyRequestObject>["requestObject"],
|
185
187
|
remotePresentations: RemotePresentation[],
|
186
|
-
rpConf: RelyingPartyEntityConfiguration["payload"],
|
188
|
+
rpConf: RelyingPartyEntityConfiguration["payload"]["metadata"],
|
187
189
|
context?: {
|
188
190
|
appFetch?: GlobalFetch["fetch"];
|
189
191
|
}
|
@@ -1,3 +1,97 @@
|
|
1
|
-
# Credential
|
1
|
+
# Credential Presentation
|
2
2
|
|
3
|
-
|
3
|
+
This flow is used for remote presentation, allowing a user with a valid Wallet Instance to remotely present credentials to a Relying Party (Verifier). The presentation flow adheres to the [IT Wallet 0.9.x specification](https://italia.github.io/eid-wallet-it-docs/v0.9.3/en/relying-party-solution.html).
|
4
|
+
|
5
|
+
The Relying Party provides the Wallet with a Request Object that contains the requested credentials and claims. The Wallet validates the Request Object and asks the user for consent. Then the Wallet creates an encrypted Authorization Response that contains the Verifiable Presentation with the requested data (`vp_token`) and sends it to the Relying Party.
|
6
|
+
|
7
|
+
## Sequence Diagram
|
8
|
+
|
9
|
+
```mermaid
|
10
|
+
sequenceDiagram
|
11
|
+
autonumber
|
12
|
+
participant I as User (Wallet Instance)
|
13
|
+
participant O as Relying Party (Verifier)
|
14
|
+
|
15
|
+
O->>+I: QR-CODE: Authorization Request (`request_uri`)
|
16
|
+
I->>+O: GET: Verifier's Entity Configuration
|
17
|
+
O->>+I: Respond with metadata (including public keys)
|
18
|
+
I->>+O: GET: Request Object, resolved from `request_uri`
|
19
|
+
O->>+I: Respond with the Request Object
|
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`
|
23
|
+
```
|
24
|
+
|
25
|
+
## Mapped results
|
26
|
+
|
27
|
+
|Error|Description|
|
28
|
+
|-----|-----------|
|
29
|
+
|`ValidationFailed`|The presentation request is not valid, for instance the DCQL query is invalid.|
|
30
|
+
|`CredentialsNotFoundError`|The presentation cannot be completed because the Wallet does not contain all requested credentials. The missing credentials can be found in `details`.|
|
31
|
+
|
32
|
+
|
33
|
+
## Examples
|
34
|
+
|
35
|
+
<details>
|
36
|
+
<summary>Remote Presentation flow</summary>
|
37
|
+
|
38
|
+
**Note:** To successfully complete a remote presentation, the Wallet Instance must be in a valid state with a valid Wallet Instance Attestation.
|
39
|
+
|
40
|
+
```ts
|
41
|
+
// Retrieve and scan the qr-code, decode it and get its parameters
|
42
|
+
const qrCodeParams = decodeQrCode(qrCode)
|
43
|
+
|
44
|
+
// Start the issuance flow
|
45
|
+
const {
|
46
|
+
request_uri,
|
47
|
+
client_id,
|
48
|
+
request_uri_method,
|
49
|
+
state
|
50
|
+
} = Credential.Presentation.startFlowFromQR(qrCodeParams);
|
51
|
+
|
52
|
+
// Get the Relying Party's Entity Configuration and evaluate trust
|
53
|
+
const { rpConf } = await Credential.Presentation.evaluateRelyingPartyTrust(client_id);
|
54
|
+
|
55
|
+
// Get the Request Object from the RP
|
56
|
+
const { requestObjectEncodedJwt } =
|
57
|
+
await Credential.Presentation.getRequestObject(request_uri);
|
58
|
+
|
59
|
+
// Validate the Request Object
|
60
|
+
const { requestObject } = await Credential.Presentation.verifyRequestObject(
|
61
|
+
requestObjectEncodedJwt,
|
62
|
+
{ clientId: client_id, rpConf }
|
63
|
+
);
|
64
|
+
|
65
|
+
// All the credentials that might be requested by the Relying Party
|
66
|
+
const credentialsSdJwt = [
|
67
|
+
["credential1_keytag", "eyJraWQiOiItRl82VWdhOG4zVmVnalkyVTdZVUhLMXpMb2FELU5QVGM2M1JNSVNuTGF3IiwidHlwIjoidmMrc2Qtand0IiwiYWxnIjoiRVMyNTYifQ.eyJfc2"],
|
68
|
+
["credential2_keytag", "eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiIsImtpZCI6Ii1GXzZVZ2E4bjNWZWdqWTJVN1lVSEsxekxvYUQtTlBUYzYzUk1JU25MYXcifQ.ew0KIC"]
|
69
|
+
];
|
70
|
+
|
71
|
+
const result = Credential.Presentation.evaluateDcqlQuery(
|
72
|
+
credentialsSdJwt,
|
73
|
+
requestObject.dcql_query as DcqlQuery
|
74
|
+
);
|
75
|
+
|
76
|
+
const credentialsToPresent = result.map(
|
77
|
+
({ requiredDisclosures, ...rest }) => ({
|
78
|
+
...rest,
|
79
|
+
requestedClaims: requiredDisclosures.map(([, claimName]) => claimName),
|
80
|
+
})
|
81
|
+
);
|
82
|
+
|
83
|
+
const remotePresentations =
|
84
|
+
await Credential.Presentation.prepareRemotePresentations(
|
85
|
+
credentialsToPresent,
|
86
|
+
requestObject.nonce,
|
87
|
+
requestObject.client_id
|
88
|
+
);
|
89
|
+
|
90
|
+
const authResponse = await Credential.Presentation.sendAuthorizationResponse(
|
91
|
+
requestObject,
|
92
|
+
remotePresentations,
|
93
|
+
rpConf
|
94
|
+
);
|
95
|
+
```
|
96
|
+
|
97
|
+
</details>
|
@@ -47,12 +47,12 @@ export class NoSuitableKeysFoundInEntityConfiguration extends IoWalletError {
|
|
47
47
|
export class InvalidQRCodeError extends IoWalletError {
|
48
48
|
code = "ERR_INVALID_QR_CODE";
|
49
49
|
|
50
|
-
/**
|
51
|
-
|
52
|
-
|
53
|
-
constructor(
|
54
|
-
|
55
|
-
|
50
|
+
/** Detailed reason for the QR code validation failure. */
|
51
|
+
reason: string;
|
52
|
+
|
53
|
+
constructor(reason: string) {
|
54
|
+
super("Invalid QR code");
|
55
|
+
this.reason = reason;
|
56
56
|
}
|
57
57
|
}
|
58
58
|
|
@@ -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
|
}
|
@@ -17,12 +17,22 @@ import {
|
|
17
17
|
type FetchPresentationDefinition,
|
18
18
|
} from "./06-fetch-presentation-definition";
|
19
19
|
import {
|
20
|
-
|
21
|
-
|
20
|
+
evaluateInputDescriptors,
|
21
|
+
prepareLegacyRemotePresentations,
|
22
|
+
type EvaluateInputDescriptors,
|
23
|
+
type PrepareLegacyRemotePresentations,
|
22
24
|
} from "./07-evaluate-input-descriptor";
|
25
|
+
import {
|
26
|
+
evaluateDcqlQuery,
|
27
|
+
prepareRemotePresentations,
|
28
|
+
type EvaluateDcqlQuery,
|
29
|
+
type PrepareRemotePresentations,
|
30
|
+
} from "./07-evaluate-dcql-query";
|
23
31
|
import {
|
24
32
|
sendAuthorizationResponse,
|
25
33
|
type SendAuthorizationResponse,
|
34
|
+
sendLegacyAuthorizationResponse,
|
35
|
+
type SendLegacyAuthorizationResponse,
|
26
36
|
} from "./08-send-authorization-response";
|
27
37
|
import * as Errors from "./errors";
|
28
38
|
|
@@ -33,8 +43,12 @@ export {
|
|
33
43
|
getJwksFromConfig,
|
34
44
|
verifyRequestObject,
|
35
45
|
fetchPresentDefinition,
|
36
|
-
|
46
|
+
evaluateInputDescriptors,
|
47
|
+
evaluateDcqlQuery,
|
48
|
+
prepareLegacyRemotePresentations,
|
49
|
+
prepareRemotePresentations,
|
37
50
|
sendAuthorizationResponse,
|
51
|
+
sendLegacyAuthorizationResponse,
|
38
52
|
Errors,
|
39
53
|
};
|
40
54
|
export type {
|
@@ -44,6 +58,10 @@ export type {
|
|
44
58
|
FetchJwks,
|
45
59
|
VerifyRequestObject,
|
46
60
|
FetchPresentationDefinition,
|
47
|
-
|
61
|
+
EvaluateInputDescriptors,
|
62
|
+
EvaluateDcqlQuery,
|
63
|
+
PrepareLegacyRemotePresentations,
|
64
|
+
PrepareRemotePresentations,
|
48
65
|
SendAuthorizationResponse,
|
66
|
+
SendLegacyAuthorizationResponse,
|
49
67
|
};
|
@@ -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
|
});
|
@@ -0,0 +1,68 @@
|
|
1
|
+
/**
|
2
|
+
* Logger interface which can be provided to the Logger class as a custom implementation.
|
3
|
+
*/
|
4
|
+
export interface LoggingContext {
|
5
|
+
logDebug: (msg: string) => void;
|
6
|
+
logInfo: (msg: string) => void;
|
7
|
+
logWarn: (msg: string) => void;
|
8
|
+
logError: (msg: string) => void;
|
9
|
+
}
|
10
|
+
|
11
|
+
/**
|
12
|
+
* Supported debug levels.
|
13
|
+
*/
|
14
|
+
export enum LogLevel {
|
15
|
+
DEBUG,
|
16
|
+
INFO,
|
17
|
+
WARN,
|
18
|
+
ERROR,
|
19
|
+
}
|
20
|
+
|
21
|
+
/**
|
22
|
+
* Logger singleton class which provides a simple logging interface with an init function to set the logging context and
|
23
|
+
* a static log function to log messages based on the debug level.
|
24
|
+
* This can be used as follows:
|
25
|
+
* const logger = Logger.getInstance();
|
26
|
+
* logger.initLogging(yourLoggingContext);
|
27
|
+
* logger.log(LogLevel.DEBUG, "Debug message");
|
28
|
+
*/
|
29
|
+
export class Logger {
|
30
|
+
private static instance: Logger | null = null;
|
31
|
+
private static loggingContext?: LoggingContext;
|
32
|
+
|
33
|
+
// Private constructor to prevent direct instantiation
|
34
|
+
private constructor() {}
|
35
|
+
|
36
|
+
// Public static method to get the Logger instance
|
37
|
+
public static getInstance(): Logger {
|
38
|
+
if (Logger.instance === null) {
|
39
|
+
Logger.instance = new Logger();
|
40
|
+
}
|
41
|
+
return Logger.instance;
|
42
|
+
}
|
43
|
+
|
44
|
+
// Method to initialize the logging context
|
45
|
+
public initLogging(loggingCtx: LoggingContext): void {
|
46
|
+
Logger.loggingContext = loggingCtx;
|
47
|
+
}
|
48
|
+
|
49
|
+
// Method to log based on the level which wraps the null check for the logging context
|
50
|
+
public static log(level: LogLevel, msg: string): void {
|
51
|
+
if (Logger.loggingContext) {
|
52
|
+
switch (level) {
|
53
|
+
case LogLevel.DEBUG:
|
54
|
+
Logger.loggingContext.logDebug(msg);
|
55
|
+
break;
|
56
|
+
case LogLevel.INFO:
|
57
|
+
Logger.loggingContext.logInfo(msg);
|
58
|
+
break;
|
59
|
+
case LogLevel.WARN:
|
60
|
+
Logger.loggingContext.logWarn(msg);
|
61
|
+
break;
|
62
|
+
case LogLevel.ERROR:
|
63
|
+
Logger.loggingContext.logError(msg);
|
64
|
+
break;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
package/src/utils/misc.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import { IoWalletError, UnexpectedStatusCodeError } from "./errors";
|
2
2
|
import { sha256 } from "js-sha256";
|
3
|
+
import { LogLevel, Logger } from "./logging";
|
3
4
|
|
4
5
|
/**
|
5
6
|
* Check if a response is in the expected status, otherwise throw an error
|
@@ -13,6 +14,10 @@ export const hasStatusOrThrow =
|
|
13
14
|
async (res: Response): Promise<Response> => {
|
14
15
|
if (res.status !== status) {
|
15
16
|
const ErrorClass = customError ?? UnexpectedStatusCodeError;
|
17
|
+
Logger.log(
|
18
|
+
LogLevel.ERROR,
|
19
|
+
`Http request failed. Expected ${status}, got ${res.status}, url: ${res.url}`
|
20
|
+
);
|
16
21
|
throw new ErrorClass({
|
17
22
|
message: `Http request failed. Expected ${status}, got ${res.status}, url: ${res.url}`,
|
18
23
|
statusCode: res.status,
|
package/src/utils/par.ts
CHANGED
@@ -9,6 +9,7 @@ import * as WalletInstanceAttestation from "../wallet-instance-attestation";
|
|
9
9
|
import { generateRandomAlphaNumericString, hasStatusOrThrow } from "./misc";
|
10
10
|
import { createPopToken } from "./pop";
|
11
11
|
import { IssuerResponseError } from "./errors";
|
12
|
+
import { LogLevel, Logger } from "./logging";
|
12
13
|
|
13
14
|
export type AuthorizationDetail = z.infer<typeof AuthorizationDetail>;
|
14
15
|
export const AuthorizationDetail = z.object({
|
@@ -103,6 +104,11 @@ export const makeParRequest =
|
|
103
104
|
client_assertion: walletInstanceAttestation + "~" + signedWiaPoP,
|
104
105
|
});
|
105
106
|
|
107
|
+
Logger.log(
|
108
|
+
LogLevel.DEBUG,
|
109
|
+
`Sending to PAR endpoint ${parEndpoint}: ${formBody}`
|
110
|
+
);
|
111
|
+
|
106
112
|
return await appFetch(parEndpoint, {
|
107
113
|
method: "POST",
|
108
114
|
headers: {
|
@@ -6,6 +6,7 @@ import {
|
|
6
6
|
} from "../utils/errors";
|
7
7
|
import type { WalletInstanceData } from "../client/generated/wallet-provider";
|
8
8
|
import type { IntegrityContext } from "..";
|
9
|
+
import { LogLevel, Logger } from "../utils/logging";
|
9
10
|
|
10
11
|
export async function createWalletInstance(context: {
|
11
12
|
integrityContext: IntegrityContext;
|
@@ -13,15 +14,25 @@ export async function createWalletInstance(context: {
|
|
13
14
|
appFetch?: GlobalFetch["fetch"];
|
14
15
|
}) {
|
15
16
|
const { integrityContext } = context;
|
16
|
-
|
17
17
|
const api = getWalletProviderClient(context);
|
18
18
|
|
19
19
|
//1. Obtain nonce
|
20
20
|
const challenge = await api.get("/nonce").then((response) => response.nonce);
|
21
21
|
|
22
|
+
Logger.log(
|
23
|
+
LogLevel.DEBUG,
|
24
|
+
`Challenge obtained from ${context.walletProviderBaseUrl}: ${challenge}`
|
25
|
+
);
|
26
|
+
|
22
27
|
const keyAttestation = await integrityContext.getAttestation(challenge);
|
28
|
+
|
23
29
|
const hardwareKeyTag = integrityContext.getHardwareKeyTag();
|
24
30
|
|
31
|
+
Logger.log(
|
32
|
+
LogLevel.DEBUG,
|
33
|
+
`Key attestation: ${keyAttestation}\nAssociated hardware key tag: ${hardwareKeyTag}`
|
34
|
+
);
|
35
|
+
|
25
36
|
//2. Create Wallet Instance
|
26
37
|
await api
|
27
38
|
.post("/wallet-instances", {
|
@@ -37,6 +48,11 @@ export async function createWalletInstance(context: {
|
|
37
48
|
}
|
38
49
|
|
39
50
|
const handleCreateWalletInstanceError = (e: unknown) => {
|
51
|
+
Logger.log(
|
52
|
+
LogLevel.ERROR,
|
53
|
+
`An error occurred while calling /wallet-instances endpoint: ${e}`
|
54
|
+
);
|
55
|
+
|
40
56
|
if (!(e instanceof WalletProviderResponseError)) {
|
41
57
|
throw e;
|
42
58
|
}
|
@@ -12,6 +12,7 @@ import {
|
|
12
12
|
WalletProviderResponseErrorCodes,
|
13
13
|
} from "../utils/errors";
|
14
14
|
import { TokenResponse } from "./types";
|
15
|
+
import { LogLevel, Logger } from "../utils/logging";
|
15
16
|
|
16
17
|
/**
|
17
18
|
* Getter for an attestation request. The attestation request is a JWT that will be sent to the Wallet Provider to request a Wallet Instance Attestation.
|
@@ -92,6 +93,10 @@ export const getAttestation = async ({
|
|
92
93
|
|
93
94
|
// 1. Get nonce from backend
|
94
95
|
const challenge = await api.get("/nonce").then((response) => response.nonce);
|
96
|
+
Logger.log(
|
97
|
+
LogLevel.DEBUG,
|
98
|
+
`Challenge obtained from ${walletProviderBaseUrl}: ${challenge} `
|
99
|
+
);
|
95
100
|
|
96
101
|
// 2. Get a signed attestation request
|
97
102
|
const signedAttestationRequest = await getAttestationRequest(
|
@@ -100,6 +105,10 @@ export const getAttestation = async ({
|
|
100
105
|
integrityContext,
|
101
106
|
walletProviderBaseUrl
|
102
107
|
);
|
108
|
+
Logger.log(
|
109
|
+
LogLevel.DEBUG,
|
110
|
+
`Signed attestation request: ${signedAttestationRequest}`
|
111
|
+
);
|
103
112
|
|
104
113
|
// 3. Request WIA
|
105
114
|
const tokenResponse = await api
|
@@ -112,10 +121,20 @@ export const getAttestation = async ({
|
|
112
121
|
.then((result) => TokenResponse.parse(result))
|
113
122
|
.catch(handleAttestationCreationError);
|
114
123
|
|
124
|
+
Logger.log(
|
125
|
+
LogLevel.DEBUG,
|
126
|
+
`Obtained wallet attestation: ${tokenResponse.wallet_attestation}`
|
127
|
+
);
|
128
|
+
|
115
129
|
return tokenResponse.wallet_attestation;
|
116
130
|
};
|
117
131
|
|
118
132
|
const handleAttestationCreationError = (e: unknown) => {
|
133
|
+
Logger.log(
|
134
|
+
LogLevel.ERROR,
|
135
|
+
`An error occurred while calling /token endpoint: ${e}`
|
136
|
+
);
|
137
|
+
|
119
138
|
if (!(e instanceof WalletProviderResponseError)) {
|
120
139
|
throw e;
|
121
140
|
}
|