@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.
Files changed (168) hide show
  1. package/README.md +43 -0
  2. package/lib/commonjs/credential/issuance/03-start-user-authorization.js +5 -0
  3. package/lib/commonjs/credential/issuance/03-start-user-authorization.js.map +1 -1
  4. package/lib/commonjs/credential/issuance/04-complete-user-authorization.js +17 -3
  5. package/lib/commonjs/credential/issuance/04-complete-user-authorization.js.map +1 -1
  6. package/lib/commonjs/credential/issuance/05-authorize-access.js +5 -0
  7. package/lib/commonjs/credential/issuance/05-authorize-access.js.map +1 -1
  8. package/lib/commonjs/credential/issuance/06-obtain-credential.js +13 -2
  9. package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -1
  10. package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js +10 -0
  11. package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
  12. package/lib/commonjs/credential/presentation/01-start-flow.js +14 -14
  13. package/lib/commonjs/credential/presentation/01-start-flow.js.map +1 -1
  14. package/lib/commonjs/credential/presentation/02-evaluate-rp-trust.js +4 -2
  15. package/lib/commonjs/credential/presentation/02-evaluate-rp-trust.js.map +1 -1
  16. package/lib/commonjs/credential/presentation/03-get-request-object.js +2 -2
  17. package/lib/commonjs/credential/presentation/03-get-request-object.js.map +1 -1
  18. package/lib/commonjs/credential/presentation/05-verify-request-object.js +11 -4
  19. package/lib/commonjs/credential/presentation/05-verify-request-object.js.map +1 -1
  20. package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js +54 -14
  21. package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js.map +1 -1
  22. package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js +26 -7
  23. package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
  24. package/lib/commonjs/credential/presentation/08-send-authorization-response.js +4 -4
  25. package/lib/commonjs/credential/presentation/08-send-authorization-response.js.map +1 -1
  26. package/lib/commonjs/credential/presentation/README.md +96 -2
  27. package/lib/commonjs/credential/presentation/errors.js +16 -19
  28. package/lib/commonjs/credential/presentation/errors.js.map +1 -1
  29. package/lib/commonjs/credential/presentation/index.js +27 -2
  30. package/lib/commonjs/credential/presentation/index.js.map +1 -1
  31. package/lib/commonjs/credential/presentation/types.js +1 -1
  32. package/lib/commonjs/credential/presentation/types.js.map +1 -1
  33. package/lib/commonjs/credential/status/02-status-attestation.js +2 -0
  34. package/lib/commonjs/credential/status/02-status-attestation.js.map +1 -1
  35. package/lib/commonjs/credential/status/03-verify-and-parse-status-attestation.js +3 -0
  36. package/lib/commonjs/credential/status/03-verify-and-parse-status-attestation.js.map +1 -1
  37. package/lib/commonjs/credential/trustmark/get-credential-trustmark.js +5 -0
  38. package/lib/commonjs/credential/trustmark/get-credential-trustmark.js.map +1 -1
  39. package/lib/commonjs/index.js +3 -1
  40. package/lib/commonjs/index.js.map +1 -1
  41. package/lib/commonjs/utils/decoder.js +2 -0
  42. package/lib/commonjs/utils/decoder.js.map +1 -1
  43. package/lib/commonjs/utils/logging.js +68 -0
  44. package/lib/commonjs/utils/logging.js.map +1 -0
  45. package/lib/commonjs/utils/misc.js +2 -0
  46. package/lib/commonjs/utils/misc.js.map +1 -1
  47. package/lib/commonjs/utils/par.js +2 -0
  48. package/lib/commonjs/utils/par.js.map +1 -1
  49. package/lib/commonjs/wallet-instance/index.js +4 -0
  50. package/lib/commonjs/wallet-instance/index.js.map +1 -1
  51. package/lib/commonjs/wallet-instance-attestation/issuing.js +5 -0
  52. package/lib/commonjs/wallet-instance-attestation/issuing.js.map +1 -1
  53. package/lib/module/credential/issuance/03-start-user-authorization.js +5 -0
  54. package/lib/module/credential/issuance/03-start-user-authorization.js.map +1 -1
  55. package/lib/module/credential/issuance/04-complete-user-authorization.js +17 -3
  56. package/lib/module/credential/issuance/04-complete-user-authorization.js.map +1 -1
  57. package/lib/module/credential/issuance/05-authorize-access.js +5 -0
  58. package/lib/module/credential/issuance/05-authorize-access.js.map +1 -1
  59. package/lib/module/credential/issuance/06-obtain-credential.js +13 -2
  60. package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -1
  61. package/lib/module/credential/issuance/07-verify-and-parse-credential.js +10 -0
  62. package/lib/module/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
  63. package/lib/module/credential/presentation/01-start-flow.js +14 -14
  64. package/lib/module/credential/presentation/01-start-flow.js.map +1 -1
  65. package/lib/module/credential/presentation/02-evaluate-rp-trust.js +4 -2
  66. package/lib/module/credential/presentation/02-evaluate-rp-trust.js.map +1 -1
  67. package/lib/module/credential/presentation/03-get-request-object.js +2 -2
  68. package/lib/module/credential/presentation/03-get-request-object.js.map +1 -1
  69. package/lib/module/credential/presentation/05-verify-request-object.js +11 -4
  70. package/lib/module/credential/presentation/05-verify-request-object.js.map +1 -1
  71. package/lib/module/credential/presentation/07-evaluate-dcql-query.js +55 -14
  72. package/lib/module/credential/presentation/07-evaluate-dcql-query.js.map +1 -1
  73. package/lib/module/credential/presentation/07-evaluate-input-descriptor.js +25 -6
  74. package/lib/module/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
  75. package/lib/module/credential/presentation/08-send-authorization-response.js +4 -4
  76. package/lib/module/credential/presentation/08-send-authorization-response.js.map +1 -1
  77. package/lib/module/credential/presentation/README.md +96 -2
  78. package/lib/module/credential/presentation/errors.js +13 -16
  79. package/lib/module/credential/presentation/errors.js.map +1 -1
  80. package/lib/module/credential/presentation/index.js +4 -3
  81. package/lib/module/credential/presentation/index.js.map +1 -1
  82. package/lib/module/credential/presentation/types.js +1 -1
  83. package/lib/module/credential/presentation/types.js.map +1 -1
  84. package/lib/module/credential/status/02-status-attestation.js +2 -0
  85. package/lib/module/credential/status/02-status-attestation.js.map +1 -1
  86. package/lib/module/credential/status/03-verify-and-parse-status-attestation.js +3 -0
  87. package/lib/module/credential/status/03-verify-and-parse-status-attestation.js.map +1 -1
  88. package/lib/module/credential/trustmark/get-credential-trustmark.js +5 -0
  89. package/lib/module/credential/trustmark/get-credential-trustmark.js.map +1 -1
  90. package/lib/module/index.js +2 -1
  91. package/lib/module/index.js.map +1 -1
  92. package/lib/module/utils/decoder.js +2 -0
  93. package/lib/module/utils/decoder.js.map +1 -1
  94. package/lib/module/utils/logging.js +62 -0
  95. package/lib/module/utils/logging.js.map +1 -0
  96. package/lib/module/utils/misc.js +2 -0
  97. package/lib/module/utils/misc.js.map +1 -1
  98. package/lib/module/utils/par.js +2 -0
  99. package/lib/module/utils/par.js.map +1 -1
  100. package/lib/module/wallet-instance/index.js +4 -0
  101. package/lib/module/wallet-instance/index.js.map +1 -1
  102. package/lib/module/wallet-instance-attestation/issuing.js +5 -0
  103. package/lib/module/wallet-instance-attestation/issuing.js.map +1 -1
  104. package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts.map +1 -1
  105. package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts +2 -2
  106. package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts.map +1 -1
  107. package/lib/typescript/credential/issuance/05-authorize-access.d.ts.map +1 -1
  108. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts +1 -1
  109. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -1
  110. package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts.map +1 -1
  111. package/lib/typescript/credential/presentation/01-start-flow.d.ts +17 -19
  112. package/lib/typescript/credential/presentation/01-start-flow.d.ts.map +1 -1
  113. package/lib/typescript/credential/presentation/02-evaluate-rp-trust.d.ts +1 -0
  114. package/lib/typescript/credential/presentation/02-evaluate-rp-trust.d.ts.map +1 -1
  115. package/lib/typescript/credential/presentation/03-get-request-object.d.ts +1 -4
  116. package/lib/typescript/credential/presentation/03-get-request-object.d.ts.map +1 -1
  117. package/lib/typescript/credential/presentation/05-verify-request-object.d.ts +4 -2
  118. package/lib/typescript/credential/presentation/05-verify-request-object.d.ts.map +1 -1
  119. package/lib/typescript/credential/presentation/07-evaluate-dcql-query.d.ts +13 -5
  120. package/lib/typescript/credential/presentation/07-evaluate-dcql-query.d.ts.map +1 -1
  121. package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts +7 -2
  122. package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts.map +1 -1
  123. package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts +3 -3
  124. package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts.map +1 -1
  125. package/lib/typescript/credential/presentation/errors.d.ts +14 -9
  126. package/lib/typescript/credential/presentation/errors.d.ts.map +1 -1
  127. package/lib/typescript/credential/presentation/index.d.ts +5 -4
  128. package/lib/typescript/credential/presentation/index.d.ts.map +1 -1
  129. package/lib/typescript/credential/presentation/types.d.ts +3 -3
  130. package/lib/typescript/credential/status/02-status-attestation.d.ts.map +1 -1
  131. package/lib/typescript/credential/status/03-verify-and-parse-status-attestation.d.ts.map +1 -1
  132. package/lib/typescript/credential/trustmark/get-credential-trustmark.d.ts.map +1 -1
  133. package/lib/typescript/index.d.ts +2 -1
  134. package/lib/typescript/index.d.ts.map +1 -1
  135. package/lib/typescript/utils/decoder.d.ts.map +1 -1
  136. package/lib/typescript/utils/logging.d.ts +35 -0
  137. package/lib/typescript/utils/logging.d.ts.map +1 -0
  138. package/lib/typescript/utils/misc.d.ts.map +1 -1
  139. package/lib/typescript/utils/par.d.ts.map +1 -1
  140. package/lib/typescript/wallet-instance/index.d.ts.map +1 -1
  141. package/lib/typescript/wallet-instance-attestation/issuing.d.ts.map +1 -1
  142. package/package.json +3 -3
  143. package/src/credential/issuance/03-start-user-authorization.ts +18 -0
  144. package/src/credential/issuance/04-complete-user-authorization.ts +57 -3
  145. package/src/credential/issuance/05-authorize-access.ts +16 -0
  146. package/src/credential/issuance/06-obtain-credential.ts +31 -2
  147. package/src/credential/issuance/07-verify-and-parse-credential.ts +27 -1
  148. package/src/credential/presentation/01-start-flow.ts +18 -20
  149. package/src/credential/presentation/02-evaluate-rp-trust.ts +3 -2
  150. package/src/credential/presentation/03-get-request-object.ts +4 -6
  151. package/src/credential/presentation/05-verify-request-object.ts +17 -6
  152. package/src/credential/presentation/07-evaluate-dcql-query.ts +60 -17
  153. package/src/credential/presentation/07-evaluate-input-descriptor.ts +53 -39
  154. package/src/credential/presentation/08-send-authorization-response.ts +9 -7
  155. package/src/credential/presentation/README.md +96 -2
  156. package/src/credential/presentation/errors.ts +21 -14
  157. package/src/credential/presentation/index.ts +22 -4
  158. package/src/credential/presentation/types.ts +1 -1
  159. package/src/credential/status/02-status-attestation.ts +3 -0
  160. package/src/credential/status/03-verify-and-parse-status-attestation.ts +10 -0
  161. package/src/credential/trustmark/get-credential-trustmark.ts +19 -0
  162. package/src/index.ts +2 -0
  163. package/src/utils/decoder.ts +5 -0
  164. package/src/utils/logging.ts +68 -0
  165. package/src/utils/misc.ts +5 -0
  166. package/src/utils/par.ts +6 -0
  167. package/src/wallet-instance/index.ts +17 -1
  168. 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.metadata);
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.metadata.openid_credential_verifier;
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"]) || "RSA-OAEP-256",
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 presentation
1
+ # Credential Presentation
2
2
 
3
- Currently this flow is outdated.
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
- * @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);
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
- * When a credential is not found in the wallet.
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 CredentialNotFoundError extends IoWalletError {
96
- code = "ERR_CREDENTIAL_NOT_FOUND";
101
+ export class CredentialsNotFoundError extends IoWalletError {
102
+ code = "ERR_CREDENTIALS_NOT_FOUND";
103
+ details: NotFoundDetail[];
97
104
 
98
105
  /**
99
- * @param credentialId The ID of the credential that was not found.
106
+ * @param details The details of the credentials that could not be found.
100
107
  */
101
- constructor(credentialId: string) {
102
- const message = `Credential not found: ${credentialId}.`;
103
- super(message);
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
- evaluateInputDescriptorForSdJwt4VC,
21
- type EvaluateInputDescriptorSdJwt4VC,
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
- evaluateInputDescriptorForSdJwt4VC,
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
- EvaluateInputDescriptorSdJwt4VC,
61
+ EvaluateInputDescriptors,
62
+ EvaluateDcqlQuery,
63
+ PrepareLegacyRemotePresentations,
64
+ PrepareRemotePresentations,
48
65
  SendAuthorizationResponse,
66
+ SendLegacyAuthorizationResponse,
49
67
  };
@@ -94,7 +94,7 @@ export const RequestObject = z.object({
94
94
  iss: z.string(),
95
95
  iat: UnixTime,
96
96
  exp: UnixTime,
97
- state: z.string(),
97
+ state: z.string().optional(),
98
98
  nonce: z.string(),
99
99
  response_uri: z.string(),
100
100
  response_uri_method: z.string().optional(),
@@ -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 };
@@ -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
  }