@fedify/fedify 2.4.0-dev.2164 → 2.4.0-dev.2190

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 (103) hide show
  1. package/dist/{builder-BqRmnx7p.mjs → builder-CFF0YNTp.mjs} +3 -3
  2. package/dist/{circuit-breaker-C5NqoLBJ.mjs → circuit-breaker-XJ53md4S.mjs} +16 -11
  3. package/dist/compat/mod.d.cts +1 -1
  4. package/dist/compat/mod.d.ts +1 -1
  5. package/dist/compat/transformers.test.mjs +1 -1
  6. package/dist/{compound-proof-CxDBdtNz.mjs → compound-proof-F2jjkrt0.mjs} +3 -3
  7. package/dist/{context-BykNUf04.d.ts → context-9T--NSo4.d.ts} +55 -1
  8. package/dist/{context-L0Fnib9j.d.cts → context-CDcAgm4l.d.cts} +55 -1
  9. package/dist/{deno-CizGaYeG.mjs → deno-EopndaNb.mjs} +1 -1
  10. package/dist/{docloader-BBFAItNB.mjs → docloader-u6zzOExF.mjs} +25 -17
  11. package/dist/federation/builder.test.mjs +1 -1
  12. package/dist/federation/circuit-breaker.test.mjs +50 -1
  13. package/dist/federation/compound-fanout.test.mjs +3 -3
  14. package/dist/federation/handler-compound-proof.test.mjs +3 -3
  15. package/dist/federation/handler.test.mjs +5 -5
  16. package/dist/federation/hashlink-media.test.mjs +2 -2
  17. package/dist/federation/idempotency.test.mjs +2 -2
  18. package/dist/federation/keycache.test.mjs +1 -1
  19. package/dist/federation/metrics.test.mjs +1 -1
  20. package/dist/federation/middleware.test.mjs +137 -13
  21. package/dist/federation/mod.cjs +1 -1
  22. package/dist/federation/mod.d.cts +2 -2
  23. package/dist/federation/mod.d.ts +2 -2
  24. package/dist/federation/mod.js +1 -1
  25. package/dist/federation/outgoing-proof.test.mjs +5 -5
  26. package/dist/federation/portable-actor.test.mjs +3 -3
  27. package/dist/federation/portable-chain.test.mjs +3 -3
  28. package/dist/federation/portable-collection.test.mjs +4 -4
  29. package/dist/federation/portable-gateway-keys.test.mjs +6 -6
  30. package/dist/federation/portable-inbox.test.mjs +35 -5
  31. package/dist/federation/portable-parse-uri.test.mjs +1 -1
  32. package/dist/federation/portable-route-activity.test.d.mts +2 -0
  33. package/dist/federation/portable-route-activity.test.mjs +259 -0
  34. package/dist/federation/portable.test.mjs +3 -3
  35. package/dist/federation/send.test.mjs +3 -3
  36. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  37. package/dist/federation/tasks/tasks.test.mjs +2 -2
  38. package/dist/federation/temporal.test.mjs +1 -1
  39. package/dist/federation/webfinger.test.mjs +1 -1
  40. package/dist/{federation-DFCnp94y.cjs → federation-BSS2dUO7.cjs} +38 -21
  41. package/dist/{http-Baovr6xq.js → http-BqN5kyUf.js} +426 -141
  42. package/dist/{http-DC1cqAQ2.d.cts → http-BrwKINQn.d.cts} +28 -0
  43. package/dist/{http-R4g1McwE.cjs → http-CCr2_ipG.cjs} +443 -140
  44. package/dist/{http-Cok5-vIC.d.ts → http-DGx0KOws.d.ts} +28 -0
  45. package/dist/{http-DRH0n8TD.mjs → http-Y1ObT1A8.mjs} +180 -92
  46. package/dist/{key-D5awqp7u.mjs → key-DyXf88bq.mjs} +4 -4
  47. package/dist/{key-owner-evidence-Bo3yaeL5.mjs → key-owner-evidence-APB6NpSk.mjs} +1 -1
  48. package/dist/{keycache-PiOM9pM0.mjs → keycache-Da8A8mZa.mjs} +1 -1
  49. package/dist/{kv-cache-CZiBDLPi.js → kv-cache-C02XitwK.js} +24 -16
  50. package/dist/{kv-cache-C7RWL7hz.mjs → kv-cache-C8YjNAi_.mjs} +1 -1
  51. package/dist/{kv-cache-Ct-KWRta.cjs → kv-cache-DUXluAc0.cjs} +23 -15
  52. package/dist/{ld-CyliEU48.mjs → ld-oQj6j_hP.mjs} +3 -3
  53. package/dist/{metrics-CFBEehTc.mjs → metrics-zMe834ID.mjs} +1 -1
  54. package/dist/{middleware-B99JjvFn.mjs → middleware-Bdu2-OPD.mjs} +37 -25
  55. package/dist/{middleware-CdpTFsa2.js → middleware-CaR2MRWY.js} +39 -22
  56. package/dist/{middleware-BmqEWsWP.mjs → middleware-Ck9yghxs.mjs} +1 -1
  57. package/dist/{mod-DK0y9fd-.d.ts → mod-B3OBLj5g.d.ts} +1 -1
  58. package/dist/{mod-B5z_q9TH.d.ts → mod-C5Mwx5ty.d.ts} +5 -1
  59. package/dist/{mod--jv6vyrP.d.ts → mod-Ck9_lSJB.d.ts} +1 -1
  60. package/dist/{mod-BLOXGs6m.d.cts → mod-D58KCqUg.d.cts} +1 -1
  61. package/dist/{mod-CPPqkyV_.d.cts → mod-DHTuu3l8.d.cts} +1 -1
  62. package/dist/{mod-BA_F2x53.d.cts → mod-Dp3Ij7sw.d.cts} +5 -1
  63. package/dist/mod.cjs +4 -4
  64. package/dist/mod.d.cts +5 -5
  65. package/dist/mod.d.ts +5 -5
  66. package/dist/mod.js +4 -4
  67. package/dist/nodeinfo/handler.test.mjs +1 -1
  68. package/dist/{owner-DKdtsrEq.mjs → owner-Dem4fbwc.mjs} +5 -5
  69. package/dist/{portable-collection-uv4CuQXm.js → portable-collection-BEqLrMW3.js} +1 -1
  70. package/dist/{portable-collection-Cb5cdPIU.mjs → portable-collection-BL6aZlQ0.mjs} +2 -2
  71. package/dist/{portable-collection-UajqDrSL.cjs → portable-collection-DJe_bk50.cjs} +1 -1
  72. package/dist/{portable-key-Bv1RdQ0n.mjs → portable-key-Duue9Y2Y.mjs} +209 -56
  73. package/dist/{portable-key-id-Bg259c4Z.mjs → portable-key-id-Ca30-hOa.mjs} +45 -1
  74. package/dist/{proof-CRTPWbVh.mjs → proof-C9115DX_.mjs} +5 -5
  75. package/dist/{send-2dULlZc8.mjs → send-D0hxFFRB.mjs} +3 -3
  76. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  77. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  78. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  79. package/dist/sig/compound-proof.test.mjs +2 -2
  80. package/dist/sig/http.test.mjs +495 -23
  81. package/dist/sig/key-owner-evidence.test.mjs +2 -2
  82. package/dist/sig/key.test.mjs +1 -1
  83. package/dist/sig/ld.test.mjs +2 -2
  84. package/dist/sig/mod.cjs +2 -2
  85. package/dist/sig/mod.d.cts +2 -2
  86. package/dist/sig/mod.d.ts +2 -2
  87. package/dist/sig/mod.js +2 -2
  88. package/dist/sig/owner.test.mjs +1 -1
  89. package/dist/sig/portable-collection.test.mjs +1 -1
  90. package/dist/sig/portable-key-id.test.d.mts +2 -0
  91. package/dist/sig/portable-key-id.test.mjs +67 -0
  92. package/dist/sig/portable-key.test.mjs +253 -7
  93. package/dist/sig/proof.test.mjs +3 -3
  94. package/dist/{temporal-Dhsk6aUT.mjs → temporal-DKchpKyp.mjs} +1 -1
  95. package/dist/testing/kv.test.mjs +1 -1
  96. package/dist/testing/mod.d.mts +52 -0
  97. package/dist/utils/docloader.test.mjs +93 -2
  98. package/dist/utils/kv-cache.test.mjs +1 -1
  99. package/dist/utils/mod.cjs +1 -1
  100. package/dist/utils/mod.d.cts +1 -1
  101. package/dist/utils/mod.d.ts +1 -1
  102. package/dist/utils/mod.js +1 -1
  103. package/package.json +6 -6
@@ -14,7 +14,7 @@ import serialize from "json-canon";
14
14
  import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
15
15
  //#region deno.json
16
16
  var name = "@fedify/fedify";
17
- var version = "2.4.0-dev.2164+db2b8571";
17
+ var version = "2.4.0-dev.2190+be3a8be0";
18
18
  //#endregion
19
19
  //#region src/sig/portable-key-id.ts
20
20
  const COMPATIBLE_KEY_ID_PATH_PATTERN = /^\/\.well-known\/apgateway\/did(?::|%3A)/i;
@@ -115,6 +115,50 @@ function getCanonicalPortableId(id) {
115
115
  }
116
116
  }
117
117
  /**
118
+ * Gets the [FEP-fe34] origin of an ID for same-origin checks. The origin of
119
+ * an `ap:` or `ap+ef61:` URI, or of a compatible identifier on any gateway,
120
+ * is the DID of its canonical portable ID, as FEP-ef61 treats a compatible
121
+ * identifier as the portable ID it stands for; unlike `getFe34Origin()`,
122
+ * which gives a compatible identifier the web origin of its gateway. The
123
+ * origin of any other HTTP(S) URL is its web origin, and that of a DID URL
124
+ * is its DID.
125
+ *
126
+ * Only the parsed `URL` is validated, so dot segments that URL parsing has
127
+ * already resolved cannot be detected here.
128
+ *
129
+ * [FEP-fe34]: https://w3id.org/fep/fe34
130
+ * @returns The origin, or `null` if the ID has none that is supported, or is
131
+ * a malformed portable ID or compatible identifier.
132
+ * @internal
133
+ */
134
+ function getAuthenticationOrigin(id) {
135
+ try {
136
+ if (isPortableId(id)) {
137
+ const canonical = getCanonicalPortableId(id);
138
+ return canonical == null ? null : getFe34Origin(canonical);
139
+ }
140
+ return getFe34Origin(id);
141
+ } catch (error) {
142
+ if (error instanceof TypeError) return null;
143
+ throw error;
144
+ }
145
+ }
146
+ /**
147
+ * Checks whether two IDs identify the same object. Two portable IDs, i.e.,
148
+ * `ap:` or `ap+ef61:` URIs or compatible identifiers, are compared by their
149
+ * canonical portable IDs, so that the same object on different gateways and
150
+ * with different location hints matches. Other IDs have to be equal as
151
+ * they are.
152
+ * @internal
153
+ */
154
+ function isSameObjectId(a, b) {
155
+ const aPortable = isPortableId(a);
156
+ if (aPortable !== isPortableId(b)) return false;
157
+ if (!aPortable) return a.href === b.href;
158
+ const canonical = getCanonicalPortableId(a);
159
+ return canonical != null && canonical === getCanonicalPortableId(b);
160
+ }
161
+ /**
118
162
  * Gets the canonical portable ID of an `ap:` or `ap+ef61:` URI or
119
163
  * a compatible identifier as it is written, before any URL parsing.
120
164
  * Parsing an ID into a `URL` resolves dot segments in its path, which would
@@ -4533,6 +4577,21 @@ async function fetchPortableGatewayKey(keyId, options = {}) {
4533
4577
  });
4534
4578
  }
4535
4579
  /**
4580
+ * The maximum number of `@gateway` location hints followed for one `ap:` or
4581
+ * `ap+ef61:` key ID. Whoever made a signature chooses the hints of its key
4582
+ * ID, so fewer of them are followed than when dereferencing objects, which
4583
+ * bounds the gateways one signature can make Fedify ask. Further hints are
4584
+ * ignored.
4585
+ */
4586
+ const MAX_KEY_ID_GATEWAY_HINTS = 3;
4587
+ /**
4588
+ * The default of {@link PortableActorKeyOptions.lookupTimeout}, in
4589
+ * milliseconds.
4590
+ */
4591
+ const DEFAULT_KEY_ID_LOOKUP_TIMEOUT = 1e4;
4592
+ /** The longest delay that `setTimeout()` supports, in milliseconds. */
4593
+ const MAX_TIMEOUT = 2 ** 31 - 1;
4594
+ /**
4536
4595
  * Resolves a key of a portable actor at an `ap:` or `ap+ef61:` key ID, e.g.,
4537
4596
  * `ap://did:key:z6Mk…/actor#main-key`. Such a key ID names no gateway, so
4538
4597
  * the actor's document, i.e., the key ID without its fragment, is fetched
@@ -4560,12 +4619,25 @@ async function fetchPortableGatewayKey(keyId, options = {}) {
4560
4619
  * unreachable gateway would have served, so the result is an `unavailable`
4561
4620
  * that is not cacheable.
4562
4621
  *
4622
+ * Only the first {@link MAX_KEY_ID_GATEWAY_HINTS} location hints are
4623
+ * followed, and all the gateways share one timeout, see
4624
+ * {@link PortableActorKeyOptions.lookupTimeout}. A gateway that does not
4625
+ * serve the document in time failed to serve it, like an unreachable one,
4626
+ * with an error that has no HTTP status. A gateway whose document could not
4627
+ * be processed in time, and the gateways left untried, make the result an
4628
+ * `unavailable` that is not cacheable. A result that arrives after
4629
+ * the timeout is ignored, even if it vouches for the key.
4630
+ *
4563
4631
  * @param keyId The key ID, which must be an `ap:` or `ap+ef61:` URI.
4564
- * @param options Loaders and telemetry providers.
4632
+ * @param options Loaders, telemetry providers, and the timeout.
4565
4633
  * @returns The resolution, which is never `legacy`.
4634
+ * @throws {RangeError} If the timeout is not a non-negative number of
4635
+ * milliseconds that `setTimeout()` supports.
4566
4636
  * @internal
4567
4637
  */
4568
4638
  async function resolvePortableActorKey(keyId, options = {}) {
4639
+ const lookupTimeout = options.lookupTimeout ?? DEFAULT_KEY_ID_LOOKUP_TIMEOUT;
4640
+ if (!Number.isFinite(lookupTimeout) || lookupTimeout < 0 || lookupTimeout > MAX_TIMEOUT) throw new RangeError(`The lookup timeout must be between 0 and ${MAX_TIMEOUT} ms: ${lookupTimeout}`);
4569
4641
  const documentLoader = options.documentLoader ?? getDocumentLoader();
4570
4642
  const contextLoader = options.contextLoader ?? getDocumentLoader();
4571
4643
  let formattedKeyId = keyId.href;
@@ -4584,75 +4656,67 @@ async function resolvePortableActorKey(keyId, options = {}) {
4584
4656
  if (keyId.hash === "" || keyId.hash === "#") return reject("The key ID has no fragment; only keys embedded in actor documents are supported.");
4585
4657
  const actorUrl = new URL(keyId.href);
4586
4658
  actorUrl.hash = "";
4659
+ const gateways = getPortableGatewayCandidates(actorUrl);
4660
+ if (gateways.length > MAX_KEY_ID_GATEWAY_HINTS) logger.debug("Following only the first {max} location hints of key {keyId}.", {
4661
+ keyId: formattedKeyId,
4662
+ max: MAX_KEY_ID_GATEWAY_HINTS
4663
+ });
4587
4664
  const requestUrls = [];
4588
- for (const gateway of getPortableGatewayCandidates(actorUrl)) try {
4665
+ for (const gateway of gateways.slice(0, MAX_KEY_ID_GATEWAY_HINTS)) try {
4589
4666
  requestUrls.push(toCompatibleEf61Id(actorUrl, gateway).href);
4590
4667
  } catch (error) {
4591
4668
  if (!(error instanceof TypeError)) throw error;
4592
4669
  return reject(`The key ID cannot be fetched from gateways: ${error}`);
4593
4670
  }
4594
4671
  if (requestUrls.length < 1) requestUrls.push(formatIri(actorUrl));
4672
+ const controller = new AbortController();
4673
+ const timeoutError = new DOMException(`Timed out looking up the actor of key ${formattedKeyId} after ${lookupTimeout} ms.`, "TimeoutError");
4674
+ let timer;
4675
+ if (lookupTimeout > 0) timer = setTimeout(() => controller.abort(timeoutError), lookupTimeout);
4676
+ else controller.abort(timeoutError);
4677
+ const { signal } = controller;
4678
+ const attemptOptions = {
4679
+ ...options,
4680
+ documentLoader: withDeadline(documentLoader, signal),
4681
+ contextLoader: withDeadline(contextLoader, signal),
4682
+ signal,
4683
+ formattedKeyId
4684
+ };
4595
4685
  const attempts = [];
4596
- for (const url of requestUrls) {
4597
- let remoteDocument;
4598
- try {
4599
- remoteDocument = await documentLoader(url);
4600
- } catch (error) {
4601
- logger.debug("Failed to fetch the actor of key {keyId} from {url}: {error}", {
4602
- keyId: formattedKeyId,
4603
- url,
4604
- error
4605
- });
4606
- attempts.push({
4607
- type: "retrievalFailed",
4608
- error
4609
- });
4610
- continue;
4611
- }
4612
- let resolution;
4613
- try {
4614
- const object = await Object$1.fromJsonLd(remoteDocument.document, {
4615
- documentLoader,
4616
- contextLoader,
4617
- tracerProvider: options.tracerProvider
4618
- });
4619
- resolution = isPortableActorDocument(object) ? await verifyPortableKeyDocument(remoteDocument.document, object, keyId, false, {
4620
- ...options,
4621
- documentLoader,
4622
- contextLoader
4623
- }) : {
4624
- type: "rejected",
4625
- reason: "The document is not a portable actor."
4626
- };
4627
- } catch (error) {
4628
- if (error instanceof TypeError) resolution = {
4629
- type: "rejected",
4630
- reason: `The document is malformed: ${error.message}`
4631
- };
4632
- else {
4633
- logger.debug("Failed to process the actor of key {keyId} served from {url}: {error}", {
4686
+ try {
4687
+ for (const url of requestUrls) {
4688
+ if (signal.aborted) {
4689
+ logger.debug("Ran out of time looking up the actor of key {keyId}; gateways from {url} on were not tried.", {
4634
4690
  keyId: formattedKeyId,
4635
- url,
4636
- error
4691
+ url
4637
4692
  });
4638
4693
  attempts.push({
4639
4694
  type: "indeterminate",
4640
- error
4695
+ error: signal.reason
4696
+ });
4697
+ break;
4698
+ }
4699
+ const state = { processing: false };
4700
+ let attempt;
4701
+ try {
4702
+ attempt = await raceAbort(attemptGateway(url, keyId, attemptOptions, state), signal);
4703
+ } catch (error) {
4704
+ if (!signal.aborted) throw error;
4705
+ logger.debug("Ran out of time looking up the actor of key {keyId} at {url}.", {
4706
+ keyId: formattedKeyId,
4707
+ url
4708
+ });
4709
+ attempts.push({
4710
+ type: state.processing ? "indeterminate" : "retrievalFailed",
4711
+ error: signal.reason
4641
4712
  });
4642
4713
  continue;
4643
4714
  }
4715
+ if (attempt.type === "verified") return attempt;
4716
+ attempts.push(attempt);
4644
4717
  }
4645
- if (resolution.type === "verified") return resolution;
4646
- const reason = resolution.type === "rejected" ? resolution.reason : "The document is not a portable actor.";
4647
- logger.debug("The actor document served from {url} does not vouch for key {keyId}: {reason}", {
4648
- keyId: formattedKeyId,
4649
- url,
4650
- reason
4651
- });
4652
- attempts.push({
4653
- type: "rejected",
4654
- reason
4655
- });
4718
+ } finally {
4719
+ clearTimeout(timer);
4656
4720
  }
4657
4721
  const rejections = attempts.flatMap((a) => a.type === "rejected" ? [a.reason] : []);
4658
4722
  if (rejections.length === attempts.length) return reject(rejections.join(" "));
@@ -4673,6 +4737,139 @@ async function resolvePortableActorKey(keyId, options = {}) {
4673
4737
  };
4674
4738
  }
4675
4739
  /**
4740
+ * Fetches the actor's document of a key at an `ap:` or `ap+ef61:` key ID from
4741
+ * one gateway, and tells whether it vouches for the key. It never rejects;
4742
+ * the caller races it against the lookup's timeout, and ignores what it
4743
+ * resolves to after the timeout.
4744
+ */
4745
+ async function attemptGateway(url, keyId, options, state) {
4746
+ const { documentLoader, contextLoader, signal, formattedKeyId } = options;
4747
+ let remoteDocument;
4748
+ try {
4749
+ remoteDocument = await documentLoader(url);
4750
+ } catch (error) {
4751
+ logger.debug("Failed to fetch the actor of key {keyId} from {url}: {error}", {
4752
+ keyId: formattedKeyId,
4753
+ url,
4754
+ error
4755
+ });
4756
+ return {
4757
+ type: "retrievalFailed",
4758
+ error
4759
+ };
4760
+ }
4761
+ if (signal.aborted) return {
4762
+ type: "indeterminate",
4763
+ error: signal.reason
4764
+ };
4765
+ state.processing = true;
4766
+ let resolution;
4767
+ try {
4768
+ const object = await Object$1.fromJsonLd(remoteDocument.document, {
4769
+ documentLoader,
4770
+ contextLoader,
4771
+ tracerProvider: options.tracerProvider
4772
+ });
4773
+ signal.throwIfAborted();
4774
+ resolution = isPortableActorDocument(object) ? await verifyPortableKeyDocument(remoteDocument.document, object, keyId, false, options) : {
4775
+ type: "rejected",
4776
+ reason: "The document is not a portable actor."
4777
+ };
4778
+ } catch (error) {
4779
+ if (error instanceof TypeError && !signal.aborted) resolution = {
4780
+ type: "rejected",
4781
+ reason: `The document is malformed: ${error.message}`
4782
+ };
4783
+ else {
4784
+ logger.debug("Failed to process the actor of key {keyId} served from {url}: {error}", {
4785
+ keyId: formattedKeyId,
4786
+ url,
4787
+ error
4788
+ });
4789
+ return {
4790
+ type: "indeterminate",
4791
+ error
4792
+ };
4793
+ }
4794
+ }
4795
+ if (resolution.type === "verified") return resolution;
4796
+ const reason = resolution.type === "rejected" ? resolution.reason : "The document is not a portable actor.";
4797
+ logger.debug("The actor document served from {url} does not vouch for key {keyId}: {reason}", {
4798
+ keyId: formattedKeyId,
4799
+ url,
4800
+ reason
4801
+ });
4802
+ return {
4803
+ type: "rejected",
4804
+ reason
4805
+ };
4806
+ }
4807
+ /**
4808
+ * Wraps a document loader so that it gives up when the given signal aborts,
4809
+ * as well as when the signal in its own options does. The wrapped loader is
4810
+ * passed a signal that aborts in either case, but in case it ignores that
4811
+ * signal, what it resolves to after the abort is ignored, and the wrapper
4812
+ * rejects with the reason of the abort at once. After the abort, the wrapped
4813
+ * loader is not called at all.
4814
+ */
4815
+ function withDeadline(loader, signal) {
4816
+ return (url, options) => {
4817
+ const combined = combineSignals(signal, options?.signal);
4818
+ return raceAbort(combined.signal.aborted ? Promise.reject(combined.signal.reason) : new Promise((resolve) => resolve(loader(url, {
4819
+ ...options,
4820
+ signal: combined.signal
4821
+ }))), combined.signal).finally(combined.dispose);
4822
+ };
4823
+ }
4824
+ /**
4825
+ * Makes a signal that aborts when either of the given signals does, with
4826
+ * the reason of the one that aborted first. `AbortSignal.any()` is not
4827
+ * available on every supported runtime, e.g., Bun before 1.1.4.
4828
+ * @returns The signal, and a function that stops listening to the given
4829
+ * signals.
4830
+ */
4831
+ function combineSignals(signal, other) {
4832
+ if (other == null || other === signal) return {
4833
+ signal,
4834
+ dispose() {}
4835
+ };
4836
+ const controller = new AbortController();
4837
+ const sources = [signal, other];
4838
+ const dispose = () => {
4839
+ for (const source of sources) source.removeEventListener("abort", onAbort);
4840
+ };
4841
+ function onAbort() {
4842
+ dispose();
4843
+ controller.abort(this.reason);
4844
+ }
4845
+ const aborted = sources.find((source) => source.aborted);
4846
+ if (aborted == null) for (const source of sources) source.addEventListener("abort", onAbort);
4847
+ else controller.abort(aborted.reason);
4848
+ return {
4849
+ signal: controller.signal,
4850
+ dispose
4851
+ };
4852
+ }
4853
+ /**
4854
+ * Waits for the given promise unless the given signal aborts first, in which
4855
+ * case it rejects with the reason of the abort. If the signal has aborted by
4856
+ * the time the promise settles, the abort wins as well, so that nothing that
4857
+ * settles after it counts.
4858
+ */
4859
+ function raceAbort(promise, signal) {
4860
+ return new Promise((resolve, reject) => {
4861
+ const onAbort = () => reject(signal.reason);
4862
+ const settle = (settled) => {
4863
+ signal.removeEventListener("abort", onAbort);
4864
+ if (signal.aborted) onAbort();
4865
+ else settled();
4866
+ };
4867
+ promise.then((value) => settle(() => resolve(value)), (error) => settle(() => reject(error)));
4868
+ if (signal.aborted) onAbort();
4869
+ else signal.addEventListener("abort", onAbort, { once: true });
4870
+ });
4871
+ }
4872
+ /**
4676
4873
  * Finds the nodes that stand for the key with the given canonical portable
4677
4874
  * ID. A node whose ID is an `ap:` or `ap+ef61:` URI stands for the key
4678
4875
  * itself, e.g., Mitra lists the keys of portable actors that way while
@@ -4903,16 +5100,19 @@ function parseDraftSignature(signature) {
4903
5100
  * Lists the HTTP Signatures that a request claims to carry, without verifying
4904
5101
  * any of them. Signatures whose key IDs are not URLs are left out.
4905
5102
  * @param request The request.
5103
+ * @param maxSignatures The maximum number of RFC 9421 signatures to consider,
5104
+ * counted the same way as by {@link verifyRequest}, so
5105
+ * that the signatures it ignores are not listed either.
4906
5106
  * @returns The signatures; RFC 9421 ones if the request has
4907
5107
  * a `Signature-Input` header, or a draft-cavage one otherwise.
4908
5108
  * @internal
4909
5109
  */
4910
- function listRequestSignatures(request) {
5110
+ function listRequestSignatures(request, maxSignatures = 3) {
4911
5111
  const signatureInput = request.headers.get("Signature-Input");
4912
5112
  if (signatureInput != null) {
4913
5113
  const signatures = [];
4914
- const inputs = parseRfc9421SignatureInput(signatureInput);
4915
- for (const [label, input] of Object.entries(inputs)) {
5114
+ const inputs = Object.entries(parseRfc9421SignatureInput(signatureInput));
5115
+ for (const [label, input] of inputs.slice(0, maxSignatures)) {
4916
5116
  const keyId = parseKeyId(input.keyId);
4917
5117
  if (keyId == null) continue;
4918
5118
  signatures.push({
@@ -5040,6 +5240,18 @@ async function signRequestRfc9421(request, privateKey, keyId, span, currentTime,
5040
5240
  body
5041
5241
  });
5042
5242
  }
5243
+ /**
5244
+ * Checks that a maximum number of signatures to verify is a positive safe
5245
+ * integer or `Infinity`.
5246
+ * @param value The value to check.
5247
+ * @param name The name of the option, used in the error message.
5248
+ * @throws {RangeError} Thrown if the value is not valid.
5249
+ * @internal
5250
+ */
5251
+ function validateMaxSignatures(value, name) {
5252
+ if (value === Infinity || Number.isSafeInteger(value) && value >= 1) return;
5253
+ throw new RangeError(`${name} must be a positive integer or Infinity.`);
5254
+ }
5043
5255
  const supportedHashAlgorithms = {
5044
5256
  "sha": "SHA-1",
5045
5257
  "sha-256": "SHA-256",
@@ -5132,6 +5344,8 @@ function recordVerificationResult(span, result) {
5132
5344
  * @param options Options for verifying the request.
5133
5345
  * @returns The public key of the verified signature, or `null` if the signature
5134
5346
  * could not be verified.
5347
+ * @throws {RangeError} Thrown if {@link VerifyRequestOptions.maxSignatures}
5348
+ * is not a positive integer or `Infinity`.
5135
5349
  */
5136
5350
  async function verifyRequest(request, options = {}) {
5137
5351
  const result = await verifyRequestDetailed(request, options);
@@ -5144,9 +5358,12 @@ async function verifyRequest(request, options = {}) {
5144
5358
  * @param request The request to verify.
5145
5359
  * @param options Options for verifying the request.
5146
5360
  * @returns The verified public key, or a structured verification failure.
5361
+ * @throws {RangeError} Thrown if {@link VerifyRequestOptions.maxSignatures}
5362
+ * is not a positive integer or `Infinity`.
5147
5363
  * @since 2.1.0
5148
5364
  */
5149
5365
  async function verifyRequestDetailed(request, options = {}) {
5366
+ if (options.maxSignatures !== void 0) validateMaxSignatures(options.maxSignatures, "maxSignatures");
5150
5367
  return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("http_signatures.verify", async (span) => {
5151
5368
  if (span.isRecording()) {
5152
5369
  span.setAttribute(ATTR_HTTP_REQUEST_METHOD, request.method);
@@ -5455,7 +5672,100 @@ async function verifyRfc9421ContentDigest(digestHeader, body) {
5455
5672
  }
5456
5673
  return false;
5457
5674
  }
5458
- async function verifyRequestRfc9421(request, span, metricsContext, { documentLoader, contextLoader, timeWindow, currentTime, keyCache, meterProvider, tracerProvider } = {}) {
5675
+ /**
5676
+ * Verifies one RFC 9421 signature of a request with a key.
5677
+ * @param request The request, whose body may be consumed already.
5678
+ * @param sigInput The parsed `Signature-Input` member of the signature.
5679
+ * @param sigBytes The bytes of the signature.
5680
+ * @param key The public key named by the signature.
5681
+ * @param span The span to record the algorithm and the signature on.
5682
+ * @returns Whether the signature is verified, and the algorithm of the
5683
+ * signature if it is supported.
5684
+ */
5685
+ async function verifyRfc9421SignatureWithKey(request, sigInput, sigBytes, key, span) {
5686
+ const logger = getLogger([
5687
+ "fedify",
5688
+ "sig",
5689
+ "http"
5690
+ ]);
5691
+ let alg = sigInput.alg?.toLowerCase();
5692
+ if (alg == null) {
5693
+ if (key.publicKey.algorithm.name === "RSASSA-PKCS1-v1_5") alg = "hash" in key.publicKey.algorithm ? key.publicKey.algorithm.hash === "SHA-512" ? "rsa-v1_5-sha512" : "rsa-v1_5-sha256" : "rsa-v1_5-sha256";
5694
+ else if (key.publicKey.algorithm.name === "RSA-PSS") alg = "rsa-pss-sha512";
5695
+ else if (key.publicKey.algorithm.name === "ECDSA") alg = "namedCurve" in key.publicKey.algorithm && key.publicKey.algorithm.namedCurve === "P-256" ? "ecdsa-p256-sha256" : "ecdsa-p384-sha384";
5696
+ else if (key.publicKey.algorithm.name === "Ed25519") alg = "ed25519";
5697
+ }
5698
+ if (alg) span?.setAttribute("http_signatures.algorithm", alg);
5699
+ const algorithm = alg && rfc9421AlgorithmMap[alg];
5700
+ if (!algorithm) {
5701
+ logger.debug("Failed to verify; unsupported algorithm: {algorithm}", {
5702
+ algorithm: sigInput.alg,
5703
+ supported: Object.keys(rfc9421AlgorithmMap)
5704
+ });
5705
+ return {
5706
+ verified: false,
5707
+ mismatched: false
5708
+ };
5709
+ }
5710
+ const metricAlgorithm = alg;
5711
+ let signatureBase;
5712
+ try {
5713
+ signatureBase = createRfc9421SignatureBase(request, sigInput.components, sigInput.parameters);
5714
+ } catch (error) {
5715
+ logger.debug("Failed to create signature base for verification: {error}", {
5716
+ error,
5717
+ signatureInput: sigInput
5718
+ });
5719
+ return {
5720
+ verified: false,
5721
+ algorithm: metricAlgorithm,
5722
+ mismatched: false
5723
+ };
5724
+ }
5725
+ const signatureBaseBytes = new TextEncoder().encode(signatureBase);
5726
+ span?.setAttribute("http_signatures.signature", encodeHex(sigBytes));
5727
+ const algorithmName = typeof algorithm === "string" ? algorithm : algorithm.name;
5728
+ if (key.publicKey.algorithm.name !== algorithmName) {
5729
+ logger.debug("Failed to verify; key {keyId} is not a key for algorithm {algorithm}.", {
5730
+ keyId: sigInput.keyId,
5731
+ algorithm: alg
5732
+ });
5733
+ return {
5734
+ verified: false,
5735
+ algorithm: metricAlgorithm,
5736
+ mismatched: true
5737
+ };
5738
+ }
5739
+ let verified;
5740
+ try {
5741
+ verified = await crypto.subtle.verify(algorithm, key.publicKey, sigBytes.slice(), signatureBaseBytes);
5742
+ } catch (error) {
5743
+ logger.debug("Error during signature verification: {error}", {
5744
+ error,
5745
+ keyId: sigInput.keyId,
5746
+ algorithm: sigInput.alg
5747
+ });
5748
+ return {
5749
+ verified: false,
5750
+ algorithm: metricAlgorithm,
5751
+ mismatched: false
5752
+ };
5753
+ }
5754
+ if (verified) return {
5755
+ verified: true,
5756
+ algorithm: metricAlgorithm
5757
+ };
5758
+ logger.debug("Failed to verify signature with key {keyId}; signature invalid.", {
5759
+ keyId: sigInput.keyId,
5760
+ signatureBase
5761
+ });
5762
+ return {
5763
+ verified: false,
5764
+ algorithm: metricAlgorithm,
5765
+ mismatched: true
5766
+ };
5767
+ }
5768
+ async function verifyRequestRfc9421(request, span, metricsContext, { documentLoader, contextLoader, timeWindow, currentTime, keyCache, maxSignatures = 3, meterProvider, tracerProvider } = {}) {
5459
5769
  const logger = getLogger([
5460
5770
  "fedify",
5461
5771
  "sig",
@@ -5468,7 +5778,6 @@ async function verifyRequestRfc9421(request, span, metricsContext, { documentLoa
5468
5778
  logger.error("Failed to verify; the request body is locked.", { url: request.url });
5469
5779
  return noSignatureResult();
5470
5780
  }
5471
- const originalRequest = request;
5472
5781
  request = request.clone();
5473
5782
  const signatureInputHeader = request.headers.get("Signature-Input");
5474
5783
  if (!signatureInputHeader) {
@@ -5488,6 +5797,29 @@ async function verifyRequestRfc9421(request, span, metricsContext, { documentLoa
5488
5797
  logger.debug("Failed to verify; no valid signatures found in Signature-Input header.", { header: signatureInputHeader });
5489
5798
  return invalidSignatureResult(null);
5490
5799
  }
5800
+ if (signatureNames.length > maxSignatures) {
5801
+ logger.debug("Verifying only the first {maxSignatures} of the {count} signatures in the Signature-Input header; the rest are ignored.", {
5802
+ maxSignatures,
5803
+ count: signatureNames.length
5804
+ });
5805
+ signatureNames.splice(maxSignatures);
5806
+ }
5807
+ const keyLookups = /* @__PURE__ */ new Map();
5808
+ const refreshedKeyIds = /* @__PURE__ */ new Set();
5809
+ const lookUpKey = (keyId, keyCache) => measureSignatureKeyFetch(meterProvider, "http", () => fetchKeyDetailed(keyId, CryptographicKey, {
5810
+ documentLoader,
5811
+ contextLoader,
5812
+ keyCache,
5813
+ tracerProvider,
5814
+ meterProvider,
5815
+ portableKeyResolvers: createPortableKeyResolvers({
5816
+ documentLoader,
5817
+ contextLoader,
5818
+ keyCache,
5819
+ tracerProvider,
5820
+ meterProvider
5821
+ })
5822
+ }));
5491
5823
  let failure = noSignatureResult();
5492
5824
  let failureAlgorithm;
5493
5825
  const setFailure = (result, algorithm) => {
@@ -5561,94 +5893,40 @@ async function verifyRequestRfc9421(request, span, metricsContext, { documentLoa
5561
5893
  setFailure(invalidSignatureResult(null));
5562
5894
  continue;
5563
5895
  }
5564
- const { key, cached, fetchError } = await measureSignatureKeyFetch(meterProvider, "http", () => fetchKeyDetailed(keyId, CryptographicKey, {
5565
- documentLoader,
5566
- contextLoader,
5567
- keyCache,
5568
- tracerProvider,
5569
- meterProvider,
5570
- portableKeyResolvers: createPortableKeyResolvers({
5571
- documentLoader,
5572
- contextLoader,
5573
- keyCache,
5574
- tracerProvider,
5575
- meterProvider
5576
- })
5577
- }));
5578
- if (fetchError != null) {
5579
- setFailure(keyFetchErrorResult(keyId, fetchError));
5580
- continue;
5581
- }
5582
- if (!key) {
5583
- logger.debug("Failed to fetch key: {keyId}", { keyId: sigInput.keyId });
5584
- setFailure(invalidSignatureResult(keyId));
5585
- continue;
5586
- }
5587
- let alg = sigInput.alg?.toLowerCase();
5588
- if (alg == null) {
5589
- if (key.publicKey.algorithm.name === "RSASSA-PKCS1-v1_5") alg = "hash" in key.publicKey.algorithm ? key.publicKey.algorithm.hash === "SHA-512" ? "rsa-v1_5-sha512" : "rsa-v1_5-sha256" : "rsa-v1_5-sha256";
5590
- else if (key.publicKey.algorithm.name === "RSA-PSS") alg = "rsa-pss-sha512";
5591
- else if (key.publicKey.algorithm.name === "ECDSA") alg = "namedCurve" in key.publicKey.algorithm && key.publicKey.algorithm.namedCurve === "P-256" ? "ecdsa-p256-sha256" : "ecdsa-p384-sha384";
5592
- else if (key.publicKey.algorithm.name === "Ed25519") alg = "ed25519";
5593
- }
5594
- if (alg) span?.setAttribute("http_signatures.algorithm", alg);
5595
- const algorithm = alg && rfc9421AlgorithmMap[alg];
5596
- const candidateAlgorithm = algorithm ? alg : void 0;
5597
- if (!algorithm) {
5598
- logger.debug("Failed to verify; unsupported algorithm: {algorithm}", {
5599
- algorithm: sigInput.alg,
5600
- supported: Object.keys(rfc9421AlgorithmMap)
5601
- });
5602
- setFailure(invalidSignatureResult(keyId));
5603
- continue;
5604
- }
5605
- let signatureBase;
5606
- try {
5607
- signatureBase = createRfc9421SignatureBase(request, sigInput.components, sigInput.parameters);
5608
- } catch (error) {
5609
- logger.debug("Failed to create signature base for verification: {error}", {
5610
- error,
5611
- signatureInput: sigInput
5612
- });
5613
- setFailure(invalidSignatureResult(keyId), candidateAlgorithm);
5614
- continue;
5896
+ let lookup = keyLookups.get(keyId.href);
5897
+ if (lookup == null) {
5898
+ lookup = await lookUpKey(keyId, keyCache);
5899
+ keyLookups.set(keyId.href, lookup);
5615
5900
  }
5616
- const signatureBaseBytes = new TextEncoder().encode(signatureBase);
5617
- span?.setAttribute("http_signatures.signature", encodeHex(sigBytes));
5618
- try {
5619
- if (await crypto.subtle.verify(algorithm, key.publicKey, sigBytes.slice(), signatureBaseBytes)) {
5620
- metricsContext.algorithm = candidateAlgorithm;
5901
+ while (true) {
5902
+ const { key, cached, fetchError } = lookup;
5903
+ if (fetchError != null) {
5904
+ setFailure(keyFetchErrorResult(keyId, fetchError));
5905
+ break;
5906
+ }
5907
+ if (!key) {
5908
+ logger.debug("Failed to fetch key: {keyId}", { keyId: sigInput.keyId });
5909
+ setFailure(invalidSignatureResult(keyId));
5910
+ break;
5911
+ }
5912
+ const result = await verifyRfc9421SignatureWithKey(request, sigInput, sigBytes, key, span);
5913
+ if (result.verified) {
5914
+ metricsContext.algorithm = result.algorithm;
5621
5915
  return {
5622
5916
  verified: true,
5623
5917
  key,
5624
5918
  signatureLabel: sigName
5625
5919
  };
5626
- } else if (cached) {
5920
+ }
5921
+ if (result.mismatched && cached && !refreshedKeyIds.has(keyId.href)) {
5627
5922
  logger.debug("Failed to verify with cached key {keyId}; retrying with fresh key...", { keyId: sigInput.keyId });
5628
- return await verifyRequestRfc9421(originalRequest, span, metricsContext, {
5629
- documentLoader,
5630
- contextLoader,
5631
- timeWindow,
5632
- currentTime,
5633
- keyCache: bypassKeyCacheReads(keyCache),
5634
- spec: "rfc9421",
5635
- meterProvider,
5636
- tracerProvider
5637
- });
5638
- } else {
5639
- logger.debug("Failed to verify signature with fetched key {keyId}; signature invalid.", {
5640
- keyId: sigInput.keyId,
5641
- signatureBase
5642
- });
5643
- setFailure(invalidSignatureResult(keyId), candidateAlgorithm);
5923
+ refreshedKeyIds.add(keyId.href);
5924
+ lookup = await lookUpKey(keyId, bypassKeyCacheReads(keyCache));
5925
+ keyLookups.set(keyId.href, lookup);
5926
+ continue;
5644
5927
  }
5645
- } catch (error) {
5646
- logger.debug("Error during signature verification: {error}", {
5647
- error,
5648
- keyId: sigInput.keyId,
5649
- algorithm: sigInput.alg
5650
- });
5651
- setFailure(invalidSignatureResult(keyId), candidateAlgorithm);
5928
+ setFailure(invalidSignatureResult(keyId), result.algorithm);
5929
+ break;
5652
5930
  }
5653
5931
  }
5654
5932
  metricsContext.algorithm = failureAlgorithm;
@@ -5748,16 +6026,19 @@ async function doubleKnock(request, identity, options = {}) {
5748
6026
  }
5749
6027
  async function doubleKnockInternal(request, identity, options, redirected = 0, visited = /* @__PURE__ */ new Set()) {
5750
6028
  const { specDeterminer, log, tracerProvider, signal } = options;
6029
+ signal?.throwIfAborted();
5751
6030
  const maximumRedirection = options.maxRedirection ?? DEFAULT_MAX_REDIRECTION;
5752
6031
  visited.add(request.url);
5753
6032
  const origin = new URL(request.url).origin;
5754
6033
  const firstTrySpec = specDeterminer == null ? "rfc9421" : await specDeterminer.determineSpec(origin);
6034
+ signal?.throwIfAborted();
5755
6035
  const body = options.body !== void 0 ? options.body : request.method !== "GET" && request.method !== "HEAD" ? await request.clone().arrayBuffer() : null;
5756
6036
  let signedRequest = await signRequest(request, identity.privateKey, identity.keyId, {
5757
6037
  spec: firstTrySpec,
5758
6038
  tracerProvider,
5759
6039
  body
5760
6040
  });
6041
+ signal?.throwIfAborted();
5761
6042
  log?.(signedRequest);
5762
6043
  let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
5763
6044
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
@@ -5782,6 +6063,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
5782
6063
  let fulfilled = false;
5783
6064
  let challengeRequest;
5784
6065
  for (const entry of entries) {
6066
+ signal?.throwIfAborted();
5785
6067
  const rfc9421 = fulfillAcceptSignature(entry, localKeyId, localAlg);
5786
6068
  if (rfc9421 == null) continue;
5787
6069
  logger.debug("Received Accept-Signature challenge; accumulating label {label} and components {components}.", {
@@ -5804,6 +6086,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
5804
6086
  }
5805
6087
  }
5806
6088
  if (fulfilled && challengeRequest != null) {
6089
+ signal?.throwIfAborted();
5807
6090
  signedRequest = challengeRequest;
5808
6091
  log?.(signedRequest);
5809
6092
  response = await fetch(signedRequest, {
@@ -5828,11 +6111,13 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
5828
6111
  status: response.status,
5829
6112
  statusText: response.statusText
5830
6113
  });
6114
+ signal?.throwIfAborted();
5831
6115
  signedRequest = await signRequest(request, identity.privateKey, identity.keyId, {
5832
6116
  spec,
5833
6117
  tracerProvider,
5834
6118
  body
5835
6119
  });
6120
+ signal?.throwIfAborted();
5836
6121
  log?.(signedRequest);
5837
6122
  response = await fetchDoubleKnockRequest(request, signedRequest, signal);
5838
6123
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
@@ -5875,4 +6160,4 @@ function timingSafeEqual(a, b) {
5875
6160
  return result === 0;
5876
6161
  }
5877
6162
  //#endregion
5878
- export { isAbortError$1 as $, hasSignatureLike as A, fetchKey as B, assertSafeJsonLd as C, isPortableId as Ct, detachSignature as D, name as Dt, createSignature as E, isSamePublicKey as Et, verifyJsonLd as F, verifyKeyOwnership as G, generateCryptoKeyPair as H, verifySignature as I, parseKeyOwnerEvidence as J, MAX_PORTABLE_KEY_TTL as K, wrapContextLoaderForJsonLd as L, isInvalidUrlTypeError as M, signJsonLd as N, getNormalizationContextLoader as O, version as Ot, verifyCompactJsonLd as P, instrumentDocumentLoader as Q, exportJwk as R, InvalidContextReferenceError as S, isCompatibleKeyId as St, compactJsonLd as T, isPortableUri as Tt, importJwk as U, fetchKeyDetailed as V, validateCryptoKey as W, getFederationMetrics as X, getDurationMs as Y, getRemoteHost as Z, verifyPortableObjectProof as _, getCanonicalPortableId as _t, signRequest as a, recordDocumentCache as at, verifyProof as b, getRawCanonicalPortableId as bt, fetchPortableGatewayKey as c, recordOutboxActivity as ct, classifyFep2277CoreType as d, registerQueueDepthGauge as dt, recordCircuitBreakerStateChange as et, createProof as f, preloadedOnlyDocumentLoader as ft, verifyObject as g, validateAcceptSignature as gt, verifyMapLocalProof as h, parseAcceptSignature as ht, selectRequestSignature as i, recordCollectionTotalItems as it, isClearlyMalformedContextReference as j, hasSignature as k, resolvePortableActorKey as l, recordOutboxEnqueue as lt, signObject as m, fulfillAcceptSignature as mt, listRequestSignatures as n, recordCollectionPageItems as nt, verifyRequest as o, recordFanoutRecipients as ot, hasProofLike as p, formatAcceptSignature as pt, getVerifiedKeyOwnerEvidence as q, parseRfc9421SignatureInput as r, recordCollectionRequest as rt, verifyRequestDetailed as s, recordInboxActivity as st, doubleKnock as t, recordCollectionDispatchDuration as tt, InvalidPortableObjectIdError as u, recordWebFingerHandle as ut, verifyPortableObjectProofPolicy as v, getGatewayKeyBase as vt, attachSignature as w, isPortableKeyId as wt, normalizeOutgoingActivityJsonLd as x, hasPortableActor as xt, verifyPortableObjectProofWithRoot as y, getPortableDid as yt, fetchActorDocument as z };
6163
+ export { instrumentDocumentLoader as $, hasSignature as A, name as At, fetchActorDocument as B, InvalidContextReferenceError as C, hasPortableActor as Ct, createSignature as D, isPortableUri as Dt, compactJsonLd as E, isPortableKeyId as Et, verifyCompactJsonLd as F, validateCryptoKey as G, fetchKeyDetailed as H, verifyJsonLd as I, getVerifiedKeyOwnerEvidence as J, verifyKeyOwnership as K, verifySignature as L, isClearlyMalformedContextReference as M, isInvalidUrlTypeError as N, detachSignature as O, isSameObjectId as Ot, signJsonLd as P, getRemoteHost as Q, wrapContextLoaderForJsonLd as R, normalizeOutgoingActivityJsonLd as S, getRawCanonicalPortableId as St, attachSignature as T, isPortableId as Tt, generateCryptoKeyPair as U, fetchKey as V, importJwk as W, getDurationMs as X, parseKeyOwnerEvidence as Y, getFederationMetrics as Z, verifyObject as _, validateAcceptSignature as _t, signRequest as a, recordCollectionTotalItems as at, verifyPortableObjectProofWithRoot as b, getGatewayKeyBase as bt, verifyRequestDetailed as c, recordInboxActivity as ct, InvalidPortableObjectIdError as d, recordWebFingerHandle as dt, isAbortError$1 as et, classifyFep2277CoreType as f, registerQueueDepthGauge as ft, verifyMapLocalProof as g, parseAcceptSignature as gt, signObject as h, fulfillAcceptSignature as ht, selectRequestSignature as i, recordCollectionRequest as it, hasSignatureLike as j, version as jt, getNormalizationContextLoader as k, isSamePublicKey as kt, fetchPortableGatewayKey as l, recordOutboxActivity as lt, hasProofLike as m, formatAcceptSignature as mt, listRequestSignatures as n, recordCollectionDispatchDuration as nt, validateMaxSignatures as o, recordDocumentCache as ot, createProof as p, preloadedOnlyDocumentLoader as pt, MAX_PORTABLE_KEY_TTL as q, parseRfc9421SignatureInput as r, recordCollectionPageItems as rt, verifyRequest as s, recordFanoutRecipients as st, doubleKnock as t, recordCircuitBreakerStateChange as tt, resolvePortableActorKey as u, recordOutboxEnqueue as ut, verifyPortableObjectProof as v, getAuthenticationOrigin as vt, assertSafeJsonLd as w, isCompatibleKeyId as wt, verifyProof as x, getPortableDid as xt, verifyPortableObjectProofPolicy as y, getCanonicalPortableId as yt, exportJwk as z };