@openeudi/openid4vp 0.11.1 → 0.13.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/README.md +140 -4
- package/dist/index.cjs +742 -113
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +165 -8
- package/dist/index.d.ts +165 -8
- package/dist/index.js +741 -115
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -45,7 +45,7 @@ var init_reflect_polyfill = __esm({
|
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
// src/errors.ts
|
|
48
|
-
exports.InvalidSignatureError = void 0; exports.ExpiredCredentialError = void 0; exports.UnsupportedFormatError = void 0; exports.MalformedCredentialError = void 0; exports.NonceValidationError = void 0; exports.HaipValidationError = void 0; exports.OpenID4VPError = void 0; exports.TrustAnchorNotFoundError = void 0; exports.CertificateChainError = void 0; exports.RevokedCertificateError = void 0; exports.RevocationCheckFailedError = void 0; exports.LotlFetchError = void 0; exports.LotlSignatureError = void 0; exports.SignedRequestBuildError = void 0; exports.UnsupportedJweError = void 0; exports.DecryptionFailedError = void 0; exports.MissingDecryptionKeyError = void 0; exports.MissingVerifierEncryptionKeyError = void 0; exports.MultipleCredentialsNotSupportedError = void 0;
|
|
48
|
+
exports.InvalidSignatureError = void 0; exports.ExpiredCredentialError = void 0; exports.UnsupportedFormatError = void 0; exports.MalformedCredentialError = void 0; exports.NonceValidationError = void 0; exports.HaipValidationError = void 0; exports.OpenID4VPError = void 0; exports.TrustAnchorNotFoundError = void 0; exports.CertificateChainError = void 0; exports.RevokedCertificateError = void 0; exports.RevocationCheckFailedError = void 0; exports.LotlFetchError = void 0; exports.LotlSignatureError = void 0; exports.LotlConfigurationError = void 0; exports.SignedRequestBuildError = void 0; exports.UnsupportedJweError = void 0; exports.DecryptionFailedError = void 0; exports.MissingDecryptionKeyError = void 0; exports.MissingVerifierEncryptionKeyError = void 0; exports.MultipleCredentialsNotSupportedError = void 0; exports.GuardedFetchError = void 0;
|
|
49
49
|
var init_errors = __esm({
|
|
50
50
|
"src/errors.ts"() {
|
|
51
51
|
init_reflect_polyfill();
|
|
@@ -142,6 +142,9 @@ var init_errors = __esm({
|
|
|
142
142
|
exports.LotlSignatureError = class extends exports.OpenID4VPError {
|
|
143
143
|
code = "lotl_signature_invalid";
|
|
144
144
|
};
|
|
145
|
+
exports.LotlConfigurationError = class extends exports.OpenID4VPError {
|
|
146
|
+
code = "lotl_configuration_invalid";
|
|
147
|
+
};
|
|
145
148
|
exports.SignedRequestBuildError = class extends exports.OpenID4VPError {
|
|
146
149
|
code;
|
|
147
150
|
constructor(code, message) {
|
|
@@ -189,6 +192,16 @@ var init_errors = __esm({
|
|
|
189
192
|
this.presentationCount = presentationCount;
|
|
190
193
|
}
|
|
191
194
|
};
|
|
195
|
+
exports.GuardedFetchError = class extends exports.OpenID4VPError {
|
|
196
|
+
code = "guarded_fetch_rejected";
|
|
197
|
+
reason;
|
|
198
|
+
url;
|
|
199
|
+
constructor(reason, message, options) {
|
|
200
|
+
super(message, { cause: options.cause });
|
|
201
|
+
this.reason = reason;
|
|
202
|
+
this.url = options.url;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
192
205
|
}
|
|
193
206
|
});
|
|
194
207
|
|
|
@@ -6585,7 +6598,7 @@ function dnIsUnder(childDn, subtreeDn) {
|
|
|
6585
6598
|
}
|
|
6586
6599
|
return true;
|
|
6587
6600
|
}
|
|
6588
|
-
var NAME_CONSTRAINTS_OID, DEFAULT_ALGORITHMS, ChainBuilder;
|
|
6601
|
+
var NAME_CONSTRAINTS_OID, ISO_18013_5_DS_EKU, DEFAULT_MAX_CHAIN_LENGTH, DEFAULT_MAX_SIGNATURE_CHECKS, searchAborts, DEFAULT_ALGORITHMS, ChainBuilder;
|
|
6589
6602
|
var init_ChainBuilder = __esm({
|
|
6590
6603
|
"src/trust/ChainBuilder.ts"() {
|
|
6591
6604
|
init_reflect_polyfill();
|
|
@@ -6594,6 +6607,10 @@ var init_ChainBuilder = __esm({
|
|
|
6594
6607
|
init_errors();
|
|
6595
6608
|
init_x509_utils();
|
|
6596
6609
|
NAME_CONSTRAINTS_OID = "2.5.29.30";
|
|
6610
|
+
ISO_18013_5_DS_EKU = "1.0.18013.5.1.2";
|
|
6611
|
+
DEFAULT_MAX_CHAIN_LENGTH = 5;
|
|
6612
|
+
DEFAULT_MAX_SIGNATURE_CHECKS = 32;
|
|
6613
|
+
searchAborts = /* @__PURE__ */ new WeakSet();
|
|
6597
6614
|
DEFAULT_ALGORITHMS = [
|
|
6598
6615
|
"ES256",
|
|
6599
6616
|
"ES384",
|
|
@@ -6616,62 +6633,130 @@ var init_ChainBuilder = __esm({
|
|
|
6616
6633
|
* optionally using additional intermediates. Returns the ordered chain
|
|
6617
6634
|
* (leaf → anchor). Throws `CertificateChainError` on any validation
|
|
6618
6635
|
* failure.
|
|
6636
|
+
*
|
|
6637
|
+
* Trust is by presence in the anchor set and is established ONLY by (a) the
|
|
6638
|
+
* leaf being byte-identical to an anchor, or (b) a verified signature by an
|
|
6639
|
+
* anchor's key on the last certificate of the path. Subject/Issuer DN
|
|
6640
|
+
* equality is used to select candidates, never to conclude trust
|
|
6641
|
+
* (GHSA-4c2f-96cf-f5fc).
|
|
6642
|
+
*
|
|
6643
|
+
* The search is depth-first and backtracks: when several intermediates share
|
|
6644
|
+
* a Subject DN — a re-issued certificate next to its expired predecessor, or
|
|
6645
|
+
* cross-signed copies under different roots — a candidate that fails a check
|
|
6646
|
+
* or leads nowhere does not end the search. The result therefore does not
|
|
6647
|
+
* depend on the order of `intermediates`. Work is bounded by
|
|
6648
|
+
* `maxChainLength` and `maxSignatureChecks`.
|
|
6619
6649
|
*/
|
|
6620
|
-
async build(leaf, anchors, intermediates = []) {
|
|
6621
|
-
const
|
|
6650
|
+
async build(leaf, anchors, intermediates = [], context = {}) {
|
|
6651
|
+
const search = {
|
|
6652
|
+
remaining: this.opts.maxSignatureChecks ?? DEFAULT_MAX_SIGNATURE_CHECKS
|
|
6653
|
+
};
|
|
6654
|
+
let lastFailure;
|
|
6622
6655
|
for (const anchor of anchors) {
|
|
6656
|
+
search.specific = void 0;
|
|
6657
|
+
search.fallback = void 0;
|
|
6623
6658
|
try {
|
|
6624
|
-
|
|
6659
|
+
const chain = await this.tryBuild(leaf, anchor, intermediates, context, search);
|
|
6660
|
+
if (chain) return chain;
|
|
6661
|
+
lastFailure = search.specific ?? search.fallback;
|
|
6625
6662
|
} catch (err) {
|
|
6626
|
-
|
|
6663
|
+
if (searchAborts.has(err)) throw err;
|
|
6664
|
+
lastFailure = err;
|
|
6627
6665
|
}
|
|
6628
6666
|
}
|
|
6629
|
-
|
|
6630
|
-
if (last instanceof exports.CertificateChainError) throw last;
|
|
6667
|
+
if (lastFailure instanceof exports.CertificateChainError) throw lastFailure;
|
|
6631
6668
|
throw new exports.CertificateChainError("no valid chain to any anchor", {
|
|
6632
6669
|
reason: "signature",
|
|
6633
|
-
cause:
|
|
6670
|
+
cause: lastFailure
|
|
6634
6671
|
});
|
|
6635
6672
|
}
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
this.
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6673
|
+
/** Search for a path from `leaf` that closes at `anchor`. */
|
|
6674
|
+
async tryBuild(leaf, anchor, intermediates, context, search) {
|
|
6675
|
+
this.checkPerCert(leaf, context);
|
|
6676
|
+
if (certificatesEqual(leaf, anchor)) {
|
|
6677
|
+
this.checkLeafKeyUsage(leaf, "generic");
|
|
6678
|
+
return [leaf];
|
|
6679
|
+
}
|
|
6680
|
+
const profile = this.opts.profile ?? "generic";
|
|
6681
|
+
this.checkLeafKeyUsage(leaf, profile);
|
|
6682
|
+
this.checkLeafExtendedKeyUsage(leaf, profile);
|
|
6683
|
+
const pool = intermediates.filter(
|
|
6684
|
+
(c) => !certificatesEqual(c, anchor) && !certificatesEqual(c, leaf)
|
|
6685
|
+
);
|
|
6686
|
+
return this.extendPath([leaf], anchor, pool, context, search);
|
|
6687
|
+
}
|
|
6688
|
+
/**
|
|
6689
|
+
* Try to complete `chain` (leaf first) to `anchor`. Returns the completed
|
|
6690
|
+
* chain, or `undefined` when no extension of this prefix works — failures
|
|
6691
|
+
* are recorded on `search` so the caller can report the most specific one.
|
|
6692
|
+
* Throws only to abandon the whole search (signature budget exhausted).
|
|
6693
|
+
*/
|
|
6694
|
+
async extendPath(chain, anchor, pool, context, search) {
|
|
6695
|
+
const leaf = chain[0];
|
|
6696
|
+
const current = chain[chain.length - 1];
|
|
6697
|
+
const maxLength = this.opts.maxChainLength ?? DEFAULT_MAX_CHAIN_LENGTH;
|
|
6698
|
+
if (chain.length + 1 > maxLength) {
|
|
6699
|
+
search.specific = new exports.CertificateChainError(
|
|
6700
|
+
`chain from ${leaf.subject} exceeds the maximum length of ${maxLength} certificates`,
|
|
6701
|
+
{ reason: "path_length" }
|
|
6702
|
+
);
|
|
6703
|
+
return void 0;
|
|
6704
|
+
}
|
|
6705
|
+
const nonLeafDepth = chain.length - 1;
|
|
6706
|
+
if (current.issuer === anchor.subject) {
|
|
6707
|
+
try {
|
|
6708
|
+
await this.closeAtAnchor(current, anchor, nonLeafDepth, context, search);
|
|
6709
|
+
const closed = [...chain, anchor];
|
|
6710
|
+
this.checkNameConstraints(leaf, closed.slice(1));
|
|
6711
|
+
return closed;
|
|
6712
|
+
} catch (err) {
|
|
6713
|
+
if (searchAborts.has(err)) throw err;
|
|
6714
|
+
search.specific = err;
|
|
6658
6715
|
}
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6716
|
+
}
|
|
6717
|
+
const candidates = pool.filter(
|
|
6718
|
+
(c) => c.subject === current.issuer && !chain.some((x) => certificatesEqual(x, c))
|
|
6719
|
+
);
|
|
6720
|
+
let verified = 0;
|
|
6721
|
+
for (const candidate of candidates) {
|
|
6722
|
+
if (!await this.signatureVerifies(current, candidate, search)) continue;
|
|
6723
|
+
verified++;
|
|
6724
|
+
try {
|
|
6725
|
+
this.checkPerCert(candidate, context);
|
|
6726
|
+
this.checkCaAndPathLen(candidate, nonLeafDepth);
|
|
6727
|
+
this.checkAkiSkiMatch(current, candidate);
|
|
6728
|
+
} catch (err) {
|
|
6729
|
+
search.specific = err;
|
|
6730
|
+
continue;
|
|
6731
|
+
}
|
|
6732
|
+
const found = await this.extendPath([...chain, candidate], anchor, pool, context, search);
|
|
6733
|
+
if (found) return found;
|
|
6734
|
+
}
|
|
6735
|
+
search.fallback = new exports.CertificateChainError(
|
|
6736
|
+
candidates.length > 0 && verified === 0 ? `signature verification failed for ${current.subject}` : `no issuer certificate found for ${current.subject}`,
|
|
6737
|
+
{ reason: "signature" }
|
|
6738
|
+
);
|
|
6739
|
+
return void 0;
|
|
6740
|
+
}
|
|
6741
|
+
async closeAtAnchor(current, anchor, nonLeafDepth, context, search) {
|
|
6742
|
+
this.checkPerCert(anchor, context);
|
|
6743
|
+
this.checkCaAndPathLen(anchor, nonLeafDepth);
|
|
6744
|
+
this.checkAkiSkiMatch(current, anchor);
|
|
6745
|
+
this.spendSignatureCheck(search);
|
|
6746
|
+
await this.verifySignature(current, anchor);
|
|
6747
|
+
}
|
|
6748
|
+
/** Charge one signature verification to the search, or abandon it. */
|
|
6749
|
+
spendSignatureCheck(search) {
|
|
6750
|
+
if (search.remaining <= 0) {
|
|
6751
|
+
const limit = this.opts.maxSignatureChecks ?? DEFAULT_MAX_SIGNATURE_CHECKS;
|
|
6752
|
+
const err = new exports.CertificateChainError(
|
|
6753
|
+
`certificate path search exceeded ${limit} signature checks`,
|
|
6754
|
+
{ reason: "path_length" }
|
|
6671
6755
|
);
|
|
6756
|
+
searchAborts.add(err);
|
|
6757
|
+
throw err;
|
|
6672
6758
|
}
|
|
6673
|
-
|
|
6674
|
-
return chain;
|
|
6759
|
+
search.remaining--;
|
|
6675
6760
|
}
|
|
6676
6761
|
/**
|
|
6677
6762
|
* Enforce nameConstraints asserted by any CA above the leaf against the
|
|
@@ -6720,7 +6805,7 @@ var init_ChainBuilder = __esm({
|
|
|
6720
6805
|
}
|
|
6721
6806
|
}
|
|
6722
6807
|
checkCaAndPathLen(cert, nonLeafDepth) {
|
|
6723
|
-
this.checkCaKeyUsage(cert);
|
|
6808
|
+
this.checkCaKeyUsage(cert, this.opts.profile ?? "generic");
|
|
6724
6809
|
const bc = cert.getExtension(x509.BasicConstraintsExtension);
|
|
6725
6810
|
if (!bc || !bc.ca) {
|
|
6726
6811
|
throw new exports.CertificateChainError(
|
|
@@ -6735,9 +6820,17 @@ var init_ChainBuilder = __esm({
|
|
|
6735
6820
|
);
|
|
6736
6821
|
}
|
|
6737
6822
|
}
|
|
6738
|
-
checkLeafKeyUsage(leaf) {
|
|
6823
|
+
checkLeafKeyUsage(leaf, profile) {
|
|
6739
6824
|
const ext = leaf.getExtension(x509.KeyUsagesExtension);
|
|
6740
|
-
if (!ext)
|
|
6825
|
+
if (!ext) {
|
|
6826
|
+
if (profile === "iso18013-5") {
|
|
6827
|
+
throw new exports.CertificateChainError(
|
|
6828
|
+
`document signer ${leaf.subject} has no keyUsage extension (ISO 18013-5 requires digitalSignature)`,
|
|
6829
|
+
{ reason: "key_usage" }
|
|
6830
|
+
);
|
|
6831
|
+
}
|
|
6832
|
+
return;
|
|
6833
|
+
}
|
|
6741
6834
|
if ((ext.usages & x509.KeyUsageFlags.digitalSignature) === 0) {
|
|
6742
6835
|
throw new exports.CertificateChainError(
|
|
6743
6836
|
`leaf ${leaf.subject} does not assert digitalSignature key usage`,
|
|
@@ -6745,9 +6838,28 @@ var init_ChainBuilder = __esm({
|
|
|
6745
6838
|
);
|
|
6746
6839
|
}
|
|
6747
6840
|
}
|
|
6748
|
-
|
|
6841
|
+
checkLeafExtendedKeyUsage(leaf, profile) {
|
|
6842
|
+
if (profile !== "iso18013-5") return;
|
|
6843
|
+
const ext = leaf.getExtension(x509.ExtendedKeyUsageExtension);
|
|
6844
|
+
const usages = (ext?.usages ?? []).map(String);
|
|
6845
|
+
if (!usages.includes(ISO_18013_5_DS_EKU)) {
|
|
6846
|
+
throw new exports.CertificateChainError(
|
|
6847
|
+
`document signer ${leaf.subject} lacks extended key usage ${ISO_18013_5_DS_EKU} (id-mdl-kp-mdlDS)`,
|
|
6848
|
+
{ reason: "extended_key_usage" }
|
|
6849
|
+
);
|
|
6850
|
+
}
|
|
6851
|
+
}
|
|
6852
|
+
checkCaKeyUsage(cert, profile) {
|
|
6749
6853
|
const ext = cert.getExtension(x509.KeyUsagesExtension);
|
|
6750
|
-
if (!ext)
|
|
6854
|
+
if (!ext) {
|
|
6855
|
+
if (profile === "iso18013-5") {
|
|
6856
|
+
throw new exports.CertificateChainError(
|
|
6857
|
+
`CA ${cert.subject} has no keyUsage extension (ISO 18013-5 requires keyCertSign)`,
|
|
6858
|
+
{ reason: "key_usage" }
|
|
6859
|
+
);
|
|
6860
|
+
}
|
|
6861
|
+
return;
|
|
6862
|
+
}
|
|
6751
6863
|
if ((ext.usages & x509.KeyUsageFlags.keyCertSign) === 0) {
|
|
6752
6864
|
throw new exports.CertificateChainError(
|
|
6753
6865
|
`CA ${cert.subject} does not assert keyCertSign key usage`,
|
|
@@ -6768,30 +6880,46 @@ var init_ChainBuilder = __esm({
|
|
|
6768
6880
|
);
|
|
6769
6881
|
}
|
|
6770
6882
|
}
|
|
6883
|
+
/**
|
|
6884
|
+
* Signature check used to select among DN-matching candidates. Never throws
|
|
6885
|
+
* on a bad signature; throws only when the search budget is exhausted.
|
|
6886
|
+
*/
|
|
6887
|
+
async signatureVerifies(child, issuer, search) {
|
|
6888
|
+
this.spendSignatureCheck(search);
|
|
6889
|
+
try {
|
|
6890
|
+
return await child.verify({ publicKey: issuer.publicKey, signatureOnly: true });
|
|
6891
|
+
} catch {
|
|
6892
|
+
return false;
|
|
6893
|
+
}
|
|
6894
|
+
}
|
|
6771
6895
|
async verifySignature(child, issuer) {
|
|
6772
6896
|
const ok = await child.verify({ publicKey: issuer.publicKey, signatureOnly: true });
|
|
6773
6897
|
if (!ok) {
|
|
6774
6898
|
throw new exports.CertificateChainError(`signature verification failed for ${child.subject}`, { reason: "signature" });
|
|
6775
6899
|
}
|
|
6776
6900
|
}
|
|
6777
|
-
checkPerCert(cert) {
|
|
6778
|
-
this.
|
|
6901
|
+
checkPerCert(cert, context = {}) {
|
|
6902
|
+
const now = (this.opts.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
6903
|
+
this.checkValidity(cert, now, "");
|
|
6904
|
+
if (context.issuedAt) {
|
|
6905
|
+
this.checkValidity(cert, context.issuedAt, ` at issuance time ${context.issuedAt.toISOString()}`);
|
|
6906
|
+
}
|
|
6779
6907
|
this.checkAlgorithm(cert);
|
|
6780
6908
|
}
|
|
6781
|
-
checkValidity(cert) {
|
|
6782
|
-
const
|
|
6909
|
+
checkValidity(cert, at, label) {
|
|
6910
|
+
const time = at.getTime();
|
|
6783
6911
|
const skewMs = (this.opts.clockSkewTolerance ?? 60) * 1e3;
|
|
6784
6912
|
const notBefore = cert.notBefore.getTime();
|
|
6785
6913
|
const notAfter = cert.notAfter.getTime();
|
|
6786
|
-
if (
|
|
6914
|
+
if (time + skewMs < notBefore) {
|
|
6787
6915
|
throw new exports.CertificateChainError(
|
|
6788
|
-
`certificate ${cert.subject} not yet valid (notBefore=${cert.notBefore.toISOString()})`,
|
|
6916
|
+
`certificate ${cert.subject} not yet valid${label} (notBefore=${cert.notBefore.toISOString()})`,
|
|
6789
6917
|
{ reason: "validity" }
|
|
6790
6918
|
);
|
|
6791
6919
|
}
|
|
6792
|
-
if (
|
|
6920
|
+
if (time - skewMs > notAfter) {
|
|
6793
6921
|
throw new exports.CertificateChainError(
|
|
6794
|
-
`certificate ${cert.subject} expired (notAfter=${cert.notAfter.toISOString()})`,
|
|
6922
|
+
`certificate ${cert.subject} expired${label} (notAfter=${cert.notAfter.toISOString()})`,
|
|
6795
6923
|
{ reason: "validity" }
|
|
6796
6924
|
);
|
|
6797
6925
|
}
|
|
@@ -6838,6 +6966,349 @@ var init_ecdsa_util = __esm({
|
|
|
6838
6966
|
}
|
|
6839
6967
|
});
|
|
6840
6968
|
|
|
6969
|
+
// src/http/ip-address.ts
|
|
6970
|
+
function parseIPv4(input) {
|
|
6971
|
+
const parts = input.split(".");
|
|
6972
|
+
if (parts.length !== 4) return void 0;
|
|
6973
|
+
const bytes = [];
|
|
6974
|
+
for (const part of parts) {
|
|
6975
|
+
if (!/^\d{1,3}$/.test(part)) return void 0;
|
|
6976
|
+
const value = Number(part);
|
|
6977
|
+
if (value > 255) return void 0;
|
|
6978
|
+
bytes.push(value);
|
|
6979
|
+
}
|
|
6980
|
+
return bytes;
|
|
6981
|
+
}
|
|
6982
|
+
function parseIPv6(input) {
|
|
6983
|
+
const address = input.split("%")[0];
|
|
6984
|
+
if (!address.includes(":")) return void 0;
|
|
6985
|
+
let head = address;
|
|
6986
|
+
let embeddedV4;
|
|
6987
|
+
const lastColon = address.lastIndexOf(":");
|
|
6988
|
+
const tail = address.slice(lastColon + 1);
|
|
6989
|
+
if (tail.includes(".")) {
|
|
6990
|
+
embeddedV4 = parseIPv4(tail);
|
|
6991
|
+
if (!embeddedV4) return void 0;
|
|
6992
|
+
head = address.slice(0, lastColon + 1) + "0:0";
|
|
6993
|
+
}
|
|
6994
|
+
const doubleColon = head.split("::");
|
|
6995
|
+
if (doubleColon.length > 2) return void 0;
|
|
6996
|
+
const toGroups = (s) => s === "" ? [] : s.split(":");
|
|
6997
|
+
const left = toGroups(doubleColon[0]);
|
|
6998
|
+
const right = doubleColon.length === 2 ? toGroups(doubleColon[1]) : [];
|
|
6999
|
+
const missing = 8 - left.length - right.length;
|
|
7000
|
+
if (doubleColon.length === 2 ? missing < 1 : missing !== 0) return void 0;
|
|
7001
|
+
const groups = [...left, ...Array(doubleColon.length === 2 ? missing : 0).fill("0"), ...right];
|
|
7002
|
+
const bytes = [];
|
|
7003
|
+
for (const group of groups) {
|
|
7004
|
+
if (!/^[0-9a-fA-F]{1,4}$/.test(group)) return void 0;
|
|
7005
|
+
const value = parseInt(group, 16);
|
|
7006
|
+
bytes.push(value >> 8, value & 255);
|
|
7007
|
+
}
|
|
7008
|
+
if (embeddedV4) bytes.splice(12, 4, ...embeddedV4);
|
|
7009
|
+
return bytes;
|
|
7010
|
+
}
|
|
7011
|
+
function inPrefix(bytes, prefix, bits) {
|
|
7012
|
+
for (let i = 0; i < bits; i++) {
|
|
7013
|
+
const byte = i >> 3;
|
|
7014
|
+
const mask = 128 >> (i & 7);
|
|
7015
|
+
if ((bytes[byte] & mask) !== ((prefix[byte] ?? 0) & mask)) return false;
|
|
7016
|
+
}
|
|
7017
|
+
return true;
|
|
7018
|
+
}
|
|
7019
|
+
function isPublicV4(bytes) {
|
|
7020
|
+
return !BLOCKED_V4.some(([prefix, bits]) => inPrefix(bytes, prefix, bits));
|
|
7021
|
+
}
|
|
7022
|
+
function isPublicV6(bytes) {
|
|
7023
|
+
const first10Zero = bytes.slice(0, 10).every((b) => b === 0);
|
|
7024
|
+
if (first10Zero && bytes[10] === 0 && bytes[11] === 0) {
|
|
7025
|
+
const v4 = bytes.slice(12);
|
|
7026
|
+
if (v4.slice(0, 3).every((b) => b === 0)) return false;
|
|
7027
|
+
return isPublicV4(v4);
|
|
7028
|
+
}
|
|
7029
|
+
if (first10Zero && bytes[10] === 255 && bytes[11] === 255) return isPublicV4(bytes.slice(12));
|
|
7030
|
+
if (inPrefix(bytes, [0, 100, 255, 155], 96)) return isPublicV4(bytes.slice(12));
|
|
7031
|
+
if (inPrefix(bytes, [32, 2], 16)) return isPublicV4(bytes.slice(2, 6));
|
|
7032
|
+
return !BLOCKED_V6.some(([prefix, bits]) => inPrefix(bytes, prefix, bits));
|
|
7033
|
+
}
|
|
7034
|
+
function isPublicIpAddress(ip) {
|
|
7035
|
+
const v4 = parseIPv4(ip);
|
|
7036
|
+
if (v4) return isPublicV4(v4);
|
|
7037
|
+
const v6 = parseIPv6(ip);
|
|
7038
|
+
if (v6) return isPublicV6(v6);
|
|
7039
|
+
return false;
|
|
7040
|
+
}
|
|
7041
|
+
function isIpLiteral(host) {
|
|
7042
|
+
return parseIPv4(host) !== void 0 || parseIPv6(host) !== void 0;
|
|
7043
|
+
}
|
|
7044
|
+
var BLOCKED_V4, BLOCKED_V6;
|
|
7045
|
+
var init_ip_address = __esm({
|
|
7046
|
+
"src/http/ip-address.ts"() {
|
|
7047
|
+
init_reflect_polyfill();
|
|
7048
|
+
BLOCKED_V4 = [
|
|
7049
|
+
[[0, 0, 0, 0], 8],
|
|
7050
|
+
[[10, 0, 0, 0], 8],
|
|
7051
|
+
[[100, 64, 0, 0], 10],
|
|
7052
|
+
[[127, 0, 0, 0], 8],
|
|
7053
|
+
[[169, 254, 0, 0], 16],
|
|
7054
|
+
[[172, 16, 0, 0], 12],
|
|
7055
|
+
[[192, 0, 0, 0], 24],
|
|
7056
|
+
[[192, 0, 2, 0], 24],
|
|
7057
|
+
[[192, 88, 99, 0], 24],
|
|
7058
|
+
[[192, 168, 0, 0], 16],
|
|
7059
|
+
[[198, 18, 0, 0], 15],
|
|
7060
|
+
[[198, 51, 100, 0], 24],
|
|
7061
|
+
[[203, 0, 113, 0], 24],
|
|
7062
|
+
[[224, 0, 0, 0], 4],
|
|
7063
|
+
[[240, 0, 0, 0], 4]
|
|
7064
|
+
];
|
|
7065
|
+
BLOCKED_V6 = [
|
|
7066
|
+
[[1, 0], 64],
|
|
7067
|
+
// 100::/64 discard-only
|
|
7068
|
+
[[32, 1, 0, 0], 32],
|
|
7069
|
+
// 2001::/32 Teredo (embeds an obfuscated IPv4)
|
|
7070
|
+
[[32, 1, 13, 184], 32],
|
|
7071
|
+
// 2001:db8::/32 documentation
|
|
7072
|
+
[[252], 7],
|
|
7073
|
+
// fc00::/7 unique local (incl. fd00:ec2::254 metadata)
|
|
7074
|
+
[[254, 128], 10],
|
|
7075
|
+
// fe80::/10 link-local
|
|
7076
|
+
[[254, 192], 10],
|
|
7077
|
+
// fec0::/10 deprecated site-local
|
|
7078
|
+
[[255], 8]
|
|
7079
|
+
// ff00::/8 multicast
|
|
7080
|
+
];
|
|
7081
|
+
}
|
|
7082
|
+
});
|
|
7083
|
+
|
|
7084
|
+
// src/http/guarded-fetch.ts
|
|
7085
|
+
function loadDns() {
|
|
7086
|
+
dnsModule ??= (async () => {
|
|
7087
|
+
try {
|
|
7088
|
+
const specifier = "node:dns";
|
|
7089
|
+
const mod = await import(
|
|
7090
|
+
/* webpackIgnore: true */
|
|
7091
|
+
/* @vite-ignore */
|
|
7092
|
+
specifier
|
|
7093
|
+
);
|
|
7094
|
+
return mod.promises ?? mod.default?.promises;
|
|
7095
|
+
} catch {
|
|
7096
|
+
return void 0;
|
|
7097
|
+
}
|
|
7098
|
+
})();
|
|
7099
|
+
return dnsModule;
|
|
7100
|
+
}
|
|
7101
|
+
function toError(err) {
|
|
7102
|
+
return err instanceof Error ? err : new Error(String(err));
|
|
7103
|
+
}
|
|
7104
|
+
function createGuardedFetcher(options = {}) {
|
|
7105
|
+
const allowHttp = options.allowHttp ?? false;
|
|
7106
|
+
const allowPrivate = options.allowPrivateNetworks ?? false;
|
|
7107
|
+
const maxRedirects = options.maxRedirects ?? exports.GUARDED_FETCH_DEFAULTS.maxRedirects;
|
|
7108
|
+
const timeoutMs = options.timeoutMs ?? exports.GUARDED_FETCH_DEFAULTS.timeoutMs;
|
|
7109
|
+
const maxBytes = options.maxResponseBytes ?? exports.GUARDED_FETCH_DEFAULTS.maxResponseBytes;
|
|
7110
|
+
const lookup = options.lookup ?? defaultLookup;
|
|
7111
|
+
const transport = options.fetch ?? ((url, init) => globalThis.fetch(url, init));
|
|
7112
|
+
return async (input, init = {}) => {
|
|
7113
|
+
const controller = new AbortController();
|
|
7114
|
+
const timer = setTimeout(() => {
|
|
7115
|
+
controller.abort(
|
|
7116
|
+
new exports.GuardedFetchError("timeout", `request to ${input} exceeded ${timeoutMs} ms`, { url: input })
|
|
7117
|
+
);
|
|
7118
|
+
}, timeoutMs);
|
|
7119
|
+
const callerSignal = init.signal ?? void 0;
|
|
7120
|
+
const onCallerAbort = () => controller.abort(callerSignal?.reason);
|
|
7121
|
+
if (callerSignal?.aborted) onCallerAbort();
|
|
7122
|
+
else callerSignal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
7123
|
+
const aborted = new Promise((_, reject) => {
|
|
7124
|
+
const fail = () => reject(toError(controller.signal.reason));
|
|
7125
|
+
if (controller.signal.aborted) fail();
|
|
7126
|
+
else controller.signal.addEventListener("abort", fail, { once: true });
|
|
7127
|
+
});
|
|
7128
|
+
aborted.catch(() => {
|
|
7129
|
+
});
|
|
7130
|
+
const race = (p) => Promise.race([p, aborted]);
|
|
7131
|
+
try {
|
|
7132
|
+
let url = await race(validateTarget(input, void 0));
|
|
7133
|
+
let method = (init.method ?? "GET").toUpperCase();
|
|
7134
|
+
let body = init.body;
|
|
7135
|
+
const headers = new Headers(init.headers);
|
|
7136
|
+
for (let hop = 0; ; hop++) {
|
|
7137
|
+
const response = await race(
|
|
7138
|
+
transport(url.href, { ...init, method, body, headers, redirect: "manual", signal: controller.signal })
|
|
7139
|
+
);
|
|
7140
|
+
if (response.type === "opaqueredirect") {
|
|
7141
|
+
throw new exports.GuardedFetchError(
|
|
7142
|
+
"invalid_redirect",
|
|
7143
|
+
`redirect from ${url.href} cannot be inspected by this transport`,
|
|
7144
|
+
{ url: url.href }
|
|
7145
|
+
);
|
|
7146
|
+
}
|
|
7147
|
+
if (!REDIRECT_STATUSES.has(response.status)) {
|
|
7148
|
+
const bytes = await readBounded(response, url.href, maxBytes, race);
|
|
7149
|
+
return new Response(NULL_BODY_STATUSES.has(response.status) ? null : bytes, {
|
|
7150
|
+
status: response.status,
|
|
7151
|
+
statusText: response.statusText,
|
|
7152
|
+
headers: response.headers
|
|
7153
|
+
});
|
|
7154
|
+
}
|
|
7155
|
+
await response.body?.cancel().catch(() => {
|
|
7156
|
+
});
|
|
7157
|
+
if (hop >= maxRedirects) {
|
|
7158
|
+
throw new exports.GuardedFetchError(
|
|
7159
|
+
"too_many_redirects",
|
|
7160
|
+
`more than ${maxRedirects} redirects starting at ${input}`,
|
|
7161
|
+
{ url: url.href }
|
|
7162
|
+
);
|
|
7163
|
+
}
|
|
7164
|
+
const location = response.headers.get("location");
|
|
7165
|
+
if (!location) {
|
|
7166
|
+
throw new exports.GuardedFetchError(
|
|
7167
|
+
"invalid_redirect",
|
|
7168
|
+
`HTTP ${response.status} from ${url.href} has no Location header`,
|
|
7169
|
+
{ url: url.href }
|
|
7170
|
+
);
|
|
7171
|
+
}
|
|
7172
|
+
let next;
|
|
7173
|
+
try {
|
|
7174
|
+
next = new URL(location, url);
|
|
7175
|
+
} catch (err) {
|
|
7176
|
+
throw new exports.GuardedFetchError("invalid_redirect", `unparseable Location from ${url.href}`, {
|
|
7177
|
+
url: url.href,
|
|
7178
|
+
cause: toError(err)
|
|
7179
|
+
});
|
|
7180
|
+
}
|
|
7181
|
+
const nextUrl = await race(validateTarget(next.href, url));
|
|
7182
|
+
if (response.status === 303 || (response.status === 301 || response.status === 302) && method === "POST") {
|
|
7183
|
+
if (method !== "HEAD") method = "GET";
|
|
7184
|
+
body = void 0;
|
|
7185
|
+
for (const h of BODY_HEADERS) headers.delete(h);
|
|
7186
|
+
}
|
|
7187
|
+
if (nextUrl.origin !== url.origin) {
|
|
7188
|
+
for (const h of CROSS_ORIGIN_STRIPPED_HEADERS) headers.delete(h);
|
|
7189
|
+
}
|
|
7190
|
+
url = nextUrl;
|
|
7191
|
+
}
|
|
7192
|
+
} catch (err) {
|
|
7193
|
+
if (controller.signal.aborted) throw toError(controller.signal.reason);
|
|
7194
|
+
throw err;
|
|
7195
|
+
} finally {
|
|
7196
|
+
clearTimeout(timer);
|
|
7197
|
+
callerSignal?.removeEventListener("abort", onCallerAbort);
|
|
7198
|
+
}
|
|
7199
|
+
};
|
|
7200
|
+
async function validateTarget(raw, previous) {
|
|
7201
|
+
let url;
|
|
7202
|
+
try {
|
|
7203
|
+
url = new URL(raw);
|
|
7204
|
+
} catch (err) {
|
|
7205
|
+
throw new exports.GuardedFetchError("invalid_url", `not an absolute URL: ${raw}`, { url: raw, cause: toError(err) });
|
|
7206
|
+
}
|
|
7207
|
+
if (url.protocol !== "https:" && !(allowHttp && url.protocol === "http:")) {
|
|
7208
|
+
throw new exports.GuardedFetchError("insecure_scheme", `refusing ${url.protocol} URL ${url.href}: HTTPS is required`, {
|
|
7209
|
+
url: url.href
|
|
7210
|
+
});
|
|
7211
|
+
}
|
|
7212
|
+
if (previous?.protocol === "https:" && url.protocol !== "https:") {
|
|
7213
|
+
throw new exports.GuardedFetchError("insecure_scheme", `refusing https -> http redirect to ${url.href}`, {
|
|
7214
|
+
url: url.href
|
|
7215
|
+
});
|
|
7216
|
+
}
|
|
7217
|
+
if (allowPrivate) return url;
|
|
7218
|
+
const host = url.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
7219
|
+
if (host === "localhost" || host.endsWith(".localhost")) {
|
|
7220
|
+
throw new exports.GuardedFetchError("private_address", `refusing loopback host ${host}`, { url: url.href });
|
|
7221
|
+
}
|
|
7222
|
+
if (isIpLiteral(host)) {
|
|
7223
|
+
if (!isPublicIpAddress(host)) {
|
|
7224
|
+
throw new exports.GuardedFetchError("private_address", `refusing non-public address ${host}`, { url: url.href });
|
|
7225
|
+
}
|
|
7226
|
+
return url;
|
|
7227
|
+
}
|
|
7228
|
+
let addresses;
|
|
7229
|
+
try {
|
|
7230
|
+
addresses = await lookup(host);
|
|
7231
|
+
} catch (err) {
|
|
7232
|
+
throw new exports.GuardedFetchError("dns_resolution_failed", `could not resolve ${host}`, {
|
|
7233
|
+
url: url.href,
|
|
7234
|
+
cause: toError(err)
|
|
7235
|
+
});
|
|
7236
|
+
}
|
|
7237
|
+
if (addresses === void 0) return url;
|
|
7238
|
+
if (addresses.length === 0) {
|
|
7239
|
+
throw new exports.GuardedFetchError("dns_resolution_failed", `${host} resolved to no addresses`, {
|
|
7240
|
+
url: url.href
|
|
7241
|
+
});
|
|
7242
|
+
}
|
|
7243
|
+
const blocked = addresses.find((a) => !isPublicIpAddress(a));
|
|
7244
|
+
if (blocked !== void 0) {
|
|
7245
|
+
throw new exports.GuardedFetchError("private_address", `${host} resolves to non-public address ${blocked}`, {
|
|
7246
|
+
url: url.href
|
|
7247
|
+
});
|
|
7248
|
+
}
|
|
7249
|
+
return url;
|
|
7250
|
+
}
|
|
7251
|
+
}
|
|
7252
|
+
async function readBounded(response, url, maxBytes, race) {
|
|
7253
|
+
const tooLarge = () => new exports.GuardedFetchError("response_too_large", `response from ${url} exceeds ${maxBytes} bytes`, { url });
|
|
7254
|
+
const declared = response.headers.get("content-length");
|
|
7255
|
+
if (declared !== null && Number(declared) > maxBytes) {
|
|
7256
|
+
await response.body?.cancel().catch(() => {
|
|
7257
|
+
});
|
|
7258
|
+
throw tooLarge();
|
|
7259
|
+
}
|
|
7260
|
+
if (!response.body) return null;
|
|
7261
|
+
const reader = response.body.getReader();
|
|
7262
|
+
const chunks = [];
|
|
7263
|
+
let total = 0;
|
|
7264
|
+
try {
|
|
7265
|
+
for (; ; ) {
|
|
7266
|
+
const { done, value } = await race(reader.read());
|
|
7267
|
+
if (done) break;
|
|
7268
|
+
total += value.byteLength;
|
|
7269
|
+
if (total > maxBytes) throw tooLarge();
|
|
7270
|
+
chunks.push(value);
|
|
7271
|
+
}
|
|
7272
|
+
} catch (err) {
|
|
7273
|
+
reader.cancel().catch(() => {
|
|
7274
|
+
});
|
|
7275
|
+
throw err;
|
|
7276
|
+
}
|
|
7277
|
+
const out = new Uint8Array(new ArrayBuffer(total));
|
|
7278
|
+
let offset = 0;
|
|
7279
|
+
for (const chunk of chunks) {
|
|
7280
|
+
out.set(chunk, offset);
|
|
7281
|
+
offset += chunk.byteLength;
|
|
7282
|
+
}
|
|
7283
|
+
return out;
|
|
7284
|
+
}
|
|
7285
|
+
function createDefaultTrustFetcher() {
|
|
7286
|
+
return createGuardedFetcher({ allowHttp: true });
|
|
7287
|
+
}
|
|
7288
|
+
exports.GUARDED_FETCH_DEFAULTS = void 0; var REDIRECT_STATUSES, NULL_BODY_STATUSES, CROSS_ORIGIN_STRIPPED_HEADERS, BODY_HEADERS, dnsModule, defaultLookup;
|
|
7289
|
+
var init_guarded_fetch = __esm({
|
|
7290
|
+
"src/http/guarded-fetch.ts"() {
|
|
7291
|
+
init_reflect_polyfill();
|
|
7292
|
+
init_errors();
|
|
7293
|
+
init_ip_address();
|
|
7294
|
+
exports.GUARDED_FETCH_DEFAULTS = {
|
|
7295
|
+
maxRedirects: 3,
|
|
7296
|
+
timeoutMs: 15e3,
|
|
7297
|
+
maxResponseBytes: 16 * 1024 * 1024
|
|
7298
|
+
};
|
|
7299
|
+
REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
7300
|
+
NULL_BODY_STATUSES = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
|
|
7301
|
+
CROSS_ORIGIN_STRIPPED_HEADERS = ["authorization", "cookie", "proxy-authorization"];
|
|
7302
|
+
BODY_HEADERS = ["content-type", "content-length", "content-encoding", "content-language", "content-location"];
|
|
7303
|
+
defaultLookup = async (hostname) => {
|
|
7304
|
+
const dns = await loadDns();
|
|
7305
|
+
if (!dns) return void 0;
|
|
7306
|
+
const records = await dns.lookup(hostname, { all: true, verbatim: true });
|
|
7307
|
+
return records.map((r) => r.address);
|
|
7308
|
+
};
|
|
7309
|
+
}
|
|
7310
|
+
});
|
|
7311
|
+
|
|
6841
7312
|
// src/trust/CrlFetcher.ts
|
|
6842
7313
|
function normalizeCrl(parsed, der) {
|
|
6843
7314
|
const thisUpdate = parsed.tbsCertList.thisUpdate.getTime();
|
|
@@ -6873,11 +7344,12 @@ var init_CrlFetcher = __esm({
|
|
|
6873
7344
|
init_es2015();
|
|
6874
7345
|
init_es20152();
|
|
6875
7346
|
init_ecdsa_util();
|
|
7347
|
+
init_guarded_fetch();
|
|
6876
7348
|
CrlFetcher = class {
|
|
6877
7349
|
fetcher;
|
|
6878
7350
|
cache;
|
|
6879
7351
|
constructor(opts = {}) {
|
|
6880
|
-
this.fetcher = opts.fetcher ??
|
|
7352
|
+
this.fetcher = opts.fetcher ?? createDefaultTrustFetcher();
|
|
6881
7353
|
this.cache = opts.cache;
|
|
6882
7354
|
}
|
|
6883
7355
|
async fetchAndParse(url) {
|
|
@@ -7609,12 +8081,13 @@ var init_OcspClient = __esm({
|
|
|
7609
8081
|
init_es20152();
|
|
7610
8082
|
init_ChainBuilder();
|
|
7611
8083
|
init_ecdsa_util();
|
|
8084
|
+
init_guarded_fetch();
|
|
7612
8085
|
DEFAULT_MAX_RESPONSE_AGE_MS = 7 * 24 * 3600 * 1e3;
|
|
7613
8086
|
OcspClient = class {
|
|
7614
8087
|
fetcher;
|
|
7615
8088
|
cache;
|
|
7616
8089
|
constructor(opts = {}) {
|
|
7617
|
-
this.fetcher = opts.fetcher ??
|
|
8090
|
+
this.fetcher = opts.fetcher ?? createDefaultTrustFetcher();
|
|
7618
8091
|
this.cache = opts.cache;
|
|
7619
8092
|
}
|
|
7620
8093
|
/**
|
|
@@ -8080,7 +8553,9 @@ var init_ProvenanceResolver = __esm({
|
|
|
8080
8553
|
// src/trust/TrustEvaluator.ts
|
|
8081
8554
|
var TrustEvaluator_exports = {};
|
|
8082
8555
|
__export(TrustEvaluator_exports, {
|
|
8083
|
-
|
|
8556
|
+
MAX_CREDENTIAL_CERTIFICATES: () => MAX_CREDENTIAL_CERTIFICATES,
|
|
8557
|
+
TrustEvaluator: () => TrustEvaluator,
|
|
8558
|
+
evaluateCredentialIssuer: () => evaluateCredentialIssuer
|
|
8084
8559
|
});
|
|
8085
8560
|
function deriveHint(leaf) {
|
|
8086
8561
|
const aki = leaf.getExtension(x509.AuthorityKeyIdentifierExtension);
|
|
@@ -8091,6 +8566,13 @@ function deriveHint(leaf) {
|
|
|
8091
8566
|
aki: akiBytes
|
|
8092
8567
|
};
|
|
8093
8568
|
}
|
|
8569
|
+
function deriveSelfHint(cert) {
|
|
8570
|
+
const skiHex = getSkiHex(cert);
|
|
8571
|
+
return {
|
|
8572
|
+
issuer: cert.subject,
|
|
8573
|
+
aki: skiHex ? hexToBytes(skiHex) : void 0
|
|
8574
|
+
};
|
|
8575
|
+
}
|
|
8094
8576
|
function hexToBytes(s) {
|
|
8095
8577
|
const clean = s.replace(/[^0-9a-f]/gi, "");
|
|
8096
8578
|
const out = new Uint8Array(clean.length / 2);
|
|
@@ -8122,7 +8604,31 @@ async function resolveProvenance(store, anchor) {
|
|
|
8122
8604
|
return void 0;
|
|
8123
8605
|
}
|
|
8124
8606
|
}
|
|
8125
|
-
|
|
8607
|
+
async function evaluateCredentialIssuer(input) {
|
|
8608
|
+
const [signerDer, ...rest] = input.chain;
|
|
8609
|
+
if (!signerDer) {
|
|
8610
|
+
throw new exports.MalformedCredentialError("Missing issuer certificate");
|
|
8611
|
+
}
|
|
8612
|
+
if (input.chain.length > MAX_CREDENTIAL_CERTIFICATES) {
|
|
8613
|
+
throw new exports.MalformedCredentialError(
|
|
8614
|
+
`x5c/x5chain carries ${input.chain.length} certificates; at most ${MAX_CREDENTIAL_CERTIFICATES} are accepted`
|
|
8615
|
+
);
|
|
8616
|
+
}
|
|
8617
|
+
const parse = (bytes, position) => {
|
|
8618
|
+
try {
|
|
8619
|
+
return new x509.X509Certificate(bytes);
|
|
8620
|
+
} catch (err) {
|
|
8621
|
+
throw new exports.MalformedCredentialError(
|
|
8622
|
+
`Invalid certificate at x5c/x5chain position ${position}: ${err.message}`
|
|
8623
|
+
);
|
|
8624
|
+
}
|
|
8625
|
+
};
|
|
8626
|
+
const leaf = parse(signerDer, 0);
|
|
8627
|
+
const intermediates = rest.map((bytes, i) => parse(bytes, i + 1));
|
|
8628
|
+
const { chain, issuedAt, ...evaluatorOptions } = input;
|
|
8629
|
+
return new TrustEvaluator(evaluatorOptions).evaluate(leaf, { intermediates, issuedAt });
|
|
8630
|
+
}
|
|
8631
|
+
var TrustEvaluator, MAX_CREDENTIAL_CERTIFICATES;
|
|
8126
8632
|
var init_TrustEvaluator = __esm({
|
|
8127
8633
|
"src/trust/TrustEvaluator.ts"() {
|
|
8128
8634
|
init_reflect_polyfill();
|
|
@@ -8148,13 +8654,10 @@ var init_TrustEvaluator = __esm({
|
|
|
8148
8654
|
revocationChecker;
|
|
8149
8655
|
async evaluate(leaf, context = {}) {
|
|
8150
8656
|
const hint = deriveHint(leaf);
|
|
8151
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8152
8657
|
const anchors = [];
|
|
8153
8658
|
const pushUnique = (batch) => {
|
|
8154
8659
|
for (const a of batch) {
|
|
8155
|
-
|
|
8156
|
-
if (seen.has(key)) continue;
|
|
8157
|
-
seen.add(key);
|
|
8660
|
+
if (anchors.some((x) => certificatesEqual(x.certificate, a.certificate))) continue;
|
|
8158
8661
|
anchors.push(a);
|
|
8159
8662
|
}
|
|
8160
8663
|
};
|
|
@@ -8162,6 +8665,7 @@ var init_TrustEvaluator = __esm({
|
|
|
8162
8665
|
for (const inter of context.intermediates ?? []) {
|
|
8163
8666
|
pushUnique(await this.trustStore.getAnchors(deriveHint(inter)));
|
|
8164
8667
|
}
|
|
8668
|
+
pushUnique(await this.trustStore.getAnchors(deriveSelfHint(leaf)));
|
|
8165
8669
|
if (anchors.length === 0) {
|
|
8166
8670
|
throw new exports.TrustAnchorNotFoundError(
|
|
8167
8671
|
`no trust anchor for issuer=${hint.issuer ?? "(none)"}`
|
|
@@ -8171,7 +8675,8 @@ var init_TrustEvaluator = __esm({
|
|
|
8171
8675
|
const chain = await this.chainBuilder.build(
|
|
8172
8676
|
leaf,
|
|
8173
8677
|
anchorCerts,
|
|
8174
|
-
context.intermediates ?? []
|
|
8678
|
+
context.intermediates ?? [],
|
|
8679
|
+
{ issuedAt: context.issuedAt }
|
|
8175
8680
|
);
|
|
8176
8681
|
const terminusCert = chain[chain.length - 1];
|
|
8177
8682
|
const anchor = anchors.find(
|
|
@@ -8211,6 +8716,7 @@ var init_TrustEvaluator = __esm({
|
|
|
8211
8716
|
};
|
|
8212
8717
|
}
|
|
8213
8718
|
};
|
|
8719
|
+
MAX_CREDENTIAL_CERTIFICATES = 10;
|
|
8214
8720
|
}
|
|
8215
8721
|
});
|
|
8216
8722
|
|
|
@@ -8443,6 +8949,33 @@ function buildHaipQuery(input) {
|
|
|
8443
8949
|
}
|
|
8444
8950
|
return { credentials: [credential] };
|
|
8445
8951
|
}
|
|
8952
|
+
function buildCredentialSetQuery(input) {
|
|
8953
|
+
if (input.options.length === 0) {
|
|
8954
|
+
throw new exports.HaipValidationError(
|
|
8955
|
+
"EMPTY_OPTIONS",
|
|
8956
|
+
"a credential set must offer at least one option"
|
|
8957
|
+
);
|
|
8958
|
+
}
|
|
8959
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8960
|
+
for (const option of input.options) {
|
|
8961
|
+
if (seen.has(option.credentialId)) {
|
|
8962
|
+
throw new exports.HaipValidationError(
|
|
8963
|
+
"DUPLICATE_CREDENTIAL_ID",
|
|
8964
|
+
`credential '${option.credentialId}' is declared by more than one option; credential ids must be unique for credential_sets to reference them`,
|
|
8965
|
+
option.credentialId
|
|
8966
|
+
);
|
|
8967
|
+
}
|
|
8968
|
+
seen.add(option.credentialId);
|
|
8969
|
+
}
|
|
8970
|
+
const credentials = input.options.map((option) => buildHaipQuery(option).credentials[0]);
|
|
8971
|
+
const credentialSet = {
|
|
8972
|
+
options: input.options.map((option) => [option.credentialId])
|
|
8973
|
+
};
|
|
8974
|
+
if (input.required === false) {
|
|
8975
|
+
credentialSet.required = false;
|
|
8976
|
+
}
|
|
8977
|
+
return { credentials, credential_sets: [credentialSet] };
|
|
8978
|
+
}
|
|
8446
8979
|
var HAIP_FORMATS = /* @__PURE__ */ new Set(["dc+sd-jwt", "mso_mdoc"]);
|
|
8447
8980
|
function validateHaipQuery(query) {
|
|
8448
8981
|
if (!query.credentials || query.credentials.length === 0) {
|
|
@@ -8458,46 +8991,86 @@ function validateHaipQuery(query) {
|
|
|
8458
8991
|
);
|
|
8459
8992
|
}
|
|
8460
8993
|
for (const credential of query.credentials) {
|
|
8461
|
-
|
|
8994
|
+
validateCredential(credential);
|
|
8995
|
+
}
|
|
8996
|
+
}
|
|
8997
|
+
function validateCredential(credential) {
|
|
8998
|
+
if (!HAIP_FORMATS.has(credential.format)) {
|
|
8999
|
+
throw new exports.HaipValidationError(
|
|
9000
|
+
"UNSUPPORTED_FORMAT",
|
|
9001
|
+
`credential '${credential.id}' uses unsupported format '${credential.format}' (allowed: dc+sd-jwt, mso_mdoc)`,
|
|
9002
|
+
credential.id
|
|
9003
|
+
);
|
|
9004
|
+
}
|
|
9005
|
+
if (credential.format === "dc+sd-jwt") {
|
|
9006
|
+
const vctValues = credential.meta?.vct_values;
|
|
9007
|
+
if (!vctValues || vctValues.length === 0) {
|
|
8462
9008
|
throw new exports.HaipValidationError(
|
|
8463
|
-
"
|
|
8464
|
-
`credential '${credential.id}'
|
|
9009
|
+
"MISSING_SDJWT_META",
|
|
9010
|
+
`credential '${credential.id}' with format 'dc+sd-jwt' must set meta.vct_values`,
|
|
8465
9011
|
credential.id
|
|
8466
9012
|
);
|
|
8467
9013
|
}
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
throw new exports.HaipValidationError(
|
|
8472
|
-
"MISSING_SDJWT_META",
|
|
8473
|
-
`credential '${credential.id}' with format 'dc+sd-jwt' must set meta.vct_values`,
|
|
8474
|
-
credential.id
|
|
8475
|
-
);
|
|
8476
|
-
}
|
|
8477
|
-
}
|
|
8478
|
-
if (credential.format === "mso_mdoc") {
|
|
8479
|
-
if (typeof credential.meta?.doctype_value !== "string") {
|
|
8480
|
-
throw new exports.HaipValidationError(
|
|
8481
|
-
"MISSING_MDOC_META",
|
|
8482
|
-
`credential '${credential.id}' with format 'mso_mdoc' must set meta.doctype_value`,
|
|
8483
|
-
credential.id
|
|
8484
|
-
);
|
|
8485
|
-
}
|
|
8486
|
-
}
|
|
8487
|
-
if (!credential.claims || credential.claims.length === 0) {
|
|
9014
|
+
}
|
|
9015
|
+
if (credential.format === "mso_mdoc") {
|
|
9016
|
+
if (typeof credential.meta?.doctype_value !== "string") {
|
|
8488
9017
|
throw new exports.HaipValidationError(
|
|
8489
|
-
"
|
|
8490
|
-
`credential '${credential.id}'
|
|
9018
|
+
"MISSING_MDOC_META",
|
|
9019
|
+
`credential '${credential.id}' with format 'mso_mdoc' must set meta.doctype_value`,
|
|
8491
9020
|
credential.id
|
|
8492
9021
|
);
|
|
8493
9022
|
}
|
|
8494
|
-
|
|
9023
|
+
}
|
|
9024
|
+
if (!credential.claims || credential.claims.length === 0) {
|
|
9025
|
+
throw new exports.HaipValidationError(
|
|
9026
|
+
"NO_CLAIMS",
|
|
9027
|
+
`credential '${credential.id}' must declare at least one claim`,
|
|
9028
|
+
credential.id
|
|
9029
|
+
);
|
|
9030
|
+
}
|
|
9031
|
+
if (credential.claim_sets !== void 0) {
|
|
9032
|
+
throw new exports.HaipValidationError(
|
|
9033
|
+
"CLAIM_SETS_DISALLOWED",
|
|
9034
|
+
`credential '${credential.id}' uses claim_sets, not permitted in HAIP-minimal`,
|
|
9035
|
+
credential.id
|
|
9036
|
+
);
|
|
9037
|
+
}
|
|
9038
|
+
}
|
|
9039
|
+
function validateCredentialSetQuery(query) {
|
|
9040
|
+
if (!query.credentials || query.credentials.length === 0) {
|
|
9041
|
+
throw new exports.HaipValidationError(
|
|
9042
|
+
"EMPTY_QUERY",
|
|
9043
|
+
"query.credentials must have at least one entry"
|
|
9044
|
+
);
|
|
9045
|
+
}
|
|
9046
|
+
if (!query.credential_sets || query.credential_sets.length === 0) {
|
|
9047
|
+
throw new exports.HaipValidationError(
|
|
9048
|
+
"MISSING_CREDENTIAL_SETS",
|
|
9049
|
+
"a credential-set query must declare at least one credential_sets entry"
|
|
9050
|
+
);
|
|
9051
|
+
}
|
|
9052
|
+
for (const credential of query.credentials) {
|
|
9053
|
+
validateCredential(credential);
|
|
9054
|
+
}
|
|
9055
|
+
const declaredIds = new Set(query.credentials.map((c) => c.id));
|
|
9056
|
+
for (const credentialSet of query.credential_sets) {
|
|
9057
|
+
if (!credentialSet.options || credentialSet.options.length === 0) {
|
|
8495
9058
|
throw new exports.HaipValidationError(
|
|
8496
|
-
"
|
|
8497
|
-
|
|
8498
|
-
credential.id
|
|
9059
|
+
"EMPTY_OPTIONS",
|
|
9060
|
+
"a credential set must offer at least one option"
|
|
8499
9061
|
);
|
|
8500
9062
|
}
|
|
9063
|
+
for (const option of credentialSet.options) {
|
|
9064
|
+
for (const id of option) {
|
|
9065
|
+
if (!declaredIds.has(id)) {
|
|
9066
|
+
throw new exports.HaipValidationError(
|
|
9067
|
+
"UNKNOWN_OPTION_REFERENCE",
|
|
9068
|
+
`credential_sets option references '${id}', which is not declared in query.credentials`,
|
|
9069
|
+
id
|
|
9070
|
+
);
|
|
9071
|
+
}
|
|
9072
|
+
}
|
|
9073
|
+
}
|
|
8501
9074
|
}
|
|
8502
9075
|
}
|
|
8503
9076
|
function isHaipQuery(query) {
|
|
@@ -8935,6 +9508,14 @@ function bytesEqual3(a, b) {
|
|
|
8935
9508
|
}
|
|
8936
9509
|
return true;
|
|
8937
9510
|
}
|
|
9511
|
+
function peekMsoSigned(payload) {
|
|
9512
|
+
try {
|
|
9513
|
+
const signed = decodeMso(payload).validityInfo.signed;
|
|
9514
|
+
return Number.isFinite(signed.getTime()) ? signed : void 0;
|
|
9515
|
+
} catch {
|
|
9516
|
+
return void 0;
|
|
9517
|
+
}
|
|
9518
|
+
}
|
|
8938
9519
|
function derToPem(der) {
|
|
8939
9520
|
let binary = "";
|
|
8940
9521
|
for (const b of der) binary += String.fromCharCode(b);
|
|
@@ -9095,17 +9676,17 @@ var MdocParser = class {
|
|
|
9095
9676
|
}
|
|
9096
9677
|
let trustResult;
|
|
9097
9678
|
if (options.trustStore) {
|
|
9098
|
-
const {
|
|
9099
|
-
|
|
9679
|
+
const { evaluateCredentialIssuer: evaluateCredentialIssuer2 } = await Promise.resolve().then(() => (init_TrustEvaluator(), TrustEvaluator_exports));
|
|
9680
|
+
trustResult = await evaluateCredentialIssuer2({
|
|
9681
|
+
chain: cose.x5chain,
|
|
9682
|
+
profile: "iso18013-5",
|
|
9683
|
+
issuedAt: peekMsoSigned(cose.payload),
|
|
9100
9684
|
trustStore: options.trustStore,
|
|
9101
9685
|
revocationPolicy: options.revocationPolicy ?? "skip",
|
|
9102
9686
|
fetcher: options.fetcher,
|
|
9103
9687
|
cache: options.cache,
|
|
9104
9688
|
clockSkewTolerance: options.clockSkewTolerance
|
|
9105
9689
|
});
|
|
9106
|
-
const { X509Certificate: X509Certificate9 } = await import('@peculiar/x509');
|
|
9107
|
-
const leaf = new X509Certificate9(issuerCertBytes);
|
|
9108
|
-
trustResult = await evaluator.evaluate(leaf);
|
|
9109
9690
|
} else {
|
|
9110
9691
|
if (options.trustedCertificates.length === 0) {
|
|
9111
9692
|
if (options.skipTrustCheck !== true) {
|
|
@@ -9254,6 +9835,13 @@ var MdocParser = class {
|
|
|
9254
9835
|
init_reflect_polyfill();
|
|
9255
9836
|
init_errors();
|
|
9256
9837
|
var DEFAULT_ALLOWED_ALGORITHMS2 = ["ES256", "ES384", "ES512"];
|
|
9838
|
+
var SD_JWT_VC_TYP = "dc+sd-jwt";
|
|
9839
|
+
var LEGACY_SD_JWT_VC_TYP = "vc+sd-jwt";
|
|
9840
|
+
function normalizeTyp(typ) {
|
|
9841
|
+
if (typeof typ !== "string") return void 0;
|
|
9842
|
+
const lower = typ.toLowerCase();
|
|
9843
|
+
return lower.startsWith("application/") ? lower.slice("application/".length) : lower;
|
|
9844
|
+
}
|
|
9257
9845
|
var sha256Hasher = async (data, _alg) => {
|
|
9258
9846
|
const encoder2 = new TextEncoder();
|
|
9259
9847
|
const input = typeof data === "string" ? encoder2.encode(data) : data;
|
|
@@ -9366,6 +9954,18 @@ var SdJwtParser = class {
|
|
|
9366
9954
|
if (typeof alg !== "string" || !allowedAlgorithms.includes(alg)) {
|
|
9367
9955
|
return invalidResult(`Unsupported algorithm: ${alg}`);
|
|
9368
9956
|
}
|
|
9957
|
+
const typ = normalizeTyp(header.typ);
|
|
9958
|
+
if (typ === LEGACY_SD_JWT_VC_TYP) {
|
|
9959
|
+
if (options.allowLegacyVcSdJwtTyp !== true) {
|
|
9960
|
+
return invalidResult(
|
|
9961
|
+
`Legacy SD-JWT VC typ '${LEGACY_SD_JWT_VC_TYP}' is not accepted (removed in draft-ietf-oauth-sd-jwt-vc-19; expected '${SD_JWT_VC_TYP}'). Set allowLegacyVcSdJwtTyp to accept it during migration.`
|
|
9962
|
+
);
|
|
9963
|
+
}
|
|
9964
|
+
} else if (typ !== SD_JWT_VC_TYP) {
|
|
9965
|
+
return invalidResult(
|
|
9966
|
+
`Unsupported SD-JWT VC typ: ${header.typ === void 0 ? "(missing)" : String(header.typ)} (expected '${SD_JWT_VC_TYP}')`
|
|
9967
|
+
);
|
|
9968
|
+
}
|
|
9369
9969
|
const x5cArray = header.x5c;
|
|
9370
9970
|
const hasX5c = Array.isArray(x5cArray) && x5cArray.length > 0 && typeof x5cArray[0] === "string";
|
|
9371
9971
|
let issuerKey;
|
|
@@ -9435,17 +10035,22 @@ var SdJwtParser = class {
|
|
|
9435
10035
|
};
|
|
9436
10036
|
let trustResult;
|
|
9437
10037
|
if (issuerCertBytes === void 0) ; else if (options.trustStore) {
|
|
9438
|
-
const {
|
|
9439
|
-
const
|
|
10038
|
+
const { evaluateCredentialIssuer: evaluateCredentialIssuer2 } = await Promise.resolve().then(() => (init_TrustEvaluator(), TrustEvaluator_exports));
|
|
10039
|
+
const x5cRest = x5cArray.slice(1);
|
|
10040
|
+
if (!x5cRest.every((entry) => typeof entry === "string")) {
|
|
10041
|
+
throw new exports.MalformedCredentialError("x5c entries must be base64 strings");
|
|
10042
|
+
}
|
|
10043
|
+
const iat = payload["iat"];
|
|
10044
|
+
trustResult = await evaluateCredentialIssuer2({
|
|
10045
|
+
chain: [issuerCertBytes, ...x5cRest.map((entry) => base64ToBytes(entry))],
|
|
10046
|
+
profile: "generic",
|
|
10047
|
+
issuedAt: typeof iat === "number" && Number.isFinite(iat) ? new Date(iat * 1e3) : void 0,
|
|
9440
10048
|
trustStore: options.trustStore,
|
|
9441
10049
|
revocationPolicy: options.revocationPolicy ?? "skip",
|
|
9442
10050
|
fetcher: options.fetcher,
|
|
9443
10051
|
cache: options.cache,
|
|
9444
10052
|
clockSkewTolerance: options.clockSkewTolerance
|
|
9445
10053
|
});
|
|
9446
|
-
const { X509Certificate: X509Certificate9 } = await import('@peculiar/x509');
|
|
9447
|
-
const leaf = new X509Certificate9(issuerCertBytes);
|
|
9448
|
-
trustResult = await evaluator.evaluate(leaf);
|
|
9449
10054
|
} else {
|
|
9450
10055
|
if (options.trustedCertificates.length === 0) {
|
|
9451
10056
|
if (options.skipTrustCheck !== true) {
|
|
@@ -9881,6 +10486,9 @@ var InMemoryCache = class {
|
|
|
9881
10486
|
}
|
|
9882
10487
|
};
|
|
9883
10488
|
|
|
10489
|
+
// src/index.ts
|
|
10490
|
+
init_guarded_fetch();
|
|
10491
|
+
|
|
9884
10492
|
// src/trust/index.ts
|
|
9885
10493
|
init_reflect_polyfill();
|
|
9886
10494
|
|
|
@@ -9928,14 +10536,10 @@ var CompositeTrustStore = class {
|
|
|
9928
10536
|
const results = await Promise.all(
|
|
9929
10537
|
this.stores.map((store) => store.getAnchors(hint))
|
|
9930
10538
|
);
|
|
9931
|
-
const seen = /* @__PURE__ */ new Set();
|
|
9932
10539
|
const out = [];
|
|
9933
10540
|
for (const batch of results) {
|
|
9934
10541
|
for (const anchor of batch) {
|
|
9935
|
-
|
|
9936
|
-
const key = ski ?? anchor.certificate.serialNumber;
|
|
9937
|
-
if (seen.has(key)) continue;
|
|
9938
|
-
seen.add(key);
|
|
10542
|
+
if (out.some((a) => certificatesEqual(a.certificate, anchor.certificate))) continue;
|
|
9939
10543
|
out.push(anchor);
|
|
9940
10544
|
}
|
|
9941
10545
|
}
|
|
@@ -9967,6 +10571,7 @@ function bytesToHex3(bytes) {
|
|
|
9967
10571
|
|
|
9968
10572
|
// src/trust/LotlTrustStore.ts
|
|
9969
10573
|
init_reflect_polyfill();
|
|
10574
|
+
init_errors();
|
|
9970
10575
|
|
|
9971
10576
|
// src/trust/lotl-signing-anchors.ts
|
|
9972
10577
|
init_reflect_polyfill();
|
|
@@ -10028,13 +10633,15 @@ var EU_LOTL_SIGNING_ANCHORS = Object.freeze(
|
|
|
10028
10633
|
// src/trust/LotlFetcher.ts
|
|
10029
10634
|
init_reflect_polyfill();
|
|
10030
10635
|
init_errors();
|
|
10636
|
+
init_guarded_fetch();
|
|
10031
10637
|
var XMLDSIG_NS = "http://www.w3.org/2000/09/xmldsig#";
|
|
10032
10638
|
var LotlFetcher = class {
|
|
10033
10639
|
fetcher;
|
|
10034
10640
|
constructor(opts = {}) {
|
|
10035
|
-
this.fetcher = opts.fetcher ??
|
|
10641
|
+
this.fetcher = opts.fetcher ?? createDefaultTrustFetcher();
|
|
10036
10642
|
}
|
|
10037
10643
|
async fetchSigned(url, signingAnchors) {
|
|
10644
|
+
assertCryptoEngineRegistered();
|
|
10038
10645
|
let xmlText;
|
|
10039
10646
|
try {
|
|
10040
10647
|
const response = await this.fetcher(url, { method: "GET" });
|
|
@@ -10087,6 +10694,22 @@ var LotlFetcher = class {
|
|
|
10087
10694
|
);
|
|
10088
10695
|
}
|
|
10089
10696
|
};
|
|
10697
|
+
function assertCryptoEngineRegistered() {
|
|
10698
|
+
let engine;
|
|
10699
|
+
try {
|
|
10700
|
+
engine = xmldsig__namespace.Application.crypto;
|
|
10701
|
+
} catch (err) {
|
|
10702
|
+
throw new exports.LotlConfigurationError(
|
|
10703
|
+
`no xmldsigjs crypto engine registered \u2014 trusted-list signatures cannot be verified. Call xmldsig.Application.setEngine('NodeJS', new Crypto()) (e.g. from @peculiar/webcrypto) once at startup, before using LotlTrustStore. Underlying error: ${err instanceof Error ? err.message : String(err)}`,
|
|
10704
|
+
{ cause: err instanceof Error ? err : void 0 }
|
|
10705
|
+
);
|
|
10706
|
+
}
|
|
10707
|
+
if (!engine) {
|
|
10708
|
+
throw new exports.LotlConfigurationError(
|
|
10709
|
+
"no xmldsigjs crypto engine registered \u2014 trusted-list signatures cannot be verified. Call xmldsig.Application.setEngine('NodeJS', new Crypto()) (e.g. from @peculiar/webcrypto) once at startup, before using LotlTrustStore."
|
|
10710
|
+
);
|
|
10711
|
+
}
|
|
10712
|
+
}
|
|
10090
10713
|
async function verifyAgainst(doc, sigEl, anchor) {
|
|
10091
10714
|
try {
|
|
10092
10715
|
const signed = new xmldsig__namespace.SignedXml(doc);
|
|
@@ -10234,6 +10857,7 @@ function parsePointer(el) {
|
|
|
10234
10857
|
|
|
10235
10858
|
// src/trust/NationalTlResolver.ts
|
|
10236
10859
|
init_reflect_polyfill();
|
|
10860
|
+
init_errors();
|
|
10237
10861
|
var TSL_NS2 = "http://uri.etsi.org/02231/v2#";
|
|
10238
10862
|
var NationalTlResolver = class {
|
|
10239
10863
|
constructor(opts) {
|
|
@@ -10249,6 +10873,7 @@ var NationalTlResolver = class {
|
|
|
10249
10873
|
);
|
|
10250
10874
|
return parseNationalTl(doc, pointer.country);
|
|
10251
10875
|
} catch (err) {
|
|
10876
|
+
if (err instanceof exports.LotlConfigurationError) throw err;
|
|
10252
10877
|
console.warn(
|
|
10253
10878
|
`[openid4vp] national TL for ${pointer.country} failed: ${err.message}`
|
|
10254
10879
|
);
|
|
@@ -10427,6 +11052,7 @@ var LotlTrustStore = class {
|
|
|
10427
11052
|
};
|
|
10428
11053
|
return this.snapshot;
|
|
10429
11054
|
} catch (err) {
|
|
11055
|
+
if (err instanceof exports.LotlConfigurationError) throw err;
|
|
10430
11056
|
if (this.snapshot) {
|
|
10431
11057
|
console.warn(
|
|
10432
11058
|
`[openid4vp] LOTL refresh failed; serving cached snapshot (${err.message})`
|
|
@@ -10474,7 +11100,7 @@ function equalBytes(a, b) {
|
|
|
10474
11100
|
|
|
10475
11101
|
// src/index.ts
|
|
10476
11102
|
init_errors();
|
|
10477
|
-
var VERSION = "0.
|
|
11103
|
+
var VERSION = "0.13.0";
|
|
10478
11104
|
/*! Bundled license information:
|
|
10479
11105
|
|
|
10480
11106
|
pvtsutils/build/index.es.js:
|
|
@@ -10560,14 +11186,17 @@ exports.MdocParser = MdocParser;
|
|
|
10560
11186
|
exports.SdJwtParser = SdJwtParser;
|
|
10561
11187
|
exports.StaticTrustStore = StaticTrustStore;
|
|
10562
11188
|
exports.VERSION = VERSION;
|
|
11189
|
+
exports.buildCredentialSetQuery = buildCredentialSetQuery;
|
|
10563
11190
|
exports.buildHaipQuery = buildHaipQuery;
|
|
10564
11191
|
exports.buildOid4vpSessionTranscript = buildOid4vpSessionTranscript;
|
|
10565
11192
|
exports.buildOpenID4VPHandoverSessionTranscript = buildOpenID4VPHandoverSessionTranscript;
|
|
10566
11193
|
exports.createAuthorizationRequest = createAuthorizationRequest;
|
|
11194
|
+
exports.createGuardedFetcher = createGuardedFetcher;
|
|
10567
11195
|
exports.createSignedAuthorizationRequest = createSignedAuthorizationRequest;
|
|
10568
11196
|
exports.decryptAuthorizationResponse = decryptAuthorizationResponse;
|
|
10569
11197
|
exports.isHaipQuery = isHaipQuery;
|
|
10570
11198
|
exports.parsePresentation = parsePresentation;
|
|
11199
|
+
exports.validateCredentialSetQuery = validateCredentialSetQuery;
|
|
10571
11200
|
exports.validateHaipQuery = validateHaipQuery;
|
|
10572
11201
|
exports.verifyAuthorizationResponse = verifyAuthorizationResponse;
|
|
10573
11202
|
exports.verifyPresentation = verifyPresentation;
|