@pagopa/io-react-native-wallet 0.7.3 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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 +4 -10
  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 -8
  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 -8
  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
+ }