@pagopa/io-react-native-wallet 0.24.1 → 0.25.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. package/lib/commonjs/client/generated/wallet-provider.js +39 -16
  2. package/lib/commonjs/client/generated/wallet-provider.js.map +1 -1
  3. package/lib/commonjs/client/index.js +25 -10
  4. package/lib/commonjs/client/index.js.map +1 -1
  5. package/lib/commonjs/credential/issuance/03-start-user-authorization.js +1 -1
  6. package/lib/commonjs/credential/issuance/04-complete-user-authorization.js +21 -14
  7. package/lib/commonjs/credential/issuance/04-complete-user-authorization.js.map +1 -1
  8. package/lib/commonjs/credential/issuance/05-authorize-access.js +5 -2
  9. package/lib/commonjs/credential/issuance/05-authorize-access.js.map +1 -1
  10. package/lib/commonjs/credential/issuance/06-obtain-credential.js +26 -17
  11. package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -1
  12. package/lib/commonjs/credential/issuance/README.md +8 -14
  13. package/lib/commonjs/credential/issuance/errors.js +52 -0
  14. package/lib/commonjs/credential/issuance/errors.js.map +1 -0
  15. package/lib/commonjs/credential/issuance/index.js +7 -2
  16. package/lib/commonjs/credential/issuance/index.js.map +1 -1
  17. package/lib/commonjs/credential/issuance/types.js +1 -5
  18. package/lib/commonjs/credential/issuance/types.js.map +1 -1
  19. package/lib/commonjs/credential/presentation/01-start-flow.js +1 -1
  20. package/lib/commonjs/credential/presentation/01-start-flow.js.map +1 -1
  21. package/lib/commonjs/credential/presentation/03-get-request-object.js +2 -2
  22. package/lib/commonjs/credential/presentation/03-get-request-object.js.map +1 -1
  23. package/lib/commonjs/credential/presentation/04-send-authorization-response.js +2 -2
  24. package/lib/commonjs/credential/presentation/04-send-authorization-response.js.map +1 -1
  25. package/lib/commonjs/credential/presentation/errors.js +49 -0
  26. package/lib/commonjs/credential/presentation/errors.js.map +1 -0
  27. package/lib/commonjs/credential/presentation/index.js +5 -0
  28. package/lib/commonjs/credential/presentation/index.js.map +1 -1
  29. package/lib/commonjs/credential/status/02-status-attestation.js +8 -6
  30. package/lib/commonjs/credential/status/02-status-attestation.js.map +1 -1
  31. package/lib/commonjs/credential/status/README.md +5 -2
  32. package/lib/commonjs/credential/status/types.js +1 -14
  33. package/lib/commonjs/credential/status/types.js.map +1 -1
  34. package/lib/commonjs/sd-jwt/errors.js +40 -0
  35. package/lib/commonjs/sd-jwt/errors.js.map +1 -0
  36. package/lib/commonjs/sd-jwt/index.js +8 -4
  37. package/lib/commonjs/sd-jwt/index.js.map +1 -1
  38. package/lib/commonjs/sd-jwt/verifier.js +5 -1
  39. package/lib/commonjs/sd-jwt/verifier.js.map +1 -1
  40. package/lib/commonjs/trust/index.js +2 -2
  41. package/lib/commonjs/trust/index.js.map +1 -1
  42. package/lib/commonjs/utils/decoder.js +3 -1
  43. package/lib/commonjs/utils/decoder.js.map +1 -1
  44. package/lib/commonjs/utils/error-codes.js +51 -0
  45. package/lib/commonjs/utils/error-codes.js.map +1 -0
  46. package/lib/commonjs/utils/errors.js +119 -463
  47. package/lib/commonjs/utils/errors.js.map +1 -1
  48. package/lib/commonjs/utils/misc.js +21 -14
  49. package/lib/commonjs/utils/misc.js.map +1 -1
  50. package/lib/commonjs/utils/par.js +2 -1
  51. package/lib/commonjs/utils/par.js.map +1 -1
  52. package/lib/commonjs/wallet-instance/README.md +26 -5
  53. package/lib/commonjs/wallet-instance/index.js +33 -7
  54. package/lib/commonjs/wallet-instance/index.js.map +1 -1
  55. package/lib/commonjs/wallet-instance-attestation/README.md +8 -2
  56. package/lib/commonjs/wallet-instance-attestation/issuing.js +13 -10
  57. package/lib/commonjs/wallet-instance-attestation/issuing.js.map +1 -1
  58. package/lib/module/client/generated/wallet-provider.js +31 -11
  59. package/lib/module/client/generated/wallet-provider.js.map +1 -1
  60. package/lib/module/client/index.js +22 -8
  61. package/lib/module/client/index.js.map +1 -1
  62. package/lib/module/credential/issuance/03-start-user-authorization.js +1 -1
  63. package/lib/module/credential/issuance/04-complete-user-authorization.js +16 -9
  64. package/lib/module/credential/issuance/04-complete-user-authorization.js.map +1 -1
  65. package/lib/module/credential/issuance/05-authorize-access.js +7 -4
  66. package/lib/module/credential/issuance/05-authorize-access.js.map +1 -1
  67. package/lib/module/credential/issuance/06-obtain-credential.js +29 -20
  68. package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -1
  69. package/lib/module/credential/issuance/README.md +8 -14
  70. package/lib/module/credential/issuance/errors.js +44 -0
  71. package/lib/module/credential/issuance/errors.js.map +1 -0
  72. package/lib/module/credential/issuance/index.js +3 -2
  73. package/lib/module/credential/issuance/index.js.map +1 -1
  74. package/lib/module/credential/issuance/types.js +0 -3
  75. package/lib/module/credential/issuance/types.js.map +1 -1
  76. package/lib/module/credential/presentation/01-start-flow.js +1 -1
  77. package/lib/module/credential/presentation/01-start-flow.js.map +1 -1
  78. package/lib/module/credential/presentation/03-get-request-object.js +3 -3
  79. package/lib/module/credential/presentation/03-get-request-object.js.map +1 -1
  80. package/lib/module/credential/presentation/04-send-authorization-response.js +3 -3
  81. package/lib/module/credential/presentation/04-send-authorization-response.js.map +1 -1
  82. package/lib/module/credential/presentation/errors.js +42 -0
  83. package/lib/module/credential/presentation/errors.js.map +1 -0
  84. package/lib/module/credential/presentation/index.js +2 -1
  85. package/lib/module/credential/presentation/index.js.map +1 -1
  86. package/lib/module/credential/status/02-status-attestation.js +11 -9
  87. package/lib/module/credential/status/02-status-attestation.js.map +1 -1
  88. package/lib/module/credential/status/README.md +5 -2
  89. package/lib/module/credential/status/types.js +0 -12
  90. package/lib/module/credential/status/types.js.map +1 -1
  91. package/lib/module/sd-jwt/errors.js +32 -0
  92. package/lib/module/sd-jwt/errors.js.map +1 -0
  93. package/lib/module/sd-jwt/index.js +5 -5
  94. package/lib/module/sd-jwt/index.js.map +1 -1
  95. package/lib/module/sd-jwt/verifier.js +5 -1
  96. package/lib/module/sd-jwt/verifier.js.map +1 -1
  97. package/lib/module/trust/index.js +3 -3
  98. package/lib/module/trust/index.js.map +1 -1
  99. package/lib/module/utils/decoder.js +3 -1
  100. package/lib/module/utils/decoder.js.map +1 -1
  101. package/lib/module/utils/error-codes.js +43 -0
  102. package/lib/module/utils/error-codes.js.map +1 -0
  103. package/lib/module/utils/errors.js +98 -438
  104. package/lib/module/utils/errors.js.map +1 -1
  105. package/lib/module/utils/misc.js +18 -11
  106. package/lib/module/utils/misc.js.map +1 -1
  107. package/lib/module/utils/par.js +3 -2
  108. package/lib/module/utils/par.js.map +1 -1
  109. package/lib/module/wallet-instance/README.md +26 -5
  110. package/lib/module/wallet-instance/index.js +32 -7
  111. package/lib/module/wallet-instance/index.js.map +1 -1
  112. package/lib/module/wallet-instance-attestation/README.md +8 -2
  113. package/lib/module/wallet-instance-attestation/issuing.js +15 -12
  114. package/lib/module/wallet-instance-attestation/issuing.js.map +1 -1
  115. package/lib/typescript/client/generated/wallet-provider.d.ts +138 -27
  116. package/lib/typescript/client/generated/wallet-provider.d.ts.map +1 -1
  117. package/lib/typescript/client/index.d.ts +7 -1
  118. package/lib/typescript/client/index.d.ts.map +1 -1
  119. package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts +1 -1
  120. package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts +1 -1
  121. package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts.map +1 -1
  122. package/lib/typescript/credential/issuance/05-authorize-access.d.ts.map +1 -1
  123. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -1
  124. package/lib/typescript/credential/issuance/errors.d.ts +28 -0
  125. package/lib/typescript/credential/issuance/errors.d.ts.map +1 -0
  126. package/lib/typescript/credential/issuance/index.d.ts +3 -2
  127. package/lib/typescript/credential/issuance/index.d.ts.map +1 -1
  128. package/lib/typescript/credential/issuance/types.d.ts +0 -8
  129. package/lib/typescript/credential/issuance/types.d.ts.map +1 -1
  130. package/lib/typescript/credential/presentation/03-get-request-object.d.ts.map +1 -1
  131. package/lib/typescript/credential/presentation/04-send-authorization-response.d.ts.map +1 -1
  132. package/lib/typescript/credential/presentation/errors.d.ts +25 -0
  133. package/lib/typescript/credential/presentation/errors.d.ts.map +1 -0
  134. package/lib/typescript/credential/presentation/index.d.ts +2 -1
  135. package/lib/typescript/credential/presentation/index.d.ts.map +1 -1
  136. package/lib/typescript/credential/status/02-status-attestation.d.ts.map +1 -1
  137. package/lib/typescript/credential/status/types.d.ts +0 -15
  138. package/lib/typescript/credential/status/types.d.ts.map +1 -1
  139. package/lib/typescript/sd-jwt/errors.d.ts +20 -0
  140. package/lib/typescript/sd-jwt/errors.d.ts.map +1 -0
  141. package/lib/typescript/sd-jwt/index.d.ts +3 -2
  142. package/lib/typescript/sd-jwt/index.d.ts.map +1 -1
  143. package/lib/typescript/utils/error-codes.d.ts +45 -0
  144. package/lib/typescript/utils/error-codes.d.ts.map +1 -0
  145. package/lib/typescript/utils/errors.d.ts +88 -225
  146. package/lib/typescript/utils/errors.d.ts.map +1 -1
  147. package/lib/typescript/utils/misc.d.ts +9 -4
  148. package/lib/typescript/utils/misc.d.ts.map +1 -1
  149. package/lib/typescript/utils/par.d.ts.map +1 -1
  150. package/lib/typescript/wallet-instance/index.d.ts +17 -1
  151. package/lib/typescript/wallet-instance/index.d.ts.map +1 -1
  152. package/lib/typescript/wallet-instance-attestation/issuing.d.ts.map +1 -1
  153. package/lib/typescript/wallet-instance-attestation/types.d.ts +4 -4
  154. package/package.json +1 -1
  155. package/src/client/generated/wallet-provider.ts +43 -13
  156. package/src/client/index.ts +28 -15
  157. package/src/credential/issuance/03-start-user-authorization.ts +1 -1
  158. package/src/credential/issuance/04-complete-user-authorization.ts +21 -21
  159. package/src/credential/issuance/05-authorize-access.ts +7 -4
  160. package/src/credential/issuance/06-obtain-credential.ts +39 -39
  161. package/src/credential/issuance/README.md +8 -14
  162. package/src/credential/issuance/errors.ts +44 -0
  163. package/src/credential/issuance/index.ts +4 -2
  164. package/src/credential/issuance/types.ts +0 -8
  165. package/src/credential/presentation/01-start-flow.ts +1 -1
  166. package/src/credential/presentation/03-get-request-object.ts +3 -3
  167. package/src/credential/presentation/04-send-authorization-response.ts +3 -3
  168. package/src/credential/presentation/errors.ts +41 -0
  169. package/src/credential/presentation/index.ts +2 -0
  170. package/src/credential/status/02-status-attestation.ts +17 -25
  171. package/src/credential/status/README.md +5 -2
  172. package/src/credential/status/types.ts +0 -15
  173. package/src/sd-jwt/errors.ts +39 -0
  174. package/src/sd-jwt/index.ts +5 -8
  175. package/src/sd-jwt/verifier.ts +5 -5
  176. package/src/trust/index.ts +3 -3
  177. package/src/utils/decoder.ts +3 -3
  178. package/src/utils/error-codes.ts +50 -0
  179. package/src/utils/errors.ts +152 -476
  180. package/src/utils/misc.ts +20 -17
  181. package/src/utils/par.ts +3 -2
  182. package/src/wallet-instance/README.md +26 -5
  183. package/src/wallet-instance/index.ts +40 -18
  184. package/src/wallet-instance-attestation/README.md +8 -2
  185. package/src/wallet-instance-attestation/issuing.ts +28 -36
@@ -1,12 +1,16 @@
1
+ import { parseRawHttpResponse } from "../utils/misc";
1
2
  import { WalletProviderResponseError } from "../utils/errors";
2
3
  import {
3
4
  ProblemDetail,
4
5
  createApiClient as createWalletProviderApiClient,
6
+ ApiClient as WalletProviderApiClient,
7
+ type EndpointParameters,
5
8
  } from "./generated/wallet-provider";
6
- import { ApiClient as WalletProviderApiClient } from "./generated/wallet-provider";
7
9
 
8
10
  export type WalletProviderClient = WalletProviderApiClient;
9
11
 
12
+ type RawHttpResponse = Awaited<ReturnType<typeof parseRawHttpResponse>>;
13
+
10
14
  const validateResponse = async (response: Response) => {
11
15
  if (!response.ok) {
12
16
  let problemDetail: ProblemDetail = {};
@@ -18,12 +22,11 @@ const validateResponse = async (response: Response) => {
18
22
  };
19
23
  }
20
24
 
21
- throw new WalletProviderResponseError(
22
- problemDetail.title ?? "Invalid response from Wallet Provider",
23
- problemDetail.type,
24
- problemDetail.detail,
25
- response.status
26
- );
25
+ throw new WalletProviderResponseError({
26
+ message: problemDetail.title ?? "Invalid response from Wallet Provider",
27
+ reason: problemDetail,
28
+ statusCode: response.status,
29
+ });
27
30
  }
28
31
  return response;
29
32
  };
@@ -36,7 +39,7 @@ export const getWalletProviderClient = (context: {
36
39
 
37
40
  return createWalletProviderApiClient(
38
41
  (method, url, params) =>
39
- appFetch(url, {
42
+ appFetch(interpolateUrl(url, params), {
40
43
  method,
41
44
  body: params ? JSON.stringify(params.body) : undefined,
42
45
  headers: {
@@ -44,13 +47,23 @@ export const getWalletProviderClient = (context: {
44
47
  },
45
48
  })
46
49
  .then(validateResponse)
47
- .then((res) => {
48
- const contentType = res.headers.get("content-type");
49
- if (contentType?.includes("application/json")) {
50
- return res.json();
51
- }
52
- return res.text();
53
- }),
50
+ .then<RawHttpResponse>(parseRawHttpResponse),
54
51
  walletProviderBaseUrl
55
52
  );
56
53
  };
54
+
55
+ /**
56
+ * Function to interpolate the url when the request includes path params.
57
+ * The client generator expects the literal name of the param in the url
58
+ * and passes the actual values in a separate object.
59
+ */
60
+ export const interpolateUrl = (url: string, params?: EndpointParameters) => {
61
+ if (!params?.path) return url;
62
+
63
+ for (const [key, value] of Object.entries(params.path)) {
64
+ if (typeof value === "string") {
65
+ url = url.replace(`{${key}}`, value);
66
+ }
67
+ }
68
+ return url;
69
+ };
@@ -79,7 +79,7 @@ const selectResponseMode = (
79
79
 
80
80
  /**
81
81
  * WARNING: This function must be called after {@link evaluateIssuerTrust} and {@link startFlow}. The next steam is {@link compeUserAuthorizationWithQueryMode} or {@link compeUserAuthorizationWithFormPostJwtMode}
82
- * Creates and sends a PAR request to the /as/par endpoint of the authroization server.
82
+ * Creates and sends a PAR request to the /as/par endpoint of the authorization server.
83
83
  * This starts the authentication flow to obtain an access token.
84
84
  * This token enables the Wallet Instance to request a digital credential from the Credential Endpoint of the Credential Issuer.
85
85
  * This is an HTTP POST request containing the Wallet Instance identifier (client id), the code challenge and challenge method as specified by PKCE according to RFC 9126
@@ -6,19 +6,14 @@ import {
6
6
  } from "../../utils/auth";
7
7
  import {
8
8
  createAbortPromiseFromSignal,
9
- hasStatus,
9
+ hasStatusOrThrow,
10
10
  isDefined,
11
11
  until,
12
12
  type Out,
13
13
  } from "../../utils/misc";
14
14
  import type { StartUserAuthorization } from "./03-start-user-authorization";
15
15
  import parseUrl from "parse-url";
16
- import {
17
- AuthorizationError,
18
- AuthorizationIdpError,
19
- OperationAbortedError,
20
- ValidationFailed,
21
- } from "../../utils/errors";
16
+ import { IssuerResponseError, ValidationFailed } from "../../utils/errors";
22
17
  import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
23
18
  import { Linking } from "react-native";
24
19
  import {
@@ -31,6 +26,11 @@ import { RequestObject } from "../presentation/types";
31
26
  import uuid from "react-native-uuid";
32
27
  import { ResponseUriResultShape } from "./types";
33
28
  import { getJwtFromFormPost } from "../../utils/decoder";
29
+ import {
30
+ AuthorizationError,
31
+ AuthorizationIdpError,
32
+ OperationAbortedError,
33
+ } from "./errors";
34
34
 
35
35
  /**
36
36
  * The interface of the phase to complete User authorization via strong identification when the response mode is "query" and the request credential is a PersonIdentificationData.
@@ -155,7 +155,7 @@ export const completeUserAuthorizationWithQueryMode: CompleteUserAuthorizationWi
155
155
  }
156
156
 
157
157
  const query = parseUrl(authRedirectUrl).query;
158
- return parseAuthroizationResponse(query);
158
+ return parseAuthorizationResponse(query);
159
159
  };
160
160
 
161
161
  /**
@@ -183,16 +183,16 @@ export const getRequestedCredentialToBePresented: GetRequestedCredentialToBePres
183
183
  `${authzRequestEndpoint}?${params.toString()}`,
184
184
  { method: "GET" }
185
185
  )
186
- .then(hasStatus(200))
186
+ .then(hasStatusOrThrow(200, IssuerResponseError))
187
187
  .then((res) => res.text())
188
188
  .then((jws) => decode(jws))
189
189
  .then((reqObj) => RequestObject.safeParse(reqObj.payload));
190
190
 
191
191
  if (!requestObject.success) {
192
- throw new ValidationFailed(
193
- "Request Object validation failed",
194
- requestObject.error.message
195
- );
192
+ throw new ValidationFailed({
193
+ message: "Request Object validation failed",
194
+ reason: requestObject.error.message,
195
+ });
196
196
  }
197
197
  return requestObject.data;
198
198
  };
@@ -300,22 +300,22 @@ export const completeUserAuthorizationWithFormPostJwtMode: CompleteUserAuthoriza
300
300
  },
301
301
  body,
302
302
  })
303
- .then(hasStatus(200))
303
+ .then(hasStatusOrThrow(200, IssuerResponseError))
304
304
  .then((reqUri) => reqUri.json());
305
305
 
306
306
  const responseUri = ResponseUriResultShape.safeParse(resUriRes);
307
307
  if (!responseUri.success) {
308
- throw new ValidationFailed(
309
- "Response Uri validation failed",
310
- responseUri.error.message
311
- );
308
+ throw new ValidationFailed({
309
+ message: "Response Uri validation failed",
310
+ reason: responseUri.error.message,
311
+ });
312
312
  }
313
313
 
314
314
  return await appFetch(responseUri.data.redirect_uri)
315
- .then(hasStatus(200))
315
+ .then(hasStatusOrThrow(200, IssuerResponseError))
316
316
  .then((res) => res.text())
317
317
  .then(getJwtFromFormPost)
318
- .then((cbRes) => parseAuthroizationResponse(cbRes.decodedJwt.payload));
318
+ .then((cbRes) => parseAuthorizationResponse(cbRes.decodedJwt.payload));
319
319
  };
320
320
 
321
321
  /**
@@ -325,7 +325,7 @@ export const completeUserAuthorizationWithFormPostJwtMode: CompleteUserAuthoriza
325
325
  * @param authRes the authorization response to be parsed
326
326
  * @returns the authorization result which contains code, state and iss
327
327
  */
328
- export const parseAuthroizationResponse = (
328
+ export const parseAuthorizationResponse = (
329
329
  authRes: unknown
330
330
  ): AuthorizationResult => {
331
331
  const authResParsed = AuthorizationResultShape.safeParse(authRes);
@@ -1,4 +1,4 @@
1
- import { hasStatus, type Out } from "../../utils/misc";
1
+ import { hasStatusOrThrow, type Out } from "../../utils/misc";
2
2
  import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
3
3
  import type { StartUserAuthorization } from "./03-start-user-authorization";
4
4
  import { createDPopToken } from "../../utils/dpop";
@@ -8,7 +8,7 @@ import * as WalletInstanceAttestation from "../../wallet-instance-attestation";
8
8
  import type { CryptoContext } from "@pagopa/io-react-native-jwt";
9
9
  import { ASSERTION_TYPE } from "./const";
10
10
  import { TokenResponse } from "./types";
11
- import { ValidationFailed } from "../../utils/errors";
11
+ import { IssuerResponseError, ValidationFailed } from "../../utils/errors";
12
12
  import type { CompleteUserAuthorizationWithQueryMode } from "./04-complete-user-authorization";
13
13
 
14
14
  export type AuthorizeAccess = (
@@ -103,12 +103,15 @@ export const authorizeAccess: AuthorizeAccess = async (
103
103
  },
104
104
  body: authorizationRequestFormBody.toString(),
105
105
  })
106
- .then(hasStatus(200))
106
+ .then(hasStatusOrThrow(200, IssuerResponseError))
107
107
  .then((res) => res.json())
108
108
  .then((body) => TokenResponse.safeParse(body));
109
109
 
110
110
  if (!tokenRes.success) {
111
- throw new ValidationFailed(tokenRes.error.message);
111
+ throw new ValidationFailed({
112
+ message: "Token Response validation failed",
113
+ reason: tokenRes.error.message,
114
+ });
112
115
  }
113
116
 
114
117
  return { accessToken: tokenRes.data };
@@ -1,21 +1,20 @@
1
1
  import {
2
+ type CryptoContext,
2
3
  sha256ToBase64,
3
4
  SignJWT,
4
- type CryptoContext,
5
5
  } from "@pagopa/io-react-native-jwt";
6
6
  import type { AuthorizeAccess } from "./05-authorize-access";
7
7
  import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
8
- import { hasStatus, safeJsonParse, type Out } from "../../utils/misc";
8
+ import { hasStatusOrThrow, type Out } from "../../utils/misc";
9
9
  import type { StartUserAuthorization } from "./03-start-user-authorization";
10
10
  import {
11
- CredentialInvalidStatusError,
12
- CredentialIssuingNotSynchronousError,
13
- CredentialRequestError,
11
+ IssuerResponseError,
12
+ IssuerResponseErrorCodes,
13
+ ResponseErrorBuilder,
14
14
  UnexpectedStatusCodeError,
15
15
  ValidationFailed,
16
16
  } from "../../utils/errors";
17
- import { CredentialIssuanceFailureResponse, CredentialResponse } from "./types";
18
-
17
+ import { CredentialResponse } from "./types";
19
18
  import { createDPopToken } from "../../utils/dpop";
20
19
  import uuid from "react-native-uuid";
21
20
 
@@ -97,7 +96,7 @@ export const obtainCredential: ObtainCredential = async (
97
96
  );
98
97
 
99
98
  // Validation of accessTokenResponse.authorization_details if contain credentialDefinition
100
- const constainsCredentialDefinition = accessToken.authorization_details.some(
99
+ const containsCredentialDefinition = accessToken.authorization_details.some(
101
100
  (c) =>
102
101
  c.credential_configuration_id ===
103
102
  credentialDefinition.credential_configuration_id &&
@@ -105,10 +104,11 @@ export const obtainCredential: ObtainCredential = async (
105
104
  c.type === credentialDefinition.type
106
105
  );
107
106
 
108
- if (!constainsCredentialDefinition) {
109
- throw new ValidationFailed(
110
- "The access token response does not contain the requested credential"
111
- );
107
+ if (!containsCredentialDefinition) {
108
+ throw new ValidationFailed({
109
+ message:
110
+ "The access token response does not contain the requested credential",
111
+ });
112
112
  }
113
113
 
114
114
  /** The credential request body */
@@ -123,7 +123,7 @@ export const obtainCredential: ObtainCredential = async (
123
123
  },
124
124
  };
125
125
 
126
- const tokenRequestSignedDPop = await await createDPopToken(
126
+ const tokenRequestSignedDPop = await createDPopToken(
127
127
  {
128
128
  htm: "POST",
129
129
  htu: credentialUrl,
@@ -141,13 +141,16 @@ export const obtainCredential: ObtainCredential = async (
141
141
  },
142
142
  body: JSON.stringify(credentialRequestFormBody),
143
143
  })
144
- .then(hasStatus(200))
144
+ .then(hasStatusOrThrow(200))
145
145
  .then((res) => res.json())
146
146
  .then((body) => CredentialResponse.safeParse(body))
147
147
  .catch(handleObtainCredentialError);
148
148
 
149
149
  if (!credentialRes.success) {
150
- throw new ValidationFailed(credentialRes.error.message);
150
+ throw new ValidationFailed({
151
+ message: "Credential Response validation failed",
152
+ reason: credentialRes.error.message,
153
+ });
151
154
  }
152
155
 
153
156
  return credentialRes.data;
@@ -165,28 +168,25 @@ const handleObtainCredentialError = (e: unknown) => {
165
168
  throw e;
166
169
  }
167
170
 
168
- // Although it is technically not an error, we handle it as such to avoid
169
- // changing the return type of `obtainCredential` and introduce a breaking change.
170
- if (e.statusCode === 201) {
171
- throw new CredentialIssuingNotSynchronousError(
172
- "This credential cannot be issued synchronously. It will be available at a later time.",
173
- e.message
174
- );
175
- }
176
-
177
- if ([403, 404].includes(e.statusCode)) {
178
- const maybeError = CredentialIssuanceFailureResponse.safeParse(
179
- safeJsonParse(e.responseBody)
180
- );
181
- throw new CredentialInvalidStatusError(
182
- "Invalid status found for the given credential",
183
- maybeError.success ? maybeError.data.error : "unknown",
184
- e.message
185
- );
186
- }
187
-
188
- throw new CredentialRequestError(
189
- `Unable to obtain the requested credential [response status code: ${e.statusCode}]`,
190
- e.message
191
- );
171
+ throw new ResponseErrorBuilder(IssuerResponseError)
172
+ .handle(201, {
173
+ // Although it is technically not an error, we handle it as such to avoid
174
+ // changing the return type of `obtainCredential` and introduce a breaking change.
175
+ code: IssuerResponseErrorCodes.CredentialIssuingNotSynchronous,
176
+ message:
177
+ "This credential cannot be issued synchronously. It will be available at a later time.",
178
+ })
179
+ .handle(403, {
180
+ code: IssuerResponseErrorCodes.CredentialInvalidStatus,
181
+ message: "Invalid status found for the given credential",
182
+ })
183
+ .handle(404, {
184
+ code: IssuerResponseErrorCodes.CredentialInvalidStatus,
185
+ message: "Invalid status found for the given credential",
186
+ })
187
+ .handle("*", {
188
+ code: IssuerResponseErrorCodes.CredentialRequestFailed,
189
+ message: "Unable to obtain the requested credential",
190
+ })
191
+ .buildFrom(e);
192
192
  };
@@ -39,20 +39,14 @@ graph TD;
39
39
 
40
40
  ## Mapped results
41
41
 
42
- ### 201 Created (CredentialIssuingNotSynchronousError)
42
+ The following errors are mapped to a `IssuerResponseError` with specific codes.
43
43
 
44
- A `201 Created` response is returned by the credential issuer when the request has been queued because the credential cannot be issued synchronously. The consumer should try to obtain the credential at a later time.
45
-
46
- Although `201 Created` is not considered an error, it is mapped as an error in this context in order to handle the case where the credential issuance is not synchronous.
47
- This allows keeping the flow consistent and handle the case where the credential is not immediately available.
48
-
49
- ### 403 Forbidden (CredentialInvalidStatusError)
50
-
51
- A `403 Forbidden` response is returned by the credential issuer when the requested credential has an invalid status. It might contain more details in the `errorCode` property.
52
-
53
- ### 404 Not Found (CredentialInvalidStatusError)
54
-
55
- A `404 Not Found` response is returned by the credential issuer when the authenticated user is not entitled to receive the requested credential. It might contain more details in the `errorCode` property.
44
+ |HTTP Status|Error Code|Description|
45
+ |-----------|----------|-----------|
46
+ |`201 Created`|`ERR_CREDENTIAL_ISSUING_NOT_SYNCHRONOUS`| This response is returned by the credential issuer when the request has been queued because the credential cannot be issued synchronously. The consumer should try to obtain the credential at a later time. Although `201 Created` is not considered an error, it is mapped as an error in this context in order to handle the case where the credential issuance is not synchronous. This allows keeping the flow consistent and handle the case where the credential is not immediately available.|
47
+ |`403 Forbidden`|`ERR_CREDENTIAL_INVALID_STATUS`|This response is returned by the credential issuer when the requested credential has an invalid status. It might contain more details in the `reason` property.|
48
+ |`404 Not Found`|`ERR_CREDENTIAL_INVALID_STATUS`| This response is returned by the credential issuer when the authenticated user is not entitled to receive the requested credential. It might contain more details in the `reason` property.|
49
+ |`*`|`ERR_ISSUER_GENERIC_ERROR`|This is a generic error code to map unexpected errors that occurred when interacting with the Issuer.|
56
50
 
57
51
  ## Strong authentication for eID issuance (Query Mode)
58
52
 
@@ -278,7 +272,7 @@ const { issuerRequestUri, clientId, codeVerifier, credentialDefinition } =
278
272
  appFetch,
279
273
  });
280
274
 
281
- // Complete the authroization process with query mode with the authorizationContext which opens the browser
275
+ // Complete the authorization process with query mode with the authorizationContext which opens the browser
282
276
  const { code } =
283
277
  await Credential.Issuance.completeUserAuthorizationWithQueryMode(
284
278
  issuerRequestUri,
@@ -0,0 +1,44 @@
1
+ import { IoWalletError, serializeAttrs } from "../../utils/errors";
2
+
3
+ /**
4
+ * An error subclass thrown when an error occurs during the authorization process.
5
+ */
6
+ export class AuthorizationError extends IoWalletError {
7
+ code = "ERR_IO_WALLET_AUTHORIZATION_ERROR";
8
+
9
+ constructor(message?: string) {
10
+ super(message);
11
+ }
12
+ }
13
+
14
+ /**
15
+ * An error subclass thrown when an error occurs during the authorization process with the IDP.
16
+ * It contains the error and error description returned by the IDP.
17
+ */
18
+ export class AuthorizationIdpError extends IoWalletError {
19
+ code = "ERR_IO_WALLET_IDENTIFICATION_RESPONSE_PARSING_FAILED";
20
+
21
+ error: string;
22
+ errorDescription?: string;
23
+
24
+ constructor(error: string, errorDescription?: string) {
25
+ super(serializeAttrs({ error, errorDescription }));
26
+ this.error = error;
27
+ this.errorDescription = errorDescription;
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Error subclass thrown when an operation has been aborted.
33
+ */
34
+ export class OperationAbortedError extends IoWalletError {
35
+ code = "ERR_IO_WALLET_OPERATION_ABORTED";
36
+
37
+ /** The aborted operation */
38
+ operation: string;
39
+
40
+ constructor(operation: string) {
41
+ super(serializeAttrs({ operation }));
42
+ this.operation = operation;
43
+ }
44
+ }
@@ -10,7 +10,7 @@ import {
10
10
  import {
11
11
  completeUserAuthorizationWithQueryMode,
12
12
  completeUserAuthorizationWithFormPostJwtMode,
13
- parseAuthroizationResponse,
13
+ parseAuthorizationResponse,
14
14
  type CompleteUserAuthorizationWithQueryMode,
15
15
  type CompleteUserAuthorizationWithFormPostJwtMode,
16
16
  type GetRequestedCredentialToBePresented,
@@ -25,6 +25,7 @@ import {
25
25
  verifyAndParseCredential,
26
26
  type VerifyAndParseCredential,
27
27
  } from "./07-verify-and-parse-credential";
28
+ import * as Errors from "./errors";
28
29
 
29
30
  export {
30
31
  evaluateIssuerTrust,
@@ -35,7 +36,8 @@ export {
35
36
  authorizeAccess,
36
37
  obtainCredential,
37
38
  verifyAndParseCredential,
38
- parseAuthroizationResponse,
39
+ parseAuthorizationResponse,
40
+ Errors,
39
41
  };
40
42
  export type {
41
43
  StartFlow,
@@ -30,11 +30,3 @@ export const ResponseUriResultShape = z.object({
30
30
  });
31
31
 
32
32
  export type ResponseMode = "query" | "form_post.jwt";
33
-
34
- export const CredentialIssuanceFailureResponse = z.object({
35
- error: z.string(),
36
- });
37
-
38
- export type CredentialIssuanceFailureResponse = z.infer<
39
- typeof CredentialIssuanceFailureResponse
40
- >;
@@ -1,6 +1,6 @@
1
1
  import * as z from "zod";
2
2
  import { decodeBase64 } from "@pagopa/io-react-native-jwt";
3
- import { AuthRequestDecodeError } from "../../utils/errors";
3
+ import { AuthRequestDecodeError } from "./errors";
4
4
 
5
5
  const QRCodePayload = z.object({
6
6
  protocol: z.string(),
@@ -7,9 +7,9 @@ import {
7
7
  } from "@pagopa/io-react-native-jwt";
8
8
 
9
9
  import { createDPopToken } from "../../utils/dpop";
10
- import { NoSuitableKeysFoundInEntityConfiguration } from "../../utils/errors";
10
+ import { NoSuitableKeysFoundInEntityConfiguration } from "./errors";
11
11
  import type { EvaluateRelyingPartyTrust } from "./02-evaluate-rp-trust";
12
- import { hasStatus, type Out } from "../../utils/misc";
12
+ import { hasStatusOrThrow, type Out } from "../../utils/misc";
13
13
  import type { StartFlow } from "./01-start-flow";
14
14
  import { RequestObject } from "./types";
15
15
 
@@ -56,7 +56,7 @@ export const getRequestObject: GetRequestObject = async (
56
56
  DPoP: signedWalletInstanceDPoP,
57
57
  },
58
58
  })
59
- .then(hasStatus(200))
59
+ .then(hasStatusOrThrow(200))
60
60
  .then((res) => res.json())
61
61
  .then((responseJson) => responseJson.response);
62
62
 
@@ -2,8 +2,8 @@ import { EncryptJwe, SignJWT } from "@pagopa/io-react-native-jwt";
2
2
  import uuid from "react-native-uuid";
3
3
  import * as WalletInstanceAttestation from "../../wallet-instance-attestation";
4
4
  import type { JWK } from "@pagopa/io-react-native-jwt/lib/typescript/types";
5
- import { NoSuitableKeysFoundInEntityConfiguration } from "../../utils/errors";
6
- import { hasStatus, type Out } from "../../utils/misc";
5
+ import { NoSuitableKeysFoundInEntityConfiguration } from "./errors";
6
+ import { hasStatusOrThrow, type Out } from "../../utils/misc";
7
7
  import type { GetRequestObject } from "./03-get-request-object";
8
8
  import { disclose } from "../../sd-jwt";
9
9
  import type { EvaluateRelyingPartyTrust } from "./02-evaluate-rp-trust";
@@ -162,7 +162,7 @@ export const sendAuthorizationResponse: SendAuthorizationResponse = async (
162
162
  },
163
163
  body,
164
164
  })
165
- .then(hasStatus(200))
165
+ .then(hasStatusOrThrow(200))
166
166
  .then((res) => res.json())
167
167
  .then(AuthorizationResponse.parse);
168
168
  };
@@ -0,0 +1,41 @@
1
+ import { IoWalletError, serializeAttrs } from "../../utils/errors";
2
+
3
+ /**
4
+ * An error subclass thrown when auth request decode fail
5
+ *
6
+ */
7
+ export class AuthRequestDecodeError extends IoWalletError {
8
+ code = "ERR_IO_WALLET_AUTHENTICATION_REQUEST_DECODE_FAILED";
9
+
10
+ /** The Claim for which the validation failed. */
11
+ claim: string;
12
+
13
+ /** Reason code for the validation failure. */
14
+ reason: string;
15
+
16
+ constructor(
17
+ message: string,
18
+ claim: string = "unspecified",
19
+ reason: string = "unspecified"
20
+ ) {
21
+ super(serializeAttrs({ message, claim, reason }));
22
+ this.claim = claim;
23
+ this.reason = reason;
24
+ }
25
+ }
26
+
27
+ /**
28
+ * When selecting a public key from an entity configuration, and no one meets the requirements for the scenario
29
+ *
30
+ */
31
+ export class NoSuitableKeysFoundInEntityConfiguration extends IoWalletError {
32
+ code = "ERR_NO_SUITABLE_KEYS_NOT_FOUND";
33
+
34
+ /**
35
+ * @param scenario describe the scenario in which the error arise
36
+ */
37
+ constructor(scenario: string) {
38
+ const message = `Entity configuration do not provide any suitable keys (${scenario}).`;
39
+ super(message);
40
+ }
41
+ }
@@ -11,12 +11,14 @@ import {
11
11
  sendAuthorizationResponse,
12
12
  type SendAuthorizationResponse,
13
13
  } from "./04-send-authorization-response";
14
+ import * as Errors from "./errors";
14
15
 
15
16
  export {
16
17
  startFlowFromQR,
17
18
  evaluateRelyingPartyTrust,
18
19
  getRequestObject,
19
20
  sendAuthorizationResponse,
21
+ Errors,
20
22
  };
21
23
  export type {
22
24
  StartFlow,
@@ -1,19 +1,16 @@
1
1
  import {
2
2
  getCredentialHashWithouDiscloures,
3
- hasStatus,
4
- safeJsonParse,
3
+ hasStatusOrThrow,
5
4
  type Out,
6
5
  } from "../../utils/misc";
7
6
  import type { EvaluateIssuerTrust, ObtainCredential } from "../issuance";
8
- import { SignJWT, type CryptoContext } from "@pagopa/io-react-native-jwt";
7
+ import { type CryptoContext, SignJWT } from "@pagopa/io-react-native-jwt";
9
8
  import uuid from "react-native-uuid";
9
+ import { StatusAttestationResponse } from "./types";
10
10
  import {
11
- InvalidStatusAttestationResponse,
12
- StatusAttestationResponse,
13
- } from "./types";
14
- import {
15
- StatusAttestationError,
16
- CredentialInvalidStatusError,
11
+ IssuerResponseError,
12
+ IssuerResponseErrorCodes,
13
+ ResponseErrorBuilder,
17
14
  UnexpectedStatusCodeError,
18
15
  } from "../../utils/errors";
19
16
 
@@ -74,7 +71,7 @@ export const statusAttestation: StatusAttestation = async (
74
71
  },
75
72
  body: JSON.stringify(body),
76
73
  })
77
- .then(hasStatus(201))
74
+ .then(hasStatusOrThrow(201))
78
75
  .then((raw) => raw.json())
79
76
  .then((json) => StatusAttestationResponse.parse(json))
80
77
  .catch(handleStatusAttestationError);
@@ -94,19 +91,14 @@ const handleStatusAttestationError = (e: unknown) => {
94
91
  throw e;
95
92
  }
96
93
 
97
- if (e.statusCode === 404) {
98
- const maybeError = InvalidStatusAttestationResponse.safeParse(
99
- safeJsonParse(e.responseBody)
100
- );
101
- throw new CredentialInvalidStatusError(
102
- "Invalid status found for the given credential",
103
- maybeError.success ? maybeError.data.error : "unknown",
104
- e.message
105
- );
106
- }
107
-
108
- throw new StatusAttestationError(
109
- `Unable to obtain the status attestation for the given credential [response status code: ${e.statusCode}]`,
110
- e.message
111
- );
94
+ throw new ResponseErrorBuilder(IssuerResponseError)
95
+ .handle(404, {
96
+ code: IssuerResponseErrorCodes.CredentialInvalidStatus,
97
+ message: "Invalid status found for the given credential",
98
+ })
99
+ .handle("*", {
100
+ code: IssuerResponseErrorCodes.StatusAttestationRequestFailed,
101
+ message: `Unable to obtain the status attestation for the given credential`,
102
+ })
103
+ .buildFrom(e);
112
104
  };
@@ -16,11 +16,14 @@ graph TD;
16
16
  1 --> 2
17
17
  ```
18
18
 
19
+
19
20
  ## Mapped results
20
21
 
21
- ### 404 Not Found (CredentialInvalidStatusError)
22
+ The following errors are mapped to a `IssuerResponseError` with specific codes.
22
23
 
23
- A `404 Not Found` response is returned by the credential issuer when the status attestation is invalid.
24
+ |HTTP Status|Error Code|Description|
25
+ |-----------|----------|-----------|
26
+ |`404 Not Found`|`ERR_CREDENTIAL_INVALID_STATUS`|This response is returned by the credential issuer when the status attestation is invalid. It might contain more details in the `reason` property.|
24
27
 
25
28
  ## Example
26
29