@pagopa/io-wallet-oid4vci 1.2.1 → 1.3.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.
package/dist/index.mjs CHANGED
@@ -12,83 +12,80 @@ import {
12
12
 
13
13
  // src/errors.ts
14
14
  var Oid4vciError = class extends Error {
15
- constructor(message, statusCode) {
16
- super(message);
17
- this.statusCode = statusCode;
15
+ statusCode;
16
+ constructor(message, options) {
17
+ super(message, options);
18
18
  this.name = "Oid4vciError";
19
+ this.statusCode = options?.statusCode;
19
20
  }
20
21
  };
21
22
  var WalletProviderError = class extends Oid4vciError {
22
- constructor(message, cause) {
23
- super(message);
23
+ constructor(message, options) {
24
+ super(message, options);
24
25
  this.name = "WalletProviderError";
25
- this.cause = cause;
26
26
  }
27
27
  };
28
28
  var NonceRequestError = class extends Error {
29
- constructor(message, statusCode) {
30
- super(message);
31
- this.statusCode = statusCode;
29
+ statusCode;
30
+ constructor(message, options) {
31
+ super(message, options);
32
32
  this.name = "NonceRequestError";
33
+ this.statusCode = options?.statusCode;
33
34
  }
34
35
  };
35
36
  var FetchCredentialResponseError = class extends Oid4vciError {
36
- constructor(message, cause) {
37
- super(message);
37
+ constructor(message, options) {
38
+ super(message, options);
38
39
  this.name = "FetchCredentialResponseError";
39
- this.cause = cause;
40
40
  }
41
41
  };
42
42
  var ParseCredentialRequestError = class extends Oid4vciError {
43
- constructor(message, cause) {
44
- super(message);
43
+ constructor(message, options) {
44
+ super(message, options);
45
45
  this.name = "ParseCredentialRequestError";
46
- this.cause = cause;
47
46
  }
48
47
  };
49
48
  var FetchMetadataError = class extends Oid4vciError {
50
- constructor(message, cause) {
51
- super(message);
52
- this.cause = cause;
49
+ constructor(message, options) {
50
+ super(message, options);
53
51
  this.name = "FetchMetadataError";
54
52
  }
55
53
  };
56
54
  var CreateCredentialResponseError = class extends Oid4vciError {
57
- constructor(message, cause) {
58
- super(message);
55
+ constructor(message, options) {
56
+ super(message, options);
59
57
  this.name = "CreateCredentialResponseError";
60
- this.cause = cause;
61
58
  }
62
59
  };
63
60
  var VerifyCredentialRequestJwtProofError = class extends Oid4vciError {
64
- constructor(message, cause) {
65
- super(message);
61
+ constructor(message, options) {
62
+ super(message, options);
66
63
  this.name = "VerifyCredentialRequestJwtProofError";
67
- this.cause = cause;
68
64
  }
69
65
  };
70
66
  var VerifyKeyAttestationJwtError = class extends Oid4vciError {
71
- constructor(message, cause) {
72
- super(message);
67
+ constructor(message, options) {
68
+ super(message, options);
73
69
  this.name = "VerifyKeyAttestationJwtError";
74
- this.cause = cause;
75
70
  }
76
71
  };
77
72
  var CredentialOfferError = class extends Oid4vciError {
78
- constructor(message, statusCode) {
79
- super(message, statusCode);
73
+ statusCode;
74
+ constructor(message, options) {
75
+ super(message, options);
80
76
  this.name = "CredentialOfferError";
77
+ this.statusCode = options?.statusCode;
81
78
  }
82
79
  };
83
80
  var MissingDpopProofError = class extends Oid4vciError {
84
- constructor(message = "Credential request is missing required 'DPoP' proof header") {
85
- super(message);
81
+ constructor(message = "Credential request is missing required 'DPoP' proof header", options) {
82
+ super(message, options);
86
83
  this.name = "MissingDpopProofError";
87
84
  }
88
85
  };
89
86
  var CredentialAuthorizationHeaderError = class extends Oid4vciError {
90
- constructor(message = "Credential request is missing required 'Authorization' header with DPoP scheme") {
91
- super(message);
87
+ constructor(message = "Credential request is missing required 'Authorization' header with DPoP scheme", options) {
88
+ super(message, options);
92
89
  this.name = "CredentialAuthorizationHeaderError";
93
90
  }
94
91
  };
@@ -501,8 +498,9 @@ import {
501
498
 
502
499
  // src/credential-request/v1.3/z-credential.ts
503
500
  import { z as z5 } from "zod";
501
+ var zCredentialRequestProofJwt = z5.string().min(1, "JWT must not be empty in credential request proofs array");
504
502
  var zCredentialRequestProofs = z5.object({
505
- jwt: z5.array(z5.string().min(1, "JWT must not be empty")).min(1, "At least one JWT proof is required")
503
+ jwt: z5.tuple([zCredentialRequestProofJwt], zCredentialRequestProofJwt)
506
504
  });
507
505
  var zCredentialRequestV1_3 = zBaseCredentialRequest.extend({
508
506
  proofs: zCredentialRequestProofs.describe(
@@ -516,7 +514,8 @@ var zCredentialRequestV1_3 = zBaseCredentialRequest.extend({
516
514
  var createCredentialRequest2 = async (options) => {
517
515
  try {
518
516
  const { maxBatchSize, signers } = options;
519
- if (signers.length === 0) {
517
+ const [firstSigner, ...otherSigners] = signers;
518
+ if (!firstSigner) {
520
519
  throw new ValidationError3("At least one signer is required");
521
520
  }
522
521
  if (maxBatchSize !== void 0) {
@@ -549,29 +548,28 @@ var createCredentialRequest2 = async (options) => {
549
548
  );
550
549
  }
551
550
  }
552
- const proofJwts = await Promise.all(
553
- signers.map(
554
- (signer) => signJwt(signer, {
555
- header: {
556
- alg: signer.alg,
557
- jwk: signer.publicJwk,
558
- key_attestation: options.keyAttestation,
559
- typ: "openid4vci-proof+jwt"
560
- },
561
- payload: {
562
- aud: options.issuerIdentifier,
563
- iat: dateToSeconds2(/* @__PURE__ */ new Date()),
564
- iss: options.clientId,
565
- nonce: options.nonce
566
- }
567
- })
568
- )
569
- );
551
+ const createProofJwt = async (signer) => (await signJwt(signer, {
552
+ header: {
553
+ alg: signer.alg,
554
+ jwk: signer.publicJwk,
555
+ key_attestation: options.keyAttestation,
556
+ typ: "openid4vci-proof+jwt"
557
+ },
558
+ payload: {
559
+ aud: options.issuerIdentifier,
560
+ iat: dateToSeconds2(/* @__PURE__ */ new Date()),
561
+ iss: options.clientId,
562
+ nonce: options.nonce
563
+ }
564
+ })).jwt;
565
+ const proofJwts = await Promise.all([
566
+ createProofJwt(firstSigner),
567
+ ...otherSigners.map(createProofJwt)
568
+ ]);
570
569
  return parseWithErrorHandling2(zCredentialRequestV1_3, {
571
570
  credential_identifier: options.credential_identifier,
572
571
  proofs: {
573
- jwt: proofJwts.map((proofJwt) => proofJwt.jwt)
574
- // Array for batch support
572
+ jwt: proofJwts
575
573
  }
576
574
  });
577
575
  } catch (error) {
@@ -669,7 +667,10 @@ function validateTransactionContext(options) {
669
667
  }
670
668
  }
671
669
  function parseProofJwt(options) {
672
- const decoded = decodeJwt({ jwt: options.jwt });
670
+ const decoded = decodeJwt({
671
+ errorMessagePrefix: "Error decoding credential request proof JWT:",
672
+ jwt: options.jwt
673
+ });
673
674
  const headerValidation = options.itWalletSpecsVersion === ItWalletSpecsVersion4.V1_3 ? zProofJwtHeaderV1_3.safeParse(decoded.header) : zProofJwtHeaderV1_0.safeParse(decoded.header);
674
675
  if (!headerValidation.success) {
675
676
  throw new ValidationError4(
@@ -841,7 +842,7 @@ function parseCredentialRequest(options) {
841
842
  }
842
843
  throw new ParseCredentialRequestError(
843
844
  `Unexpected error during credential request parsing: ${error instanceof Error ? error.message : String(error)}`,
844
- error
845
+ { cause: error }
845
846
  );
846
847
  }
847
848
  }
@@ -874,6 +875,7 @@ import { ValidationError as ValidationError5 } from "@pagopa/io-wallet-utils";
874
875
  // src/wallet-provider/z-key-attestation.ts
875
876
  import { zCertificateChain, zJwk as zJwk2, zTrustChain } from "@pagopa/io-wallet-oauth2";
876
877
  import { zKeyStorageLevelV1_3 } from "@pagopa/io-wallet-oid-federation";
878
+ import { zItwSupportedSignatureAlg } from "@pagopa/io-wallet-utils";
877
879
  import { z as z7 } from "zod";
878
880
  var zStatusList = z7.object({
879
881
  idx: z7.number(),
@@ -882,14 +884,7 @@ var zStatusList = z7.object({
882
884
  var zKeyAttestationStatus = z7.object({
883
885
  status_list: zStatusList
884
886
  });
885
- var zKeyAttestationAlg = z7.enum([
886
- "ES256",
887
- "ES384",
888
- "ES512",
889
- "PS256",
890
- "PS384",
891
- "PS512"
892
- ]);
887
+ var zKeyAttestationAlg = zItwSupportedSignatureAlg;
893
888
  var zKeyAttestationHeader = z7.object({
894
889
  alg: zKeyAttestationAlg,
895
890
  kid: z7.string(),
@@ -914,6 +909,7 @@ var keyAttestationTypeHeader = zKeyAttestationTypeHeader.value;
914
909
  async function verifyKeyAttestationJwt(options) {
915
910
  try {
916
911
  const { header, payload } = decodeJwt2({
912
+ errorMessagePrefix: "Error decoding key attestation JWT:",
917
913
  headerSchema: zKeyAttestationHeader,
918
914
  jwt: options.keyAttestationJwt,
919
915
  payloadSchema: zKeyAttestationPayload
@@ -946,7 +942,7 @@ async function verifyKeyAttestationJwt(options) {
946
942
  }
947
943
  throw new VerifyKeyAttestationJwtError(
948
944
  `Unexpected error during key attestation jwt verification: ${error instanceof Error ? error.message : String(error)}`,
949
- error
945
+ { cause: error }
950
946
  );
951
947
  }
952
948
  }
@@ -979,7 +975,7 @@ function verifyProofJwtIatOrThrow(options) {
979
975
  if (error instanceof Error) {
980
976
  throw new VerifyCredentialRequestJwtProofError(
981
977
  `Invalid iat claim in credential request proof JWT: ${error.message}`,
982
- error
978
+ { cause: error }
983
979
  );
984
980
  }
985
981
  }
@@ -995,6 +991,7 @@ async function verifyCredentialRequestJwtProof(options) {
995
991
  }
996
992
  if (hasConfigVersion(options, ItWalletSpecsVersion5.V1_0)) {
997
993
  const { header, payload } = decodeJwt3({
994
+ errorMessagePrefix: "Error decoding credential request proof JWT:",
998
995
  headerSchema: zProofJwtHeaderV1_0,
999
996
  jwt: options.jwt,
1000
997
  payloadSchema: zProofJwtPayload
@@ -1020,6 +1017,7 @@ async function verifyCredentialRequestJwtProof(options) {
1020
1017
  }
1021
1018
  if (hasConfigVersion(options, ItWalletSpecsVersion5.V1_3)) {
1022
1019
  const { header, payload } = decodeJwt3({
1020
+ errorMessagePrefix: "Error decoding credential request proof JWT:",
1023
1021
  headerSchema: zProofJwtHeaderV1_3,
1024
1022
  jwt: options.jwt,
1025
1023
  payloadSchema: zProofJwtPayload
@@ -1083,7 +1081,7 @@ async function verifyCredentialRequestJwtProof(options) {
1083
1081
  }
1084
1082
  throw new VerifyCredentialRequestJwtProofError(
1085
1083
  `Unexpected error during credential request proof verification: ${error instanceof Error ? error.message : String(error)}`,
1086
- error
1084
+ { cause: error }
1087
1085
  );
1088
1086
  }
1089
1087
  }
@@ -1217,7 +1215,7 @@ async function createCredentialResponse(options) {
1217
1215
  }
1218
1216
  throw new CreateCredentialResponseError(
1219
1217
  `Unexpected error during create credential response: ${error instanceof Error ? error.message : String(error)}`,
1220
- error
1218
+ { cause: error }
1221
1219
  );
1222
1220
  }
1223
1221
  }
@@ -1363,6 +1361,7 @@ async function tryFederationDiscovery(fetch, baseUrl, verifyJwt4) {
1363
1361
  }
1364
1362
  const entityStatement = await response.text();
1365
1363
  const { header, payload } = decodeJwt4({
1364
+ errorMessagePrefix: "Error decoding entity statement JWT:",
1366
1365
  jwt: entityStatement,
1367
1366
  payloadSchema: itWalletEntityStatementClaimsSchema2
1368
1367
  });
@@ -1483,15 +1482,18 @@ async function fetchMetadata(options) {
1483
1482
  if (error instanceof UnexpectedStatusCodeError4 || error instanceof ValidationError9 || error instanceof ItWalletSpecsVersionError5 || error instanceof FetchMetadataError) {
1484
1483
  throw error;
1485
1484
  }
1486
- throw new FetchMetadataError(
1487
- "Unexpected error during metadata fetch",
1488
- error
1489
- );
1485
+ throw new FetchMetadataError("Unexpected error during metadata fetch", {
1486
+ cause: error
1487
+ });
1490
1488
  }
1491
1489
  }
1492
1490
 
1493
1491
  // src/wallet-provider/WalletProvider.ts
1494
- import { V1_0, V1_3 } from "@pagopa/io-wallet-oauth2";
1492
+ import {
1493
+ createWalletAttestationJwtV1_0,
1494
+ createWalletAttestationJwtV1_3,
1495
+ createWalletAttestationJwtV1_4
1496
+ } from "@pagopa/io-wallet-oauth2";
1495
1497
  import {
1496
1498
  ItWalletSpecsVersion as ItWalletSpecsVersion8,
1497
1499
  ItWalletSpecsVersionError as ItWalletSpecsVersionError6,
@@ -1512,6 +1514,28 @@ function assertV1_3Options(options) {
1512
1514
  );
1513
1515
  }
1514
1516
  }
1517
+ function assertV1_4Options(options) {
1518
+ if (options.signer.method !== "x5c") {
1519
+ throw new WalletProviderError(
1520
+ `Version mismatch: provider is configured for v1.4 (x5c) but received options with signer method "${options.signer.method}"`
1521
+ );
1522
+ }
1523
+ if (!options.walletLink) {
1524
+ throw new WalletProviderError(
1525
+ `Version mismatch: provider is configured for v1.4 but 'walletLink' is required and missing`
1526
+ );
1527
+ }
1528
+ if (!options.walletName) {
1529
+ throw new WalletProviderError(
1530
+ `Version mismatch: provider is configured for v1.4 but 'walletName' is required and missing`
1531
+ );
1532
+ }
1533
+ if (!("status" in options) || !options.status) {
1534
+ throw new WalletProviderError(
1535
+ `Version mismatch: provider is configured for v1.4 but 'status' is required and missing`
1536
+ );
1537
+ }
1538
+ }
1515
1539
  var WalletProvider = class {
1516
1540
  specVersion;
1517
1541
  constructor(options) {
@@ -1567,8 +1591,10 @@ var WalletProvider = class {
1567
1591
  * Creates a wallet attestation JWT according to the configured Italian Wallet specification version.
1568
1592
  *
1569
1593
  * Version Differences:
1570
- * - v1.0: Uses only `trust_chain` in header (federation method)
1571
- * - v1.3: Requires `x5c` in header, optional `trust_chain`, supports `nbf` and `status` claims
1594
+ * - v1.0: Uses only `trust_chain` in header (federation method); no `status` claim
1595
+ * - v1.3: Requires `x5c` in header, optional `trust_chain`; supports optional `nbf` and `status` claims
1596
+ * - v1.4: Requires `x5c` in header, optional `trust_chain`; `status`, `wallet_link`, and `wallet_name`
1597
+ * are all **required**; optional `eudi_wallet_info` claim; sets `sub` to `dpopJwkPublic.kid`
1572
1598
  *
1573
1599
  * @public
1574
1600
  * @async
@@ -1603,6 +1629,31 @@ var WalletProvider = class {
1603
1629
  * nbf: new Date('2025-01-01'), // Optional
1604
1630
  * status: { status_list: { idx: 2, uri: "https://status.example.com" } } // Optional
1605
1631
  * });
1632
+ *
1633
+ * @example v1.4 - Wallet attestation with required status and optional eudi_wallet_info
1634
+ * const jwt = await provider.createItWalletAttestationJwt({
1635
+ * callbacks: { signJwt: mySignJwtCallback },
1636
+ * dpopJwkPublic: myJwk,
1637
+ * issuer: "https://wallet-provider.example.com",
1638
+ * signer: {
1639
+ * alg: "ES256",
1640
+ * kid: "provider-key-id",
1641
+ * method: "x5c",
1642
+ * x5c: ["cert1-base64", "cert2-base64"],
1643
+ * trustChain: ["trust-anchor-jwt"] // Optional
1644
+ * },
1645
+ * status: { status_list: { idx: 2, uri: "https://status.example.com" } }, // Required
1646
+ * walletLink: "https://wallet.example.com", // Required
1647
+ * walletName: "My Wallet", // Required
1648
+ * eudiWalletInfo: { // Optional
1649
+ * general_info: {
1650
+ * wallet_provider_name: "PagoPA",
1651
+ * wallet_solution_certification_information: "certification-ref",
1652
+ * wallet_solution_id: "wallet-solution-id",
1653
+ * wallet_solution_version: "1.0.0"
1654
+ * }
1655
+ * }
1656
+ * });
1606
1657
  */
1607
1658
  async createItWalletAttestationJwt(options) {
1608
1659
  if (!options.dpopJwkPublic.kid) {
@@ -1610,7 +1661,7 @@ var WalletProvider = class {
1610
1661
  }
1611
1662
  if (this.specVersion === ItWalletSpecsVersion8.V1_0) {
1612
1663
  assertV1_0Options(options);
1613
- return V1_0.createWalletAttestationJwt({
1664
+ return createWalletAttestationJwtV1_0({
1614
1665
  authenticatorAssuranceLevel: options.authenticatorAssuranceLevel,
1615
1666
  callbacks: options.callbacks,
1616
1667
  dpopJwkPublic: options.dpopJwkPublic,
@@ -1623,7 +1674,7 @@ var WalletProvider = class {
1623
1674
  }
1624
1675
  if (this.specVersion === ItWalletSpecsVersion8.V1_3) {
1625
1676
  assertV1_3Options(options);
1626
- return V1_3.createWalletAttestationJwt({
1677
+ return createWalletAttestationJwtV1_3({
1627
1678
  callbacks: options.callbacks,
1628
1679
  dpopJwkPublic: options.dpopJwkPublic,
1629
1680
  expiresAt: options.expiresAt,
@@ -1635,10 +1686,24 @@ var WalletProvider = class {
1635
1686
  walletName: options.walletName
1636
1687
  });
1637
1688
  }
1689
+ if (this.specVersion === ItWalletSpecsVersion8.V1_4) {
1690
+ assertV1_4Options(options);
1691
+ return createWalletAttestationJwtV1_4({
1692
+ callbacks: options.callbacks,
1693
+ dpopJwkPublic: options.dpopJwkPublic,
1694
+ eudiWalletInfo: options.eudiWalletInfo,
1695
+ expiresAt: options.expiresAt,
1696
+ issuer: options.issuer,
1697
+ signer: options.signer,
1698
+ status: options.status,
1699
+ walletLink: options.walletLink,
1700
+ walletName: options.walletName
1701
+ });
1702
+ }
1638
1703
  throw new ItWalletSpecsVersionError6(
1639
1704
  "createItWalletAttestationJwt",
1640
1705
  this.specVersion,
1641
- [ItWalletSpecsVersion8.V1_0, ItWalletSpecsVersion8.V1_3]
1706
+ Object.values(ItWalletSpecsVersion8)
1642
1707
  );
1643
1708
  }
1644
1709
  };