@pagopa/io-react-native-wallet 2.0.0-next.3 → 2.0.0-next.4

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 (64) hide show
  1. package/lib/commonjs/credential/issuance/04-complete-user-authorization.js +75 -57
  2. package/lib/commonjs/credential/issuance/04-complete-user-authorization.js.map +1 -1
  3. package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -1
  4. package/lib/commonjs/credential/issuance/README.md +45 -34
  5. package/lib/commonjs/credential/issuance/types.js +1 -0
  6. package/lib/commonjs/credential/issuance/types.js.map +1 -1
  7. package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js +6 -13
  8. package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js.map +1 -1
  9. package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js +7 -8
  10. package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
  11. package/lib/commonjs/credential/presentation/types.js +1 -1
  12. package/lib/commonjs/credential/presentation/types.js.map +1 -1
  13. package/lib/commonjs/sd-jwt/index.js +6 -1
  14. package/lib/commonjs/sd-jwt/index.js.map +1 -1
  15. package/lib/commonjs/sd-jwt/types.js +25 -9
  16. package/lib/commonjs/sd-jwt/types.js.map +1 -1
  17. package/lib/commonjs/wallet-instance-attestation/types.js +1 -2
  18. package/lib/commonjs/wallet-instance-attestation/types.js.map +1 -1
  19. package/lib/module/credential/issuance/04-complete-user-authorization.js +76 -58
  20. package/lib/module/credential/issuance/04-complete-user-authorization.js.map +1 -1
  21. package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -1
  22. package/lib/module/credential/issuance/README.md +45 -34
  23. package/lib/module/credential/issuance/types.js +1 -0
  24. package/lib/module/credential/issuance/types.js.map +1 -1
  25. package/lib/module/credential/presentation/07-evaluate-dcql-query.js +6 -13
  26. package/lib/module/credential/presentation/07-evaluate-dcql-query.js.map +1 -1
  27. package/lib/module/credential/presentation/07-evaluate-input-descriptor.js +7 -8
  28. package/lib/module/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
  29. package/lib/module/credential/presentation/types.js +1 -1
  30. package/lib/module/credential/presentation/types.js.map +1 -1
  31. package/lib/module/sd-jwt/index.js +6 -1
  32. package/lib/module/sd-jwt/index.js.map +1 -1
  33. package/lib/module/sd-jwt/types.js +25 -9
  34. package/lib/module/sd-jwt/types.js.map +1 -1
  35. package/lib/module/wallet-instance-attestation/types.js +1 -2
  36. package/lib/module/wallet-instance-attestation/types.js.map +1 -1
  37. package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts +7 -14
  38. package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts.map +1 -1
  39. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -1
  40. package/lib/typescript/credential/issuance/types.d.ts +3 -0
  41. package/lib/typescript/credential/issuance/types.d.ts.map +1 -1
  42. package/lib/typescript/credential/presentation/01-start-flow.d.ts +2 -2
  43. package/lib/typescript/credential/presentation/07-evaluate-dcql-query.d.ts +4 -3
  44. package/lib/typescript/credential/presentation/07-evaluate-dcql-query.d.ts.map +1 -1
  45. package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts +9 -5
  46. package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts.map +1 -1
  47. package/lib/typescript/credential/presentation/types.d.ts +3 -4
  48. package/lib/typescript/credential/presentation/types.d.ts.map +1 -1
  49. package/lib/typescript/credential/status/types.d.ts +4 -4
  50. package/lib/typescript/sd-jwt/index.d.ts +68 -40
  51. package/lib/typescript/sd-jwt/index.d.ts.map +1 -1
  52. package/lib/typescript/sd-jwt/types.d.ts +97 -46
  53. package/lib/typescript/sd-jwt/types.d.ts.map +1 -1
  54. package/package.json +1 -1
  55. package/src/credential/issuance/04-complete-user-authorization.ts +79 -85
  56. package/src/credential/issuance/06-obtain-credential.ts +4 -1
  57. package/src/credential/issuance/README.md +45 -34
  58. package/src/credential/issuance/types.ts +1 -0
  59. package/src/credential/presentation/07-evaluate-dcql-query.ts +16 -17
  60. package/src/credential/presentation/07-evaluate-input-descriptor.ts +16 -13
  61. package/src/credential/presentation/types.ts +1 -2
  62. package/src/sd-jwt/index.ts +5 -1
  63. package/src/sd-jwt/types.ts +24 -10
  64. package/src/wallet-instance-attestation/types.ts +1 -1
@@ -2,9 +2,9 @@ import { DcqlQuery, DcqlError, DcqlQueryResult } from "dcql";
2
2
  import { isValiError } from "valibot";
3
3
  import { decode, prepareVpToken } from "../../sd-jwt";
4
4
  import type { Disclosure } from "../../sd-jwt/types";
5
- import { createCryptoContextFor } from "../../utils/crypto";
6
5
  import type { RemotePresentation } from "./types";
7
6
  import { CredentialsNotFoundError, type NotFoundDetail } from "./errors";
7
+ import type { CryptoContext } from "@pagopa/io-react-native-jwt";
8
8
 
9
9
  /**
10
10
  * The purpose for the credential request by the RP.
@@ -15,13 +15,13 @@ type CredentialPurpose = {
15
15
  };
16
16
 
17
17
  export type EvaluateDcqlQuery = (
18
- credentialsSdJwt: [string /* keyTag */, string /* credential */][],
18
+ credentialsSdJwt: [CryptoContext, string /* credential */][],
19
19
  query: DcqlQuery.Input
20
20
  ) => {
21
21
  id: string;
22
22
  vct: string;
23
23
  credential: string;
24
- keyTag: string;
24
+ cryptoContext: CryptoContext;
25
25
  requiredDisclosures: Disclosure[];
26
26
  purposes: CredentialPurpose[];
27
27
  }[];
@@ -30,7 +30,7 @@ export type PrepareRemotePresentations = (
30
30
  credentials: {
31
31
  id: string;
32
32
  credential: string;
33
- keyTag: string;
33
+ cryptoContext: CryptoContext;
34
34
  requestedClaims: string[];
35
35
  }[],
36
36
  nonce: string,
@@ -55,11 +55,6 @@ const mapCredentialToObject = (jwt: string) => {
55
55
  const { sdJwt, disclosures } = decode(jwt);
56
56
  const credentialFormat = sdJwt.header.typ;
57
57
 
58
- // TODO [SIW-2082]: support MDOC credentials
59
- if (credentialFormat !== "dc+sd-jwt") {
60
- throw new Error(`Unsupported credential format: ${credentialFormat}`);
61
- }
62
-
63
58
  return {
64
59
  vct: sdJwt.payload.vct,
65
60
  credential_format: credentialFormat,
@@ -100,7 +95,10 @@ const extractMissingCredentials = (
100
95
  ): NotFoundDetail[] => {
101
96
  return getDcqlQueryFailedMatches(queryResult).map(([id]) => {
102
97
  const credential = originalQuery.credentials.find((c) => c.id === id);
103
- if (credential?.format !== "dc+sd-jwt") {
98
+ if (
99
+ credential?.format !== "dc+sd-jwt" &&
100
+ credential?.format !== "vc+sd-jwt"
101
+ ) {
104
102
  throw new Error("Unsupported format"); // TODO [SIW-2082]: support MDOC credentials
105
103
  }
106
104
  return { id, vctValues: credential.meta?.vct_values };
@@ -114,7 +112,6 @@ export const evaluateDcqlQuery: EvaluateDcqlQuery = (
114
112
  const credentials = credentialsSdJwt.map(([, credential]) =>
115
113
  mapCredentialToObject(credential)
116
114
  );
117
-
118
115
  try {
119
116
  // Validate the query
120
117
  const parsedQuery = DcqlQuery.parse(query);
@@ -131,11 +128,14 @@ export const evaluateDcqlQuery: EvaluateDcqlQuery = (
131
128
  // Build an object vct:credentialJwt to map matched credentials to their JWT
132
129
  const credentialsSdJwtByVct = credentials.reduce(
133
130
  (acc, c, i) => ({ ...acc, [c.vct]: credentialsSdJwt[i]! }),
134
- {} as Record<string, [string /* keyTag */, string /* credential */]>
131
+ {} as Record<string, [CryptoContext, string /* credential */]>
135
132
  );
136
133
 
137
134
  return getDcqlQueryMatches(queryResult).map(([id, match]) => {
138
- if (match.output.credential_format !== "dc+sd-jwt") {
135
+ if (
136
+ match.output.credential_format !== "dc+sd-jwt" &&
137
+ match.output.credential_format !== "vc+sd-jwt"
138
+ ) {
139
139
  throw new Error("Unsupported format"); // TODO [SIW-2082]: support MDOC credentials
140
140
  }
141
141
  const { vct, claims } = match.output;
@@ -147,12 +147,12 @@ export const evaluateDcqlQuery: EvaluateDcqlQuery = (
147
147
  required: Boolean(credentialSet.required),
148
148
  }));
149
149
 
150
- const [keyTag, credential] = credentialsSdJwtByVct[vct]!;
150
+ const [cryptoContext, credential] = credentialsSdJwtByVct[vct]!;
151
151
  const requiredDisclosures = Object.values(claims) as Disclosure[];
152
152
  return {
153
153
  id,
154
154
  vct,
155
- keyTag,
155
+ cryptoContext,
156
156
  credential,
157
157
  requiredDisclosures,
158
158
  // When it is a match but no credential_sets are found, the credential is required by default
@@ -185,14 +185,13 @@ export const prepareRemotePresentations: PrepareRemotePresentations = async (
185
185
  const { vp_token } = await prepareVpToken(nonce, clientId, [
186
186
  item.credential,
187
187
  item.requestedClaims,
188
- createCryptoContextFor(item.keyTag),
188
+ item.cryptoContext,
189
189
  ]);
190
190
 
191
191
  return {
192
192
  credentialId: item.id,
193
193
  requestedClaims: item.requestedClaims,
194
194
  vpToken: vp_token,
195
- format: "dc+sd-jwt",
196
195
  };
197
196
  })
198
197
  );
@@ -1,10 +1,10 @@
1
1
  import { InputDescriptor, type LegacyRemotePresentation } from "./types";
2
2
  import { SdJwt4VC, type DisclosureWithEncoded } from "../../sd-jwt/types";
3
3
  import { decode, prepareVpToken } from "../../sd-jwt";
4
- import { createCryptoContextFor } from "../../utils/crypto";
5
4
  import { JSONPath } from "jsonpath-plus";
6
5
  import { CredentialsNotFoundError, MissingDataError } from "./errors";
7
6
  import Ajv from "ajv";
7
+ import type { CryptoContext } from "@pagopa/io-react-native-jwt";
8
8
 
9
9
  const ajv = new Ajv({ allErrors: true });
10
10
  const INDEX_CLAIM_NAME = 1;
@@ -23,13 +23,16 @@ export type EvaluateInputDescriptorSdJwt4VC = (
23
23
 
24
24
  export type EvaluateInputDescriptors = (
25
25
  descriptors: InputDescriptor[],
26
- credentialsSdJwt: [string /* keyTag */, string /* credential */][]
26
+ credentialsSdJwt: [
27
+ CryptoContext /* cryptoContext */,
28
+ string /* credential */,
29
+ ][]
27
30
  ) => Promise<
28
31
  {
29
32
  evaluatedDisclosure: EvaluatedDisclosures;
30
33
  inputDescriptor: InputDescriptor;
31
34
  credential: string;
32
- keyTag: string;
35
+ cryptoContext: CryptoContext;
33
36
  }[]
34
37
  >;
35
38
 
@@ -41,7 +44,7 @@ export type PrepareLegacyRemotePresentations = (
41
44
  requestedClaims: string[];
42
45
  inputDescriptor: InputDescriptor;
43
46
  credential: string;
44
- keyTag: string;
47
+ cryptoContext: CryptoContext;
45
48
  }[],
46
49
  nonce: string,
47
50
  client_id: string
@@ -247,7 +250,7 @@ export const evaluateInputDescriptorForSdJwt4VC: EvaluateInputDescriptorSdJwt4VC
247
250
  };
248
251
 
249
252
  type DecodedCredentialSdJwt = {
250
- keyTag: string;
253
+ cryptoContext: CryptoContext;
251
254
  credential: string;
252
255
  sdJwt: SdJwt4VC;
253
256
  disclosures: DisclosureWithEncoded[];
@@ -264,11 +267,11 @@ export const findCredentialSdJwt = (
264
267
  decodedSdJwtCredentials: DecodedCredentialSdJwt[]
265
268
  ): {
266
269
  matchedEvaluation: EvaluatedDisclosures;
267
- matchedKeyTag: string;
268
270
  matchedCredential: string;
271
+ cryptoContext: CryptoContext;
269
272
  } => {
270
273
  for (const {
271
- keyTag,
274
+ cryptoContext,
272
275
  credential,
273
276
  sdJwt,
274
277
  disclosures,
@@ -282,7 +285,7 @@ export const findCredentialSdJwt = (
282
285
 
283
286
  return {
284
287
  matchedEvaluation: evaluatedDisclosure,
285
- matchedKeyTag: keyTag,
288
+ cryptoContext,
286
289
  matchedCredential: credential,
287
290
  };
288
291
  } catch {
@@ -319,9 +322,9 @@ export const evaluateInputDescriptors: EvaluateInputDescriptors = async (
319
322
  ) => {
320
323
  // We need decode SD-JWT credentials for evaluation
321
324
  const decodedSdJwtCredentials =
322
- credentialsSdJwt?.map(([keyTag, credential]) => {
325
+ credentialsSdJwt?.map(([cryptoContext, credential]) => {
323
326
  const { sdJwt, disclosures } = decode(credential);
324
- return { keyTag, credential, sdJwt, disclosures };
327
+ return { cryptoContext, credential, sdJwt, disclosures };
325
328
  }) || [];
326
329
 
327
330
  return Promise.all(
@@ -336,14 +339,14 @@ export const evaluateInputDescriptors: EvaluateInputDescriptors = async (
336
339
  ]);
337
340
  }
338
341
 
339
- const { matchedEvaluation, matchedKeyTag, matchedCredential } =
342
+ const { matchedEvaluation, cryptoContext, matchedCredential } =
340
343
  findCredentialSdJwt(descriptor, decodedSdJwtCredentials);
341
344
 
342
345
  return {
343
346
  evaluatedDisclosure: matchedEvaluation,
344
347
  inputDescriptor: descriptor,
345
348
  credential: matchedCredential,
346
- keyTag: matchedKeyTag,
349
+ cryptoContext,
347
350
  };
348
351
  }
349
352
 
@@ -383,7 +386,7 @@ export const prepareLegacyRemotePresentations: PrepareLegacyRemotePresentations
383
386
  const { vp_token } = await prepareVpToken(nonce, client_id, [
384
387
  item.credential,
385
388
  item.requestedClaims,
386
- createCryptoContextFor(item.keyTag),
389
+ item.cryptoContext,
387
390
  ]);
388
391
 
389
392
  return {
@@ -30,7 +30,6 @@ export type LegacyRemotePresentation = {
30
30
  export type RemotePresentation = {
31
31
  requestedClaims: string[];
32
32
  credentialId: string;
33
- format: string;
34
33
  vpToken: string;
35
34
  };
36
35
 
@@ -97,7 +96,7 @@ export const RequestObject = z.object({
97
96
  state: z.string().optional(),
98
97
  nonce: z.string(),
99
98
  response_uri: z.string(),
100
- response_uri_method: z.string().optional(),
99
+ request_uri_method: z.string().optional(),
101
100
  response_type: z.literal("vp_token"),
102
101
  response_mode: z.literal("direct_post.jwt"),
103
102
  client_id: z.string(),
@@ -110,7 +110,11 @@ export const disclose = async (
110
110
  })
111
111
  );
112
112
 
113
- const filteredDisclosures = rawDisclosures.filter((d) => {
113
+ // The disclosures in the new SD-JWT aligned with version 1.0
114
+ // include a trailing "~" character.
115
+ // To avoid parsing errors, it is necessary to filter the array
116
+ // to remove any empty strings
117
+ const filteredDisclosures = rawDisclosures.filter(Boolean).filter((d) => {
114
118
  const {
115
119
  decoded: [, name],
116
120
  } = decodeDisclosure(d);
@@ -33,12 +33,23 @@ export type DisclosureWithEncoded = {
33
33
  encoded: string;
34
34
  };
35
35
 
36
+ const StatusAssertion = z.object({
37
+ credential_hash_alg: z.literal("sha-256"),
38
+ });
39
+
40
+ /**
41
+ * Type for a Verifiable Credential in SD-JWT format.
42
+ * It supports both the older and the new data model for backward compatibility.
43
+ */
36
44
  export type SdJwt4VC = z.infer<typeof SdJwt4VC>;
37
45
  export const SdJwt4VC = z.object({
38
46
  header: z.object({
39
- typ: z.literal("dc+sd-jwt"),
47
+ typ: z.enum(["vc+sd-jwt", "dc+sd-jwt"]),
40
48
  alg: z.string(),
41
- kid: z.string().optional(),
49
+ kid: z.string(),
50
+ trust_chain: z.array(z.string()).optional(),
51
+ x5c: z.array(z.string()).optional(),
52
+ vctm: z.array(z.string()).optional(),
42
53
  }),
43
54
  payload: z.intersection(
44
55
  z.object({
@@ -47,18 +58,21 @@ export const SdJwt4VC = z.object({
47
58
  iat: UnixTime.optional(),
48
59
  exp: UnixTime,
49
60
  _sd_alg: z.literal("sha-256"),
50
- status: z.object({
51
- status_assertion: z.object({
52
- credential_hash_alg: z.literal("sha-256"),
53
- }),
54
- }),
61
+ status: z
62
+ .union([
63
+ // Credentials v1.0
64
+ z.object({ status_assertion: StatusAssertion }),
65
+ // Credentials v0.7.1
66
+ z.object({ status_attestation: StatusAssertion }),
67
+ ])
68
+ .optional(),
55
69
  cnf: z.object({
56
70
  jwk: JWK,
57
71
  }),
58
72
  vct: z.string(),
59
- "vct#integrity": z.string(),
60
- issuing_authority: z.string(),
61
- issuing_country: z.string(),
73
+ "vct#integrity": z.string().optional(),
74
+ issuing_authority: z.string().optional(),
75
+ issuing_country: z.string().optional(),
62
76
  }),
63
77
  ObfuscatedDisclosures
64
78
  ),
@@ -58,7 +58,7 @@ export const WalletInstanceAttestationJwt = z.object({
58
58
  Jwt.shape.header,
59
59
  z.object({
60
60
  typ: z.literal("oauth-client-attestation+jwt"),
61
- trust_chain: z.array(z.string()).optional(), // TODO: [SIW-2264] Make mandatory
61
+ trust_chain: z.array(z.string()).optional(),
62
62
  })
63
63
  ),
64
64
  payload: z.intersection(