@pagopa/io-react-native-wallet 0.7.4 → 0.9.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 (211) hide show
  1. package/README.md +49 -31
  2. package/lib/commonjs/credential/index.js +13 -0
  3. package/lib/commonjs/credential/index.js.map +1 -0
  4. package/lib/commonjs/credential/issuance/01-start-flow.js +2 -0
  5. package/lib/commonjs/credential/issuance/01-start-flow.js.map +1 -0
  6. package/lib/commonjs/credential/issuance/02-evaluate-issuer-trust.js +26 -0
  7. package/lib/commonjs/credential/issuance/02-evaluate-issuer-trust.js.map +1 -0
  8. package/lib/commonjs/credential/issuance/03-start-user-authorization.js +119 -0
  9. package/lib/commonjs/credential/issuance/03-start-user-authorization.js.map +1 -0
  10. package/lib/commonjs/credential/issuance/04-complete-user-authorization.js +6 -0
  11. package/lib/commonjs/credential/issuance/04-complete-user-authorization.js.map +1 -0
  12. package/lib/commonjs/credential/issuance/05-authorize-access.js +63 -0
  13. package/lib/commonjs/credential/issuance/05-authorize-access.js.map +1 -0
  14. package/lib/commonjs/credential/issuance/06-obtain-credential.js +128 -0
  15. package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -0
  16. package/lib/commonjs/credential/issuance/07-confirm-credential.js +6 -0
  17. package/lib/commonjs/credential/issuance/07-confirm-credential.js.map +1 -0
  18. package/lib/commonjs/credential/issuance/const.js +9 -0
  19. package/lib/commonjs/credential/issuance/const.js.map +1 -0
  20. package/lib/commonjs/credential/issuance/index.js +34 -0
  21. package/lib/commonjs/credential/issuance/index.js.map +1 -0
  22. package/lib/commonjs/credential/presentation/01-start-flow.js +55 -0
  23. package/lib/commonjs/credential/presentation/01-start-flow.js.map +1 -0
  24. package/lib/commonjs/credential/presentation/02-evaluate-rp-trust.js +32 -0
  25. package/lib/commonjs/credential/presentation/02-evaluate-rp-trust.js.map +1 -0
  26. package/lib/commonjs/credential/presentation/03-get-request-object.js +68 -0
  27. package/lib/commonjs/credential/presentation/03-get-request-object.js.map +1 -0
  28. package/lib/commonjs/credential/presentation/04-send-authorization-response.js +139 -0
  29. package/lib/commonjs/credential/presentation/04-send-authorization-response.js.map +1 -0
  30. package/lib/commonjs/credential/presentation/index.js +34 -0
  31. package/lib/commonjs/credential/presentation/index.js.map +1 -0
  32. package/lib/commonjs/{rp → credential/presentation}/types.js +17 -34
  33. package/lib/commonjs/credential/presentation/types.js.map +1 -0
  34. package/lib/commonjs/index.js +10 -61
  35. package/lib/commonjs/index.js.map +1 -1
  36. package/lib/commonjs/pid/index.js +1 -3
  37. package/lib/commonjs/pid/index.js.map +1 -1
  38. package/lib/commonjs/sd-jwt/index.js +1 -1
  39. package/lib/commonjs/sd-jwt/index.js.map +1 -1
  40. package/lib/commonjs/sd-jwt/types.js +1 -1
  41. package/lib/commonjs/sd-jwt/types.js.map +1 -1
  42. package/lib/commonjs/trust/chain.js +32 -4
  43. package/lib/commonjs/trust/chain.js.map +1 -1
  44. package/lib/commonjs/trust/index.js +105 -20
  45. package/lib/commonjs/trust/index.js.map +1 -1
  46. package/lib/commonjs/trust/types.js +54 -35
  47. package/lib/commonjs/trust/types.js.map +1 -1
  48. package/lib/commonjs/utils/crypto.js +5 -18
  49. package/lib/commonjs/utils/crypto.js.map +1 -1
  50. package/lib/commonjs/utils/misc.js +23 -0
  51. package/lib/commonjs/utils/misc.js.map +1 -0
  52. package/lib/commonjs/utils/par.js +86 -0
  53. package/lib/commonjs/utils/par.js.map +1 -0
  54. package/lib/module/credential/index.js +4 -0
  55. package/lib/module/credential/index.js.map +1 -0
  56. package/lib/module/credential/issuance/01-start-flow.js +2 -0
  57. package/lib/module/credential/issuance/01-start-flow.js.map +1 -0
  58. package/lib/module/credential/issuance/02-evaluate-issuer-trust.js +19 -0
  59. package/lib/module/credential/issuance/02-evaluate-issuer-trust.js.map +1 -0
  60. package/lib/module/credential/issuance/03-start-user-authorization.js +109 -0
  61. package/lib/module/credential/issuance/03-start-user-authorization.js.map +1 -0
  62. package/lib/module/credential/issuance/04-complete-user-authorization.js +2 -0
  63. package/lib/module/credential/issuance/04-complete-user-authorization.js.map +1 -0
  64. package/lib/module/credential/issuance/05-authorize-access.js +55 -0
  65. package/lib/module/credential/issuance/05-authorize-access.js.map +1 -0
  66. package/lib/module/credential/issuance/06-obtain-credential.js +117 -0
  67. package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -0
  68. package/lib/module/credential/issuance/07-confirm-credential.js +2 -0
  69. package/lib/module/credential/issuance/07-confirm-credential.js.map +1 -0
  70. package/lib/module/credential/issuance/const.js +2 -0
  71. package/lib/module/credential/issuance/const.js.map +1 -0
  72. package/lib/module/credential/issuance/index.js +6 -0
  73. package/lib/module/credential/issuance/index.js.map +1 -0
  74. package/lib/module/credential/presentation/01-start-flow.js +46 -0
  75. package/lib/module/credential/presentation/01-start-flow.js.map +1 -0
  76. package/lib/module/credential/presentation/02-evaluate-rp-trust.js +25 -0
  77. package/lib/module/credential/presentation/02-evaluate-rp-trust.js.map +1 -0
  78. package/lib/module/credential/presentation/03-get-request-object.js +60 -0
  79. package/lib/module/credential/presentation/03-get-request-object.js.map +1 -0
  80. package/lib/module/credential/presentation/04-send-authorization-response.js +128 -0
  81. package/lib/module/credential/presentation/04-send-authorization-response.js.map +1 -0
  82. package/lib/module/credential/presentation/index.js +6 -0
  83. package/lib/module/credential/presentation/index.js.map +1 -0
  84. package/lib/module/credential/presentation/types.js +21 -0
  85. package/lib/module/credential/presentation/types.js.map +1 -0
  86. package/lib/module/index.js +4 -5
  87. package/lib/module/index.js.map +1 -1
  88. package/lib/module/pid/index.js +1 -2
  89. package/lib/module/pid/index.js.map +1 -1
  90. package/lib/module/sd-jwt/index.js +1 -1
  91. package/lib/module/sd-jwt/index.js.map +1 -1
  92. package/lib/module/sd-jwt/types.js +1 -1
  93. package/lib/module/sd-jwt/types.js.map +1 -1
  94. package/lib/module/trust/chain.js +30 -3
  95. package/lib/module/trust/chain.js.map +1 -1
  96. package/lib/module/trust/index.js +99 -16
  97. package/lib/module/trust/index.js.map +1 -1
  98. package/lib/module/trust/types.js +50 -31
  99. package/lib/module/trust/types.js.map +1 -1
  100. package/lib/module/utils/crypto.js +2 -15
  101. package/lib/module/utils/crypto.js.map +1 -1
  102. package/lib/module/utils/misc.js +17 -0
  103. package/lib/module/utils/misc.js.map +1 -0
  104. package/lib/module/utils/par.js +74 -0
  105. package/lib/module/utils/par.js.map +1 -0
  106. package/lib/typescript/credential/index.d.ts +4 -0
  107. package/lib/typescript/credential/index.d.ts.map +1 -0
  108. package/lib/typescript/credential/issuance/01-start-flow.d.ts +11 -0
  109. package/lib/typescript/credential/issuance/01-start-flow.d.ts.map +1 -0
  110. package/lib/typescript/credential/issuance/02-evaluate-issuer-trust.d.ts +18 -0
  111. package/lib/typescript/credential/issuance/02-evaluate-issuer-trust.d.ts.map +1 -0
  112. package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts +31 -0
  113. package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts.map +1 -0
  114. package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts +16 -0
  115. package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts.map +1 -0
  116. package/lib/typescript/credential/issuance/05-authorize-access.d.ts +26 -0
  117. package/lib/typescript/credential/issuance/05-authorize-access.d.ts.map +1 -0
  118. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts +32 -0
  119. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -0
  120. package/lib/typescript/credential/issuance/07-confirm-credential.d.ts +11 -0
  121. package/lib/typescript/credential/issuance/07-confirm-credential.d.ts.map +1 -0
  122. package/lib/typescript/credential/issuance/const.d.ts +2 -0
  123. package/lib/typescript/credential/issuance/const.d.ts.map +1 -0
  124. package/lib/typescript/credential/issuance/index.d.ts +10 -0
  125. package/lib/typescript/credential/issuance/index.d.ts.map +1 -0
  126. package/lib/typescript/credential/presentation/01-start-flow.d.ts +20 -0
  127. package/lib/typescript/credential/presentation/01-start-flow.d.ts.map +1 -0
  128. package/lib/typescript/credential/presentation/02-evaluate-rp-trust.d.ts +18 -0
  129. package/lib/typescript/credential/presentation/02-evaluate-rp-trust.d.ts.map +1 -0
  130. package/lib/typescript/credential/presentation/03-get-request-object.d.ts +25 -0
  131. package/lib/typescript/credential/presentation/03-get-request-object.d.ts.map +1 -0
  132. package/lib/typescript/credential/presentation/04-send-authorization-response.d.ts +34 -0
  133. package/lib/typescript/credential/presentation/04-send-authorization-response.d.ts.map +1 -0
  134. package/lib/typescript/credential/presentation/index.d.ts +7 -0
  135. package/lib/typescript/credential/presentation/index.d.ts.map +1 -0
  136. package/lib/typescript/credential/presentation/types.d.ts +49 -0
  137. package/lib/typescript/credential/presentation/types.d.ts.map +1 -0
  138. package/lib/typescript/index.d.ts +4 -5
  139. package/lib/typescript/index.d.ts.map +1 -1
  140. package/lib/typescript/pid/index.d.ts +1 -2
  141. package/lib/typescript/pid/index.d.ts.map +1 -1
  142. package/lib/typescript/sd-jwt/index.d.ts +2 -2
  143. package/lib/typescript/sd-jwt/index.d.ts.map +1 -1
  144. package/lib/typescript/sd-jwt/types.d.ts +5 -5
  145. package/lib/typescript/trust/chain.d.ts +12 -3
  146. package/lib/typescript/trust/chain.d.ts.map +1 -1
  147. package/lib/typescript/trust/index.d.ts +198 -24
  148. package/lib/typescript/trust/index.d.ts.map +1 -1
  149. package/lib/typescript/trust/types.d.ts +1299 -623
  150. package/lib/typescript/trust/types.d.ts.map +1 -1
  151. package/lib/typescript/utils/crypto.d.ts +1 -1
  152. package/lib/typescript/utils/crypto.d.ts.map +1 -1
  153. package/lib/typescript/utils/dpop.d.ts +2 -2
  154. package/lib/typescript/utils/misc.d.ts +8 -0
  155. package/lib/typescript/utils/misc.d.ts.map +1 -0
  156. package/lib/typescript/utils/par.d.ts +68 -0
  157. package/lib/typescript/utils/par.d.ts.map +1 -0
  158. package/package.json +2 -2
  159. package/src/credential/index.ts +4 -0
  160. package/src/credential/issuance/01-start-flow.ts +10 -0
  161. package/src/credential/issuance/02-evaluate-issuer-trust.ts +31 -0
  162. package/src/credential/issuance/03-start-user-authorization.ts +138 -0
  163. package/src/credential/issuance/04-complete-user-authorization.ts +17 -0
  164. package/src/credential/issuance/05-authorize-access.ts +92 -0
  165. package/src/credential/issuance/06-obtain-credential.ts +179 -0
  166. package/src/credential/issuance/07-confirm-credential.ts +14 -0
  167. package/src/credential/issuance/const.ts +2 -0
  168. package/src/credential/issuance/index.ts +32 -0
  169. package/src/credential/presentation/01-start-flow.ts +51 -0
  170. package/src/credential/presentation/02-evaluate-rp-trust.ts +33 -0
  171. package/src/credential/presentation/03-get-request-object.ts +85 -0
  172. package/src/credential/presentation/04-send-authorization-response.ts +168 -0
  173. package/src/credential/presentation/index.ts +26 -0
  174. package/src/credential/presentation/types.ts +27 -0
  175. package/src/index.ts +7 -28
  176. package/src/pid/index.ts +1 -2
  177. package/src/sd-jwt/index.ts +2 -2
  178. package/src/sd-jwt/types.ts +1 -1
  179. package/src/trust/chain.ts +45 -3
  180. package/src/trust/index.ts +136 -19
  181. package/src/trust/types.ts +57 -35
  182. package/src/utils/crypto.ts +2 -20
  183. package/src/utils/misc.ts +23 -0
  184. package/src/utils/par.ts +103 -0
  185. package/lib/commonjs/pid/issuing.js +0 -276
  186. package/lib/commonjs/pid/issuing.js.map +0 -1
  187. package/lib/commonjs/rp/__test__/index.test.js +0 -172
  188. package/lib/commonjs/rp/__test__/index.test.js.map +0 -1
  189. package/lib/commonjs/rp/index.js +0 -239
  190. package/lib/commonjs/rp/index.js.map +0 -1
  191. package/lib/commonjs/rp/types.js.map +0 -1
  192. package/lib/module/pid/issuing.js +0 -266
  193. package/lib/module/pid/issuing.js.map +0 -1
  194. package/lib/module/rp/__test__/index.test.js +0 -168
  195. package/lib/module/rp/__test__/index.test.js.map +0 -1
  196. package/lib/module/rp/index.js +0 -228
  197. package/lib/module/rp/index.js.map +0 -1
  198. package/lib/module/rp/types.js +0 -36
  199. package/lib/module/rp/types.js.map +0 -1
  200. package/lib/typescript/pid/issuing.d.ts +0 -57
  201. package/lib/typescript/pid/issuing.d.ts.map +0 -1
  202. package/lib/typescript/rp/__test__/index.test.d.ts +0 -2
  203. package/lib/typescript/rp/__test__/index.test.d.ts.map +0 -1
  204. package/lib/typescript/rp/index.d.ts +0 -43
  205. package/lib/typescript/rp/index.d.ts.map +0 -1
  206. package/lib/typescript/rp/types.d.ts +0 -122
  207. package/lib/typescript/rp/types.d.ts.map +0 -1
  208. package/src/pid/issuing.ts +0 -405
  209. package/src/rp/__test__/index.test.ts +0 -250
  210. package/src/rp/index.ts +0 -287
  211. package/src/rp/types.ts +0 -42
@@ -0,0 +1,14 @@
1
+ import type { ObtainCredential } from "./06-obtain-credential";
2
+ import type { Out } from "../../utils/misc";
3
+
4
+ /**
5
+ * The end of the issuing flow.
6
+ * The User accepted the Credential and it can be stored in the device according to the app implementation preferences.
7
+ * To be implemented.
8
+ *
9
+ * @returns The type of the Credential to be issued and the url of the Issuer
10
+ */
11
+ export type ConfirmCredential = (
12
+ credential: Out<ObtainCredential>["credential"],
13
+ format: Out<ObtainCredential>["format"]
14
+ ) => Promise<void>;
@@ -0,0 +1,2 @@
1
+ export const ASSERTION_TYPE =
2
+ "urn:ietf:params:oauth:client-assertion-type:jwt-client-attestation";
@@ -0,0 +1,32 @@
1
+ import { type StartFlow } from "./01-start-flow";
2
+ import {
3
+ evaluateIssuerTrust,
4
+ type EvaluateIssuerTrust,
5
+ } from "./02-evaluate-issuer-trust";
6
+ import {
7
+ startUserAuthorization,
8
+ type StartUserAuthorization,
9
+ } from "./03-start-user-authorization";
10
+ import { type CompleteUserAuthorization } from "./04-complete-user-authorization";
11
+ import { authorizeAccess, type AuthorizeAccess } from "./05-authorize-access";
12
+ import {
13
+ obtainCredential,
14
+ type ObtainCredential,
15
+ } from "./06-obtain-credential";
16
+ import type { ConfirmCredential } from "./07-confirm-credential";
17
+
18
+ export {
19
+ evaluateIssuerTrust,
20
+ startUserAuthorization,
21
+ authorizeAccess,
22
+ obtainCredential,
23
+ };
24
+ export type {
25
+ StartFlow,
26
+ EvaluateIssuerTrust,
27
+ StartUserAuthorization,
28
+ CompleteUserAuthorization,
29
+ AuthorizeAccess,
30
+ ObtainCredential,
31
+ ConfirmCredential,
32
+ };
@@ -0,0 +1,51 @@
1
+ import * as z from "zod";
2
+ import { decodeBase64 } from "@pagopa/io-react-native-jwt";
3
+ import { AuthRequestDecodeError } from "../../utils/errors";
4
+
5
+ const QRCodePayload = z.object({
6
+ protocol: z.string(),
7
+ resource: z.string(), // TODO: refine to known paths using literals
8
+ clientId: z.string(),
9
+ requestURI: z.string(),
10
+ });
11
+
12
+ /**
13
+ * The beginning of the presentation flow.
14
+ * To be implemented accordind to the user touchpoint
15
+ *
16
+ * @param Optional parameters, depending on the starting touchoint
17
+ * @returns The url for the Relying Party to connect with
18
+ */
19
+ export type StartFlow<T extends Array<unknown> = []> = (...args: T) => Promise<{
20
+ requestURI: string;
21
+ clientId: string;
22
+ }>;
23
+
24
+ /**
25
+ * Start a presentation flow by decoding an incoming QR-code
26
+ *
27
+ * @param qrcode The encoded QR-code content
28
+ * @returns The url for the Relying Party to connect with
29
+ * @throws If the provided qr code fails to be decoded
30
+ */
31
+ export const startFlowFromQR: StartFlow<[string]> = async (qrcode) => {
32
+ const decoded = decodeBase64(qrcode);
33
+ const decodedUrl = new URL(decoded);
34
+ const protocol = decodedUrl.protocol;
35
+ const resource = decodedUrl.hostname;
36
+ const requestURI = decodedUrl.searchParams.get("request_uri");
37
+ const clientId = decodedUrl.searchParams.get("client_id");
38
+
39
+ const result = QRCodePayload.safeParse({
40
+ protocol,
41
+ resource,
42
+ requestURI,
43
+ clientId,
44
+ });
45
+
46
+ if (result.success) {
47
+ return result.data;
48
+ } else {
49
+ throw new AuthRequestDecodeError(result.error.message, `${decodedUrl}`);
50
+ }
51
+ };
@@ -0,0 +1,33 @@
1
+ import { getRelyingPartyEntityConfiguration } from "../../trust";
2
+ import { RelyingPartyEntityConfiguration } from "../../trust/types";
3
+ import type { StartFlow } from "../issuance/01-start-flow";
4
+ import type { Out } from "../../utils/misc";
5
+
6
+ export type EvaluateRelyingPartyTrust = (
7
+ rpUrl: Out<StartFlow>["issuerUrl"],
8
+ context?: {
9
+ appFetch?: GlobalFetch["fetch"];
10
+ }
11
+ ) => Promise<{
12
+ rpConf: RelyingPartyEntityConfiguration["payload"]["metadata"];
13
+ }>;
14
+
15
+ /**
16
+ * The Relying Party trust evaluation phase.
17
+ * Fetch the Relying Party's configuration and verify trust.
18
+ *
19
+ * @param rpUrl The base url of the Issuer
20
+ * @param context.appFetch (optional) fetch api implementation. Default: built-in fetch
21
+ * @returns The Relying Party's configuration
22
+ */
23
+ export const evaluateRelyingPartyTrust: EvaluateRelyingPartyTrust = async (
24
+ rpUrl,
25
+ { appFetch = fetch } = {}
26
+ ) => {
27
+ const {
28
+ payload: { metadata: rpConf },
29
+ } = await getRelyingPartyEntityConfiguration(rpUrl, {
30
+ appFetch,
31
+ });
32
+ return { rpConf };
33
+ };
@@ -0,0 +1,85 @@
1
+ import uuid from "react-native-uuid";
2
+ import {
3
+ decode as decodeJwt,
4
+ sha256ToBase64,
5
+ verify,
6
+ type CryptoContext,
7
+ } from "@pagopa/io-react-native-jwt";
8
+
9
+ import { createDPopToken } from "../../utils/dpop";
10
+ import { NoSuitableKeysFoundInEntityConfiguration } from "../../utils/errors";
11
+ import type { EvaluateRelyingPartyTrust } from "./02-evaluate-rp-trust";
12
+ import { hasStatus, type Out } from "../../utils/misc";
13
+ import type { StartFlow } from "./01-start-flow";
14
+ import { RequestObject } from "./types";
15
+
16
+ export type GetRequestObject = (
17
+ requestUri: Out<StartFlow>["requestURI"],
18
+ rpConf: Out<EvaluateRelyingPartyTrust>["rpConf"],
19
+ context: {
20
+ wiaCryptoContext: CryptoContext;
21
+ appFetch?: GlobalFetch["fetch"];
22
+ walletInstanceAttestation: string;
23
+ }
24
+ ) => Promise<{ requestObject: RequestObject }>;
25
+
26
+ /**
27
+ * Obtain the Request Object for RP authentication
28
+ * @see https://italia.github.io/eudi-wallet-it-docs/versione-corrente/en/relying-party-solution.html
29
+ *
30
+ * @param requestUri The url for the Relying Party to connect with
31
+ * @param rpConf The Relying Party's configuration
32
+ * @param context.wiaCryptoContext The context to access the key associated with the Wallet Instance Attestation
33
+ * @param context.walletInstanceAttestation The Wallet Instance Attestation token
34
+ * @param context.appFetch (optional) fetch api implementation. Default: built-in fetch
35
+ * @returns The Request Object that describes the presentation
36
+ */
37
+ export const getRequestObject: GetRequestObject = async (
38
+ requestUri,
39
+ rpConf,
40
+ { wiaCryptoContext, appFetch = fetch, walletInstanceAttestation }
41
+ ) => {
42
+ const signedWalletInstanceDPoP = await createDPopToken(
43
+ {
44
+ jti: `${uuid.v4()}`,
45
+ htm: "GET",
46
+ htu: requestUri,
47
+ ath: await sha256ToBase64(walletInstanceAttestation),
48
+ },
49
+ wiaCryptoContext
50
+ );
51
+
52
+ const responseEncodedJwt = await appFetch(requestUri, {
53
+ method: "GET",
54
+ headers: {
55
+ Authorization: `DPoP ${walletInstanceAttestation}`,
56
+ DPoP: signedWalletInstanceDPoP,
57
+ },
58
+ })
59
+ .then(hasStatus(200))
60
+ .then((res) => res.json())
61
+ .then((responseJson) => responseJson.response);
62
+
63
+ const responseJwt = decodeJwt(responseEncodedJwt);
64
+
65
+ // verify token signature according to RP's entity configuration
66
+ // to ensure the request object is authentic
67
+ {
68
+ const pubKey = rpConf.wallet_relying_party.jwks.keys.find(
69
+ ({ kid }) => kid === responseJwt.protectedHeader.kid
70
+ );
71
+ if (!pubKey) {
72
+ throw new NoSuitableKeysFoundInEntityConfiguration(
73
+ "Request Object signature verification"
74
+ );
75
+ }
76
+ await verify(responseEncodedJwt, pubKey);
77
+ }
78
+
79
+ // Ensure that the request object conforms to the expected specification.
80
+ const requestObject = RequestObject.parse(responseJwt.payload);
81
+
82
+ return {
83
+ requestObject,
84
+ };
85
+ };
@@ -0,0 +1,168 @@
1
+ import { EncryptJwe, SignJWT } from "@pagopa/io-react-native-jwt";
2
+ import uuid from "react-native-uuid";
3
+ import * as WalletInstanceAttestation from "../../wallet-instance-attestation";
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";
7
+ import type { GetRequestObject } from "./03-get-request-object";
8
+ import { disclose } from "../../sd-jwt";
9
+ import type { EvaluateRelyingPartyTrust } from "./02-evaluate-rp-trust";
10
+ import { type Presentation } from "./types";
11
+ import * as z from "zod";
12
+
13
+ export type AuthorizationResponse = z.infer<typeof AuthorizationResponse>;
14
+ export const AuthorizationResponse = z.object({
15
+ status: z.string(),
16
+ response_code: z
17
+ .string() /**
18
+ FIXME: [SIW-627] we expect this value from every RP implementation
19
+ Actually some RP does not return the value
20
+ We make it optional to not break the flow.
21
+ */
22
+ .optional(),
23
+ });
24
+
25
+ /**
26
+ * Choose an RSA public key from those offered by the RP for encryption.
27
+ *
28
+ * @param entity The RP entity configuration
29
+ * @returns A suitable public key with its compatible encryption algorithm
30
+ * @throws {NoSuitableKeysFoundInEntityConfiguration} If entity do not contain any public key suitable for encrypting
31
+ */
32
+ const chooseRSAPublicKeyToEncrypt = (
33
+ entity: Out<EvaluateRelyingPartyTrust>["rpConf"]
34
+ ): JWK => {
35
+ const [usingRsa256] = entity.wallet_relying_party.jwks.keys.filter(
36
+ (jwk) => jwk.use === "enc" && jwk.kty === "RSA"
37
+ );
38
+
39
+ if (usingRsa256) {
40
+ return usingRsa256;
41
+ }
42
+
43
+ // No suitable key has been found
44
+ throw new NoSuitableKeysFoundInEntityConfiguration(
45
+ "Encrypt with RP public key"
46
+ );
47
+ };
48
+
49
+ /**
50
+ * Generate a Verified Presentation token for a received request object within the context of an authorization request flow.
51
+ * The presentation is created by revealing data from the provided credentials based on the requested claims.
52
+ * Each Verified Credential is accompanied by the claims that the user consents to disclose from it.
53
+ *
54
+ * @todo: Allow for handling more than one Verified Credential.
55
+ */
56
+ const prepareVpToken = async (
57
+ requestObject: Out<GetRequestObject>["requestObject"],
58
+ walletInstanceAttestation: string,
59
+ [vc, claims, cryptoCtx]: Presentation // TODO: [SIW-353] support multiple presentations,
60
+ ): Promise<{
61
+ vp_token: string;
62
+ presentation_submission: Record<string, unknown>;
63
+ }> => {
64
+ // this throws if vc cannot satisfy all the requested claims
65
+ const { token: vp, paths } = await disclose(vc, claims);
66
+
67
+ // obtain issuer from Wallet Instance
68
+ const {
69
+ payload: { iss },
70
+ } = WalletInstanceAttestation.decode(walletInstanceAttestation);
71
+
72
+ const pidKid = await cryptoCtx.getPublicKey().then((_) => _.kid);
73
+
74
+ // TODO: [SIW-359] check all requeste claims of the requestedObj are satisfied
75
+ const vp_token = await new SignJWT(cryptoCtx)
76
+ .setProtectedHeader({
77
+ typ: "JWT",
78
+ kid: pidKid,
79
+ })
80
+ .setPayload({
81
+ vp: vp,
82
+ jti: `${uuid.v4()}`,
83
+ iss,
84
+ nonce: requestObject.nonce,
85
+ })
86
+ .setAudience(requestObject.response_uri)
87
+ .setIssuedAt()
88
+ .setExpirationTime("1h")
89
+ .sign();
90
+
91
+ const vc_scope = requestObject.scope;
92
+ const presentation_submission = {
93
+ definition_id: `${uuid.v4()}`,
94
+ id: `${uuid.v4()}`,
95
+ descriptor_map: paths.map((p) => ({
96
+ id: vc_scope,
97
+ path: `$.vp_token.${p.path}`,
98
+ format: "vc+sd-jwt",
99
+ })),
100
+ };
101
+
102
+ return { vp_token, presentation_submission };
103
+ };
104
+
105
+ export type SendAuthorizationResponse = (
106
+ requestObject: Out<GetRequestObject>["requestObject"],
107
+ rpConf: Out<EvaluateRelyingPartyTrust>["rpConf"],
108
+ presentation: Presentation, // TODO: [SIW-353] support multiple presentations
109
+ context: {
110
+ walletInstanceAttestation: string;
111
+ appFetch?: GlobalFetch["fetch"];
112
+ }
113
+ ) => Promise<AuthorizationResponse>;
114
+
115
+ /**
116
+ * Complete the presentation flow by sending the authorization response to the Relying Party
117
+ *
118
+ * @param requestObject The Request Object that describes the presentation
119
+ * @param rpConf The Relying Party's configuration
120
+ * @param presentation The presentation tuple consisting in the signed credential,
121
+ * the list of claims to be disclosed, and the context to access the key that proves the holder binding
122
+ * @param context.walletInstanceAttestation The Wallet Instance Attestation token
123
+ * @param context.appFetch (optional) fetch api implementation. Default: built-in fetch
124
+ * @returns The result of the presentation flow
125
+ */
126
+ export const sendAuthorizationResponse: SendAuthorizationResponse = async (
127
+ requestObject,
128
+ rpConf,
129
+ presentation,
130
+ { appFetch = fetch, walletInstanceAttestation }
131
+ ): Promise<AuthorizationResponse> => {
132
+ // the request is an unsigned jws without iss, aud, exp
133
+ // https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#name-signed-and-encrypted-respon
134
+ const rsaPublicJwk = chooseRSAPublicKeyToEncrypt(rpConf);
135
+
136
+ const { vp_token, presentation_submission } = await prepareVpToken(
137
+ requestObject,
138
+ walletInstanceAttestation,
139
+ presentation
140
+ );
141
+
142
+ const authzResponsePayload = JSON.stringify({
143
+ state: requestObject.state,
144
+ presentation_submission,
145
+ nonce: requestObject.nonce,
146
+ vp_token,
147
+ });
148
+
149
+ const encrypted = await new EncryptJwe(authzResponsePayload, {
150
+ alg: "RSA-OAEP-256",
151
+ enc: "A256CBC-HS512",
152
+ kid: rsaPublicJwk.kid,
153
+ }).encrypt(rsaPublicJwk);
154
+
155
+ const formBody = new URLSearchParams({ response: encrypted });
156
+ const body = formBody.toString();
157
+
158
+ return appFetch(requestObject.response_uri, {
159
+ method: "POST",
160
+ headers: {
161
+ "Content-Type": "application/x-www-form-urlencoded",
162
+ },
163
+ body,
164
+ })
165
+ .then(hasStatus(200))
166
+ .then((res) => res.json())
167
+ .then(AuthorizationResponse.parse);
168
+ };
@@ -0,0 +1,26 @@
1
+ import { startFlowFromQR, type StartFlow } from "./01-start-flow";
2
+ import {
3
+ evaluateRelyingPartyTrust,
4
+ type EvaluateRelyingPartyTrust,
5
+ } from "./02-evaluate-rp-trust";
6
+ import {
7
+ getRequestObject,
8
+ type GetRequestObject,
9
+ } from "./03-get-request-object";
10
+ import {
11
+ sendAuthorizationResponse,
12
+ type SendAuthorizationResponse,
13
+ } from "./04-send-authorization-response";
14
+
15
+ export {
16
+ startFlowFromQR,
17
+ evaluateRelyingPartyTrust,
18
+ getRequestObject,
19
+ sendAuthorizationResponse,
20
+ };
21
+ export type {
22
+ StartFlow,
23
+ EvaluateRelyingPartyTrust,
24
+ GetRequestObject,
25
+ SendAuthorizationResponse,
26
+ };
@@ -0,0 +1,27 @@
1
+ import type { CryptoContext } from "@pagopa/io-react-native-jwt";
2
+ import { UnixTime } from "../../sd-jwt/types";
3
+ import * as z from "zod";
4
+
5
+ /**
6
+ * A pair that associate a tokenized Verified Credential with the claims presented or requested to present.
7
+ */
8
+ export type Presentation = [
9
+ /* verified credential token */ string,
10
+ /* claims */ string[],
11
+ /* the context for the key associated to the credential */ CryptoContext
12
+ ];
13
+
14
+ export type RequestObject = z.infer<typeof RequestObject>;
15
+ export const RequestObject = z.object({
16
+ iss: z.string(),
17
+ iat: UnixTime,
18
+ exp: UnixTime,
19
+ state: z.string(),
20
+ nonce: z.string(),
21
+ response_uri: z.string(),
22
+ response_type: z.literal("vp_token"),
23
+ response_mode: z.literal("direct_post.jwt"),
24
+ client_id: z.string(),
25
+ client_id_scheme: z.literal("entity_id"),
26
+ scope: z.string(),
27
+ });
package/src/index.ts CHANGED
@@ -2,42 +2,21 @@
2
2
  // https://github.com/facebook/react-native/issues/24428
3
3
  import "react-native-url-polyfill/auto";
4
4
 
5
+ import * as Credential from "./credential";
5
6
  import * as PID from "./pid";
6
- import * as RP from "./rp";
7
7
  import * as Errors from "./utils/errors";
8
8
  import * as WalletInstanceAttestation from "./wallet-instance-attestation";
9
- import * as RelyingPartySolution from "./rp";
10
- import {
11
- verifyTrustChain,
12
- getEntityConfiguration,
13
- getCredentialIssuerEntityConfiguration,
14
- getRelyingPartyEntityConfiguration,
15
- getTrustAnchorEntityConfiguration,
16
- getWalletProviderEntityConfiguration,
17
- } from "./trust";
18
- import {
19
- RelyingPartyEntityConfiguration,
20
- WalletProviderEntityConfiguration,
21
- TrustAnchorEntityConfiguration,
22
- CredentialIssuerEntityConfiguration,
23
- } from "./trust/types";
9
+ import * as Trust from "./trust";
10
+ import { AuthorizationDetail, AuthorizationDetails } from "./utils/par";
24
11
  import { createCryptoContextFor } from "./utils/crypto";
25
12
 
26
13
  export {
27
14
  PID,
28
- RP,
15
+ Credential,
29
16
  WalletInstanceAttestation,
30
17
  Errors,
31
- RelyingPartySolution,
32
- verifyTrustChain,
33
- getEntityConfiguration,
34
- getCredentialIssuerEntityConfiguration,
35
- getRelyingPartyEntityConfiguration,
36
- getTrustAnchorEntityConfiguration,
37
- getWalletProviderEntityConfiguration,
18
+ Trust,
38
19
  createCryptoContextFor,
39
- RelyingPartyEntityConfiguration,
40
- WalletProviderEntityConfiguration,
41
- TrustAnchorEntityConfiguration,
42
- CredentialIssuerEntityConfiguration,
20
+ AuthorizationDetail,
21
+ AuthorizationDetails,
43
22
  };
package/src/pid/index.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  import * as SdJwt from "./sd-jwt";
2
- import * as Issuing from "./issuing";
3
- export { SdJwt, Issuing };
2
+ export { SdJwt };
@@ -135,7 +135,7 @@ export const disclose = async (
135
135
  *
136
136
  *
137
137
  * @param token The encoded token that represents a valid sd-jwt for verifiable credentials
138
- * @param publicKey The public key to validate the signature
138
+ * @param publicKey The single public key or an array of public keys to validate the signature.
139
139
  * @param schema Schema to use to parse the SD-JWT
140
140
  *
141
141
  * @returns The parsed SD-JWT token and the parsed disclosures
@@ -143,7 +143,7 @@ export const disclose = async (
143
143
  */
144
144
  export const verify = async <S extends z.AnyZodObject>(
145
145
  token: string,
146
- publicKey: JWK,
146
+ publicKey: JWK | JWK[],
147
147
  schema: S
148
148
  ): Promise<{ sdJwt: z.infer<S>; disclosures: Disclosure[] }> => {
149
149
  // get decoded data
@@ -51,7 +51,7 @@ export const SdJwt4VC = z.object({
51
51
  cnf: z.object({
52
52
  jwk: JWK,
53
53
  }),
54
- type: z.literal("PersonIdentificationData"),
54
+ type: z.string(),
55
55
  verified_claims: z.object({
56
56
  verification: z.intersection(
57
57
  z.object({
@@ -11,6 +11,7 @@ import { JWK } from "../utils/jwk";
11
11
  import { IoWalletError } from "../utils/errors";
12
12
  import * as z from "zod";
13
13
  import type { JWTDecodeResult } from "@pagopa/io-react-native-jwt/lib/typescript/types";
14
+ import { getSignedEntityConfiguration, getSignedEntityStatement } from ".";
14
15
 
15
16
  type ParsedToken = {
16
17
  header: JWTDecodeResult["protectedHeader"];
@@ -51,12 +52,12 @@ const LastElementShape = z.union([
51
52
  /**
52
53
  * Validates a provided trust chain against a known trust
53
54
  *
54
- * @param trustAnchorEntity
55
- * @param chain
55
+ * @param trustAnchorEntity The entity configuration of the known trust anchor
56
+ * @param chain The chain of statements to be validate
56
57
  * @returns The list of parsed token representing the chain
57
58
  * @throws {IoWalletError} If the chain is not valid
58
59
  */
59
- export async function verifyTrustChain(
60
+ export async function validateTrustChain(
60
61
  trustAnchorEntity: TrustAnchorEntityConfiguration,
61
62
  chain: string[]
62
63
  ): Promise<ParsedToken[]> {
@@ -107,3 +108,44 @@ export async function verifyTrustChain(
107
108
  .map((args) => verify(...args))
108
109
  );
109
110
  }
111
+
112
+ /**
113
+ * Given a trust chain, obtain a new trust chain by fetching each element's fresh version
114
+ *
115
+ * @param chain The original chain
116
+ * @param appFetch (optional) fetch api implementation
117
+ * @returns A list of signed token that reprensent the trust chain, in the same order of the provided chain
118
+ * @throws When an element of the chain fails to parse
119
+ */
120
+ export function renewTrustChain(
121
+ chain: string[],
122
+ appFetch: GlobalFetch["fetch"] = fetch
123
+ ) {
124
+ return Promise.all(
125
+ chain
126
+ // Decode each item to determine its shape
127
+ .map(decode)
128
+ .map(
129
+ (e) =>
130
+ [
131
+ EntityStatement.safeParse(e),
132
+ EntityConfiguration.safeParse(e),
133
+ ] as const
134
+ )
135
+ // fetch the element according to its shape
136
+ .map(([es, ec], i) =>
137
+ ec.success
138
+ ? getSignedEntityConfiguration(ec.data.payload.iss, { appFetch })
139
+ : es.success
140
+ ? getSignedEntityStatement(es.data.payload.iss, es.data.payload.sub, {
141
+ appFetch,
142
+ })
143
+ : // if the element fail to parse in both EntityStatement and EntityConfiguration, raise an error
144
+ Promise.reject(
145
+ new IoWalletError(
146
+ `Cannot renew trust chain because the element #${i} failed to be parsed.`
147
+ )
148
+ )
149
+ )
150
+ );
151
+ }