@fedify/fedify 2.5.0-dev.2446 → 2.5.0-dev.2492

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 (141) hide show
  1. package/README.md +3 -0
  2. package/dist/{activity-listener-C-BSbKI7.mjs → activity-listener-CELFAodc.mjs} +8 -4
  3. package/dist/{builder-Da8b9O6v.mjs → builder-DphK9v7f.mjs} +5 -5
  4. package/dist/{client-D-XP_Ccb.d.ts → client-3InDZbba.d.cts} +0 -1
  5. package/dist/{client-D-XP_Ccb.d.cts → client-3InDZbba.d.ts} +0 -1
  6. package/dist/{client-CEnNz8O7.mjs → client-5SIFzW3q.mjs} +113 -64
  7. package/dist/compat/mod.d.cts +1 -1
  8. package/dist/compat/mod.d.ts +1 -1
  9. package/dist/compat/transformers.test.mjs +1 -1
  10. package/dist/{compound-proof-D1djO5fa.mjs → compound-proof-cYtvlTgF.mjs} +2 -2
  11. package/dist/{context-8Tu9kea0.mjs → context-COHd1Rsh.mjs} +2 -0
  12. package/dist/{context-BdB54V-A.d.ts → context-DQJE9YfH.d.ts} +332 -6
  13. package/dist/{context-CQ9H8vNW.d.cts → context-DSuL3YWx.d.cts} +332 -6
  14. package/dist/{deno-eNpfj4oR.mjs → deno-iOAA7iRN.mjs} +1 -1
  15. package/dist/docloader-DCZkiTeF.mjs +136 -0
  16. package/dist/{exporter-DThFfe7P.mjs → exporter-DVG68ozH.mjs} +36 -30
  17. package/dist/federation/builder.test.mjs +1 -1
  18. package/dist/federation/compound-fanout.test.mjs +6 -3
  19. package/dist/federation/handler-compound-proof.test.mjs +5 -5
  20. package/dist/federation/handler.test.mjs +22 -7
  21. package/dist/federation/hashlink-media.test.mjs +2 -2
  22. package/dist/federation/idempotency.test.mjs +2 -2
  23. package/dist/federation/inbox-actorless.test.d.mts +2 -0
  24. package/dist/federation/inbox-actorless.test.mjs +487 -0
  25. package/dist/federation/inbox-authentication.test.d.mts +2 -0
  26. package/dist/federation/inbox-authentication.test.mjs +116 -0
  27. package/dist/federation/inbox-report.test.mjs +5 -5
  28. package/dist/federation/inbox-view.test.d.mts +2 -0
  29. package/dist/federation/inbox-view.test.mjs +369 -0
  30. package/dist/federation/inbox.test.mjs +22 -12
  31. package/dist/federation/metrics.test.mjs +1 -1
  32. package/dist/federation/middleware.test.mjs +470 -35
  33. package/dist/federation/mod.cjs +2 -1
  34. package/dist/federation/mod.d.cts +4 -4
  35. package/dist/federation/mod.d.ts +4 -4
  36. package/dist/federation/mod.js +8 -2
  37. package/dist/federation/mq.test.mjs +36 -1
  38. package/dist/federation/outgoing-proof.test.mjs +9 -6
  39. package/dist/federation/portable-actor.test.mjs +3 -3
  40. package/dist/federation/portable-chain.test.mjs +3 -3
  41. package/dist/federation/portable-collection.test.mjs +4 -4
  42. package/dist/federation/portable-delivery.test.mjs +2 -2
  43. package/dist/federation/portable-gateway-keys.test.mjs +13 -7
  44. package/dist/federation/portable-inbox.test.mjs +4 -4
  45. package/dist/federation/portable-parse-uri.test.mjs +1 -1
  46. package/dist/federation/portable-route-activity.test.mjs +2 -2
  47. package/dist/federation/portable.test.mjs +3 -3
  48. package/dist/federation/send.test.mjs +502 -93
  49. package/dist/federation/tasks/enqueue.test.mjs +3 -3
  50. package/dist/federation/tasks/tasks.test.mjs +4 -4
  51. package/dist/federation/temporal.test.mjs +1 -1
  52. package/dist/federation/webfinger.test.mjs +2 -2
  53. package/dist/{federation-BVH7drJA.cjs → federation-D0AZw_aw.cjs} +1415 -236
  54. package/dist/{http-BUJ5SFh6.mjs → http-BoJCMnjY.mjs} +204 -106
  55. package/dist/{http-DlNxxW_5.js → http-ChXUU_3c.js} +319 -123
  56. package/dist/{http-BfW3wyQ4.cjs → http-kv1LZw-r.cjs} +339 -125
  57. package/dist/inbox-BjihTKLo.mjs +312 -0
  58. package/dist/inbox-authentication-DflPYlLL.mjs +171 -0
  59. package/dist/inbox-view-D-skypg-.mjs +385 -0
  60. package/dist/{key-nYGY4QB9.d.cts → key-DbLNT-vA.d.ts} +1 -2
  61. package/dist/{key-DhsBxxZN.d.ts → key-DlHT4R6k.d.cts} +1 -2
  62. package/dist/{kv-cache-D_m3A241.mjs → kv-cache-Cmsyke4d.mjs} +1 -1
  63. package/dist/{kv-cache-7015lbrx.js → kv-cache-DQcte7ES.js} +73 -28
  64. package/dist/{kv-cache-kkBB0vbI.cjs → kv-cache-Ddh5sMxH.cjs} +72 -27
  65. package/dist/ld-CWVpo_NM.d.cts +250 -0
  66. package/dist/{ld-CD2CsPxq.mjs → ld-CdvcOEXQ.mjs} +52 -9
  67. package/dist/ld-Inagww4R.d.ts +250 -0
  68. package/dist/{metrics-D3LHk6Z4.mjs → metrics-CpxvUrBz.mjs} +1 -1
  69. package/dist/{middleware-N9eM16XE.js → middleware-BHb5toqA.js} +1413 -247
  70. package/dist/{middleware-CCDXvXOG.mjs → middleware-BKs2DLUF.mjs} +1 -1
  71. package/dist/{middleware-CzoWvrdZ.mjs → middleware-CoBLrTKX.mjs} +533 -132
  72. package/dist/{mod-B0dGgQsg.d.cts → mod-6TQ4UQZb.d.cts} +1 -1
  73. package/dist/mod-B4kBw1-8.d.ts +154 -0
  74. package/dist/{mod-DkhfZC1u.d.ts → mod-B7j30IQf.d.ts} +2 -9
  75. package/dist/mod-C1nT74IG.d.cts +154 -0
  76. package/dist/{mod-D0bxB8jS.d.ts → mod-CIeBgsOC.d.ts} +1 -1
  77. package/dist/{mod-B5-wdzmJ.d.cts → mod-YvA4Rk8J.d.cts} +2 -9
  78. package/dist/mod.cjs +6 -5
  79. package/dist/mod.d.cts +9 -9
  80. package/dist/mod.d.ts +9 -9
  81. package/dist/mod.js +6 -6
  82. package/dist/{mq-Dm1Wmtm-.mjs → mq-eF96QxUT.mjs} +6 -0
  83. package/dist/nodeinfo/client.test.mjs +337 -19
  84. package/dist/nodeinfo/handler.test.mjs +2 -2
  85. package/dist/nodeinfo/mod.cjs +1 -1
  86. package/dist/nodeinfo/mod.d.cts +1 -1
  87. package/dist/nodeinfo/mod.d.ts +1 -1
  88. package/dist/nodeinfo/mod.js +1 -1
  89. package/dist/otel/exporter.test.mjs +257 -1
  90. package/dist/otel/mod.cjs +36 -30
  91. package/dist/otel/mod.d.cts +13 -0
  92. package/dist/otel/mod.d.ts +13 -0
  93. package/dist/otel/mod.js +36 -30
  94. package/dist/{owner-C5-FVX6t.mjs → owner-DTnVpUKA.mjs} +3 -3
  95. package/dist/{portable-collection-Cony3_LC.mjs → portable-collection-CJeYTL61.mjs} +2 -2
  96. package/dist/{portable-collection-C-Z1SKDy.cjs → portable-collection-DciwBIia.cjs} +1 -1
  97. package/dist/{portable-collection-CC2zNAje.js → portable-collection-TmtpzD4E.js} +1 -1
  98. package/dist/{portable-key-DNc_flH-.mjs → portable-key-DcYok4ki.mjs} +1 -1
  99. package/dist/{proof-Cryb1c70.mjs → proof-GH7Poos_.mjs} +98 -10
  100. package/dist/{send-AF25pWaJ.mjs → send-BgGJh6pv.mjs} +174 -76
  101. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  102. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  103. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  104. package/dist/sig/compound-proof.test.mjs +2 -2
  105. package/dist/sig/http.test.mjs +553 -2
  106. package/dist/sig/key.test.mjs +1 -1
  107. package/dist/sig/ld.test.mjs +1 -1
  108. package/dist/sig/mitra-receive-interop.test.mjs +4 -4
  109. package/dist/sig/mitra-send-interop.test.mjs +3 -3
  110. package/dist/sig/mod.cjs +2 -2
  111. package/dist/sig/mod.d.cts +3 -3
  112. package/dist/sig/mod.d.ts +3 -3
  113. package/dist/sig/mod.js +2 -2
  114. package/dist/sig/owner.test.mjs +1 -1
  115. package/dist/sig/portable-collection.test.mjs +1 -1
  116. package/dist/sig/portable-interop.test.mjs +3 -3
  117. package/dist/sig/portable-key.test.mjs +5 -5
  118. package/dist/sig/proof.test.mjs +45 -5
  119. package/dist/sig/tootik-request-interop.test.mjs +4 -4
  120. package/dist/sig/tootik-send-interop.test.mjs +3 -3
  121. package/dist/sig/verification.test.mjs +3 -3
  122. package/dist/{temporal-BsAeuUJj.mjs → temporal-gJINzcL4.mjs} +1 -1
  123. package/dist/testing/kv.test.mjs +1 -1
  124. package/dist/testing/mod.d.mts +288 -2
  125. package/dist/testing/mod.mjs +2 -2
  126. package/dist/{testing-t8xDeJZ5.mjs → testing-Dbr21vZk.mjs} +1 -1
  127. package/dist/{types-_S2_MeLF.js → types-DUjZb4i6.js} +112 -63
  128. package/dist/{types-poIao40f.cjs → types-hKCCjii0.cjs} +111 -62
  129. package/dist/utils/docloader.test.mjs +344 -36
  130. package/dist/utils/kv-cache.test.mjs +1 -1
  131. package/dist/utils/mod.cjs +1 -1
  132. package/dist/utils/mod.d.cts +1 -1
  133. package/dist/utils/mod.d.ts +1 -1
  134. package/dist/utils/mod.js +1 -1
  135. package/package.json +7 -7
  136. package/dist/docloader-B-0nqOB1.mjs +0 -91
  137. package/dist/inbox-CHvMaIFX.mjs +0 -188
  138. package/dist/mod-BRpER-B0.d.ts +0 -320
  139. package/dist/mod-xAfaLS4T.d.cts +0 -320
  140. package/dist/owner-BF0L9cMt.d.cts +0 -78
  141. package/dist/owner-BSzr5-I8.d.ts +0 -78
@@ -3,34 +3,37 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { d as isPortableUri, f as isSameObjectId, i as getPortableDid, l as isPortableId, n as getCanonicalPortableId, o as hasPortableActor, r as getGatewayKeyBase, s as isCompatibleKeyId, t as getAuthenticationOrigin, u as isPortableKeyId } from "./portable-key-id-Ca30-hOa.mjs";
5
5
  import { n as isPubliclyAddressedNode, t as isInAudience } from "./audience-CHQ-FlLD.mjs";
6
+ import { i as getEmptyAuthenticationEvidence, n as deserializeAuthentication, t as createAuthenticationEvidence } from "./inbox-authentication-DflPYlLL.mjs";
6
7
  import { a as verificationObservation, r as snapshotKey, t as observeAttempt } from "./verification-Dpfcw8ml.mjs";
7
- import { n as version, t as name } from "./deno-eNpfj4oR.mjs";
8
- import { a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, n as getDurationMs, o as isAbortError, r as getFederationMetrics, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "./metrics-D3LHk6Z4.mjs";
8
+ import { n as version, t as name } from "./deno-iOAA7iRN.mjs";
9
+ import { a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, n as getDurationMs, o as isAbortError, r as getFederationMetrics, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "./metrics-CpxvUrBz.mjs";
9
10
  import { t as formatAcceptSignature } from "./accept-CPVqki78.mjs";
10
- import { T as validateCryptoKey, _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike, w as importJwk, y as exportJwk } from "./ld-CD2CsPxq.mjs";
11
+ import { r as getVerifiedKeyOwnerEvidence } from "./key-owner-evidence-APB6NpSk.mjs";
12
+ import { D as validateCryptoKey, E as importJwk, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, g as verifyCompactJsonLdDetailed, l as hasSignature, m as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike, x as exportJwk, y as wrapContextLoaderForJsonLd } from "./ld-CdvcOEXQ.mjs";
11
13
  import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-4IJqPYos.mjs";
12
- import { c as verifyObject, d as verifyPortableObjectProofWithRoot, i as hasProofLike, l as verifyPortableObjectProof, o as signObject, t as InvalidPortableObjectIdError } from "./proof-Cryb1c70.mjs";
13
- import { a as listRequestSignatures, c as selectRequestSignature, d as validateMaxSignatures, f as verifyRequest, p as verifyRequestDetailed, s as parseRfc9421SignatureInput } from "./http-BUJ5SFh6.mjs";
14
- import { t as getAuthenticatedDocumentLoader } from "./docloader-B-0nqOB1.mjs";
15
- import { n as kvCache } from "./kv-cache-D_m3A241.mjs";
16
- import { d as readBoundedText, l as BodyTooLargeError, t as getNodeInfo, u as MAX_BODY_SIZE } from "./client-CEnNz8O7.mjs";
14
+ import { a as hasProofLike, d as verifyPortableObjectProof, i as getProofSigner, l as verifyObject, p as verifyPortableObjectProofWithRoot, s as signObject, t as InvalidPortableObjectIdError, u as verifyObjectDetailed } from "./proof-GH7Poos_.mjs";
15
+ import { c as parseRfc9421SignatureInput, f as validateMaxSignatures, l as selectRequestSignature, m as verifyRequestDetailed, o as listRequestSignatures, p as verifyRequest } from "./http-BoJCMnjY.mjs";
16
+ import { n as getAuthenticatedDocumentLoader } from "./docloader-DCZkiTeF.mjs";
17
+ import { n as kvCache } from "./kv-cache-Cmsyke4d.mjs";
18
+ import { d as MAX_BODY_SIZE, f as readBoundedText, t as getNodeInfo, u as BodyTooLargeError } from "./client-5SIFzW3q.mjs";
17
19
  import { t as nodeInfoToJson } from "./types-DE_LV1JB.mjs";
18
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-C5-FVX6t.mjs";
19
- import { t as verifyPortableObject } from "./portable-collection-Cony3_LC.mjs";
20
- import { a as getOrderingDestination, i as sendActivityThroughGateways, n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-AF25pWaJ.mjs";
21
- import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-Da8b9O6v.mjs";
20
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-DTnVpUKA.mjs";
21
+ import { t as verifyPortableObject } from "./portable-collection-CJeYTL61.mjs";
22
+ import { a as sendActivityThroughGateways, i as sendActivity, n as extractInboxes, o as getOrderingDestination, t as SendActivityError } from "./send-BgGJh6pv.mjs";
23
+ import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-DphK9v7f.mjs";
22
24
  import { t as CircuitBreaker } from "./circuit-breaker-XJ53md4S.mjs";
23
25
  import { t as buildCollectionSynchronizationHeader } from "./collection-CnnP1UAv.mjs";
24
- import { a as inspectCompoundPortableObjectApplicability, c as verifyServedPortableObjects, i as findUnsupportedCompoundProofShape, o as verifyCompoundPortableObjectProofs, r as findEmbeddedProofWithoutContext, t as containsCompoundPortableObject } from "./compound-proof-D1djO5fa.mjs";
25
- import { n as routeActivity, t as actorsHaveSameOrigin } from "./inbox-CHvMaIFX.mjs";
26
+ import { a as inspectCompoundPortableObjectApplicability, c as verifyServedPortableObjects, i as findUnsupportedCompoundProofShape, o as verifyCompoundPortableObjectProofs, r as findEmbeddedProofWithoutContext, t as containsCompoundPortableObject } from "./compound-proof-cYtvlTgF.mjs";
27
+ import { a as isActorlessActivityAuthenticated, i as getInboxIdempotencyKey, n as checkActorlessActivity, o as isInboxActivityProcessed, s as routeActivity, t as actorsHaveSameOrigin } from "./inbox-BjihTKLo.mjs";
28
+ import { c as expandDocument, d as parseSerializedVerifiedActivityView, f as restoreVerifiedActivityView, i as createReleasableLoader, l as getActorPresence, n as buildVerifiedActivityView, o as deepFreeze, r as createContextSnapshot, t as ContextSnapshotMissError } from "./inbox-view-D-skypg-.mjs";
26
29
  import { t as KvKeyCache } from "./keycache-N2opu4-3.mjs";
27
30
  import { t as acceptsJsonLd } from "./negotiation-CCocWT_N.mjs";
28
- import { t as hasMalformedKnownTemporalLiteral } from "./temporal-BsAeuUJj.mjs";
31
+ import { t as hasMalformedKnownTemporalLiteral } from "./temporal-gJINzcL4.mjs";
29
32
  import { t as createExponentialBackoffPolicy } from "./retry-zX5xw5e0.mjs";
30
33
  import { t as TaskCodec } from "./codec-C6rTrpIp.mjs";
31
34
  import { getLogger, withContext } from "@logtape/logtape";
32
35
  import { RouterError } from "@fedify/uri-template";
33
- import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, Tombstone, getTypeId, isActor, lookupObject, traverseCollection } from "@fedify/vocab";
36
+ import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, Tombstone, getTypeId, isActor, lookupObject, lookupObserver, traverseCollection } from "@fedify/vocab";
34
37
  import { lookupWebFinger } from "@fedify/webfinger";
35
38
  import { SpanKind, SpanStatusCode, context, metrics, propagation, trace } from "@opentelemetry/api";
36
39
  import { FetchError, canonicalizePortableUri, decodeMultibase, formatIri, fromCompatibleEf61Id, getDocumentLoader, getFe34Origin, isGatewayUrl, parseDigestMultibase, parseHashlink, parseIri, resolveDocumentLoaderTimeout, toCompatibleEf61Id } from "@fedify/vocab-runtime";
@@ -1568,13 +1571,13 @@ function recordCollectionMetrics(meterProvider, base, result, options = {}) {
1568
1571
  * @param parameters The parameters for handling the collection.
1569
1572
  * @returns A promise that resolves to an HTTP response.
1570
1573
  */
1571
- async function handleCollection(request, { name: name$2, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, portable, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
1572
- const spanName = name$2.trim().replace(/\s+/g, "_");
1574
+ async function handleCollection(request, { name: name$1, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, portable, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
1575
+ const spanName = name$1.trim().replace(/\s+/g, "_");
1573
1576
  tracerProvider = tracerProvider ?? trace.getTracerProvider();
1574
1577
  const tracer = tracerProvider.getTracer(name, version);
1575
1578
  const cursor = new URL(request.url).searchParams.get("cursor");
1576
1579
  const metricBase = {
1577
- kind: getCollectionMetricKind(name$2),
1580
+ kind: getCollectionMetricKind(name$1),
1578
1581
  page: cursor != null,
1579
1582
  dispatcher: "built_in"
1580
1583
  };
@@ -1620,7 +1623,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
1620
1623
  span.setStatus({ code: SpanStatusCode.ERROR });
1621
1624
  return await onNotFound(request);
1622
1625
  }
1623
- const items = filterCollectionItems(page.items, name$2, filterPredicate);
1626
+ const items = filterCollectionItems(page.items, name$1, filterPredicate);
1624
1627
  itemCount = items.length;
1625
1628
  span.setAttribute("fedify.collection.items", itemCount);
1626
1629
  return items;
@@ -1662,7 +1665,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
1662
1665
  } else {
1663
1666
  const uri = new URL(portable == null ? baseUri : pageBase);
1664
1667
  uri.searchParams.set("cursor", cursor);
1665
- const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$2}`, {
1668
+ const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
1666
1669
  kind: SpanKind.SERVER,
1667
1670
  attributes: {
1668
1671
  "activitypub.collection.id": uri.href,
@@ -1678,7 +1681,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
1678
1681
  span.setStatus({ code: SpanStatusCode.ERROR });
1679
1682
  return await onNotFound(request);
1680
1683
  }
1681
- const items = filterCollectionItems(page.items, name$2, filterPredicate);
1684
+ const items = filterCollectionItems(page.items, name$1, filterPredicate);
1682
1685
  itemCount = items.length;
1683
1686
  span.setAttribute("fedify.collection.items", itemCount);
1684
1687
  return {
@@ -2175,11 +2178,12 @@ async function handleInbox(request, options) {
2175
2178
  }, async (span) => {
2176
2179
  if (options.recipient != null) span.setAttribute("fedify.inbox.recipient", options.recipient);
2177
2180
  const spanContext = span.spanContext();
2181
+ const snapshot = createContextSnapshot(options.context.contextLoader);
2178
2182
  try {
2179
2183
  return await withContext({
2180
2184
  traceId: spanContext.traceId,
2181
2185
  spanId: spanContext.spanId
2182
- }, () => handleInboxInternal(request, options, span));
2186
+ }, () => handleInboxInternal(request, options, span, snapshot));
2183
2187
  } catch (e) {
2184
2188
  options.observation.hasException = true;
2185
2189
  span.setStatus({
@@ -2188,6 +2192,7 @@ async function handleInbox(request, options) {
2188
2192
  });
2189
2193
  throw e;
2190
2194
  } finally {
2195
+ snapshot.release();
2191
2196
  options.observation.project(span);
2192
2197
  span.end();
2193
2198
  }
@@ -2199,9 +2204,10 @@ async function handleInbox(request, options) {
2199
2204
  * @param request The HTTP request.
2200
2205
  * @param options The parameters for handling the inbox.
2201
2206
  * @param span The OpenTelemetry span for tracing.
2207
+ * @param snapshot The context snapshot of the delivery.
2202
2208
  * @returns A promise that resolves to an HTTP response.
2203
2209
  */
2204
- async function handleInboxInternal(request, parameters, span) {
2210
+ async function handleInboxInternal(request, parameters, span, snapshot) {
2205
2211
  const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, publicKeyTtl, queue, actorDispatcher, inboxListeners, inboxErrorHandler, unverifiedActivityHandler, onNotFound, signatureTimeWindow, maxHttpSignatures, skipSignatureVerification, inboxChallengePolicy, meterProvider, tracerProvider, portableInbox } = parameters;
2206
2212
  const observation = parameters.observation;
2207
2213
  const signatureObservation = { [verificationObservation]: observation.verification };
@@ -2315,6 +2321,8 @@ async function handleInboxInternal(request, parameters, span) {
2315
2321
  tracerProvider,
2316
2322
  keyTtl: publicKeyTtl
2317
2323
  });
2324
+ const standardLoader = snapshot.loader("standard");
2325
+ const normalizationLoader = snapshot.loader("normalization");
2318
2326
  const jsonWithoutSig = detachSignature(json);
2319
2327
  const hasLdSignature = hasSignature(json);
2320
2328
  const canAttemptAlternateAuthAfterLdSignatureFailure = skipSignatureVerification || hasHttpSignatureHeaders(request) || hasObjectIntegrityProof(jsonWithoutSig);
@@ -2350,9 +2358,10 @@ async function handleInboxInternal(request, parameters, span) {
2350
2358
  let compactedJson = json;
2351
2359
  let compactedJsonWithoutSig = jsonWithoutSig;
2352
2360
  let ldSigVerified = false;
2361
+ let ldSigKey = null;
2353
2362
  if (hasLdSignature) {
2354
2363
  try {
2355
- compactedJson = await compactJsonLd(json, ctx.contextLoader);
2364
+ compactedJson = await compactJsonLd(json, normalizationLoader);
2356
2365
  } catch (error) {
2357
2366
  if (isInvalidJsonLdError(error)) {
2358
2367
  logger.error("Failed to parse JSON-LD:\n{error}", {
@@ -2388,16 +2397,18 @@ async function handleInboxInternal(request, parameters, span) {
2388
2397
  if (compactedJson !== json) {
2389
2398
  compactedJsonWithoutSig = detachSignature(compactedJson);
2390
2399
  try {
2391
- ldSigVerified = await verifyCompactJsonLd(compactedJson, {
2400
+ const ldResult = await verifyCompactJsonLdDetailed(compactedJson, {
2392
2401
  ...signatureObservation,
2393
- contextLoader: ctx.contextLoader,
2402
+ contextLoader: normalizationLoader,
2394
2403
  documentLoader: ctx.documentLoader,
2395
2404
  keyCache,
2396
2405
  meterProvider,
2397
2406
  tracerProvider
2398
2407
  });
2408
+ ldSigVerified = ldResult.verified;
2409
+ ldSigKey = ldResult.key;
2399
2410
  } catch (error) {
2400
- if (error instanceof RangeError && await hasMalformedKnownTemporalLiteral(compactedJsonWithoutSig, ctx.contextLoader)) return await respondInvalidActivity(error);
2411
+ if (error instanceof RangeError && await hasMalformedKnownTemporalLiteral(compactedJsonWithoutSig, normalizationLoader)) return await respondInvalidActivity(error);
2401
2412
  if (isInvalidJsonLdError(error)) {
2402
2413
  logger.error("Failed to parse JSON-LD:\n{error}", {
2403
2414
  recipient,
@@ -2415,12 +2426,12 @@ async function handleInboxInternal(request, parameters, span) {
2415
2426
  if (!canAttemptAlternateAuthAfterLdSignatureFailure) throw error;
2416
2427
  if (!skipSignatureVerification) try {
2417
2428
  await Object$1.fromJsonLd(compactedJson, {
2418
- contextLoader: getNormalizationContextLoader(ctx.contextLoader),
2429
+ contextLoader: normalizationLoader,
2419
2430
  documentLoader: ctx.documentLoader,
2420
2431
  tracerProvider
2421
2432
  });
2422
2433
  } catch (parseError) {
2423
- if (parseError instanceof RangeError && await hasMalformedKnownTemporalLiteral(compactedJsonWithoutSig, ctx.contextLoader)) return await respondInvalidActivity(parseError);
2434
+ if (parseError instanceof RangeError && await hasMalformedKnownTemporalLiteral(compactedJsonWithoutSig, normalizationLoader)) return await respondInvalidActivity(parseError);
2424
2435
  if (isInvalidJsonLdError(parseError)) {
2425
2436
  logger.error("Failed to parse JSON-LD:\n{error}", {
2426
2437
  recipient,
@@ -2444,6 +2455,33 @@ async function handleInboxInternal(request, parameters, span) {
2444
2455
  let activity = null;
2445
2456
  let activityVerified = false;
2446
2457
  let proofVerified = false;
2458
+ let documentSigners = [];
2459
+ let requestSigners = [];
2460
+ let viewSource;
2461
+ const rawViewSource = {
2462
+ policy: "standard",
2463
+ source: "activity",
2464
+ document: jsonWithoutSig,
2465
+ baseUrl: null
2466
+ };
2467
+ const isActorlessCandidate = async (candidate, source) => {
2468
+ if (skipSignatureVerification) return false;
2469
+ if (inboxListeners?.dispatchWithClass(candidate)?.options.allowActorless !== true) return false;
2470
+ try {
2471
+ return getActorPresence(await expandDocument(source.document, snapshot.loader(source.policy))) === "absent";
2472
+ } catch {
2473
+ return false;
2474
+ }
2475
+ };
2476
+ const verifyProofs = (contextLoader = standardLoader) => verifyObjectDetailed(Activity, jsonWithoutSig, {
2477
+ ...signatureObservation,
2478
+ contextLoader,
2479
+ documentLoader: ctx.documentLoader,
2480
+ keyCache,
2481
+ meterProvider,
2482
+ tracerProvider,
2483
+ verifyPortableObject: ctx.verifyPortableObject
2484
+ });
2447
2485
  if (ldSigVerified) {
2448
2486
  logger.debug("Linked Data Signatures are verified.", {
2449
2487
  recipient,
@@ -2452,18 +2490,49 @@ async function handleInboxInternal(request, parameters, span) {
2452
2490
  try {
2453
2491
  activity = observation.activity = await Activity.fromJsonLd(compactedJsonWithoutSig, {
2454
2492
  ...ctx,
2455
- contextLoader: getNormalizationContextLoader(ctx.contextLoader)
2493
+ contextLoader: normalizationLoader
2456
2494
  });
2457
2495
  } catch (error) {
2458
- if (error instanceof RangeError && await hasMalformedKnownTemporalLiteral(compactedJsonWithoutSig, ctx.contextLoader)) return await respondInvalidActivity(error);
2496
+ if (error instanceof RangeError && await hasMalformedKnownTemporalLiteral(compactedJsonWithoutSig, normalizationLoader)) return await respondInvalidActivity(error);
2459
2497
  if (!isPermanentActivityParseError(error)) throw error;
2460
2498
  return await respondInvalidActivity(error);
2461
2499
  }
2462
2500
  activityVerified = true;
2501
+ viewSource = {
2502
+ policy: "normalization",
2503
+ source: "normalizedActivity",
2504
+ document: compactedJsonWithoutSig,
2505
+ baseUrl: null
2506
+ };
2507
+ if (ldSigKey?.ownerId != null) documentSigners = [{
2508
+ kind: "actor",
2509
+ id: ldSigKey.ownerId,
2510
+ mechanism: "linkedDataSignatures",
2511
+ keyId: ldSigKey.id
2512
+ }];
2513
+ if (await isActorlessCandidate(activity, viewSource)) {
2514
+ let result = null;
2515
+ try {
2516
+ result = await verifyProofs();
2517
+ } catch (error) {
2518
+ if (!isPermanentActivityParseError(error)) throw error;
2519
+ logger.debug("Failed to verify the Object Integrity Proofs of the activity without an actor:\n{error}", {
2520
+ recipient,
2521
+ error
2522
+ });
2523
+ }
2524
+ if (result?.status === "unavailable") throw result.error;
2525
+ if (result?.status === "verified" && result.signers.length > 0) {
2526
+ activity = observation.activity = result.object;
2527
+ documentSigners = toProofPrincipals(result.signers);
2528
+ viewSource = rawViewSource;
2529
+ proofVerified = true;
2530
+ }
2531
+ }
2463
2532
  if (!skipSignatureVerification && isPortableActivity(activity)) try {
2464
2533
  proofVerified = await verifyObject(Activity, jsonWithoutSig, {
2465
2534
  ...signatureObservation,
2466
- contextLoader: wrapContextLoaderForJsonLd(ctx.contextLoader),
2535
+ contextLoader: standardLoader,
2467
2536
  documentLoader: ctx.documentLoader,
2468
2537
  keyCache,
2469
2538
  meterProvider,
@@ -2481,18 +2550,11 @@ async function handleInboxInternal(request, parameters, span) {
2481
2550
  recipient,
2482
2551
  json
2483
2552
  });
2553
+ let proofResult;
2484
2554
  try {
2485
- activity = await verifyObject(Activity, jsonWithoutSig, {
2486
- ...signatureObservation,
2487
- contextLoader: wrapContextLoaderForJsonLd(ctx.contextLoader),
2488
- documentLoader: ctx.documentLoader,
2489
- keyCache,
2490
- meterProvider,
2491
- tracerProvider,
2492
- verifyPortableObject: ctx.verifyPortableObject
2493
- });
2555
+ proofResult = await verifyProofs();
2494
2556
  } catch (error) {
2495
- if (error instanceof RangeError && await hasMalformedKnownTemporalLiteral(jsonWithoutSig, ctx.contextLoader)) return await respondInvalidActivity(error);
2557
+ if (error instanceof RangeError && await hasMalformedKnownTemporalLiteral(jsonWithoutSig, standardLoader)) return await respondInvalidActivity(error);
2496
2558
  if (deferredLdSignatureError != null) {
2497
2559
  logger.debug("Object Integrity Proof fallback did not supersede a deferred Linked Data Signature failure:\n{error}", {
2498
2560
  recipient,
@@ -2528,6 +2590,22 @@ async function handleInboxInternal(request, parameters, span) {
2528
2590
  headers: { "Content-Type": "text/plain; charset=utf-8" }
2529
2591
  });
2530
2592
  }
2593
+ if (proofResult.status === "verified") if (proofResult.signers.length < 1 && await isActorlessCandidate(proofResult.object, rawViewSource)) activity = null;
2594
+ else {
2595
+ activity = proofResult.object;
2596
+ documentSigners = toProofPrincipals(proofResult.signers);
2597
+ viewSource = rawViewSource;
2598
+ }
2599
+ else if (proofResult.status === "unavailable") {
2600
+ let parsed = null;
2601
+ try {
2602
+ parsed = await Activity.fromJsonLd(jsonWithoutSig, {
2603
+ ...ctx,
2604
+ contextLoader: standardLoader
2605
+ });
2606
+ } catch {}
2607
+ if (parsed != null && await isActorlessCandidate(parsed, rawViewSource)) throw proofResult.error;
2608
+ }
2531
2609
  if (activity == null) logger.debug("Object Integrity Proofs are not verified.", {
2532
2610
  recipient,
2533
2611
  activity: json
@@ -2657,14 +2735,28 @@ async function handleInboxInternal(request, parameters, span) {
2657
2735
  try {
2658
2736
  activity = observation.activity = await Activity.fromJsonLd(jsonWithoutSig, {
2659
2737
  ...ctx,
2660
- contextLoader: wrapContextLoaderForJsonLd(ctx.contextLoader)
2738
+ contextLoader: standardLoader
2661
2739
  });
2662
2740
  } catch (error) {
2663
2741
  if (!isPermanentActivityParseError(error)) throw error;
2664
2742
  return await respondInvalidActivity(error);
2665
2743
  }
2744
+ viewSource = rawViewSource;
2666
2745
  }
2667
2746
  observation.activity = activity;
2747
+ let view;
2748
+ try {
2749
+ view = await buildVerifiedActivityView(snapshot, viewSource ?? rawViewSource);
2750
+ } catch (error) {
2751
+ if (!isPermanentActivityParseError(error)) throw error;
2752
+ return await respondInvalidActivity(error);
2753
+ }
2754
+ const actorless = !skipSignatureVerification && getActorPresence(view.expanded) === "absent" && inboxListeners?.dispatchWithClass(activity)?.options.allowActorless === true;
2755
+ span.setAttribute("activitypub.activity.actorless", actorless);
2756
+ if (actorless && httpSigKey != null) {
2757
+ const principal = getHttpKeyPrincipal(httpSigKey);
2758
+ if (principal != null) requestSigners = [principal];
2759
+ }
2668
2760
  observation.stage = "policy";
2669
2761
  observation.result = {
2670
2762
  disposition: "rejected",
@@ -2708,7 +2800,7 @@ async function handleInboxInternal(request, parameters, span) {
2708
2800
  const rejection = await observeAttempt(signatureObservation, "objectIntegrity", async (verification) => {
2709
2801
  const rejection = await verifyPortableActivityId(activity.id, jsonWithoutSig, {
2710
2802
  [verificationObservation]: verification,
2711
- contextLoader: wrapContextLoaderForJsonLd(ctx.contextLoader),
2803
+ contextLoader: standardLoader,
2712
2804
  documentLoader: ctx.documentLoader,
2713
2805
  keyCache,
2714
2806
  meterProvider,
@@ -2746,7 +2838,7 @@ async function handleInboxInternal(request, parameters, span) {
2746
2838
  });
2747
2839
  }
2748
2840
  }
2749
- if (httpSigKey != null && !await doesActorOwnKey(activity, httpSigKey, ctx)) {
2841
+ if (httpSigKey != null && !actorless && !await doesActorOwnKey(activity, httpSigKey, ctx)) {
2750
2842
  if (deferredLdSignatureError != null) throw deferredLdSignatureError;
2751
2843
  observation.authentication = {
2752
2844
  status: "rejected",
@@ -2772,6 +2864,66 @@ async function handleInboxInternal(request, parameters, span) {
2772
2864
  headers: { "Content-Type": "text/plain; charset=utf-8" }
2773
2865
  });
2774
2866
  }
2867
+ if (httpSigKey != null && !actorless && activity.actorId != null) requestSigners = [{
2868
+ kind: "actor",
2869
+ id: activity.actorId,
2870
+ mechanism: "httpSignatures",
2871
+ keyId: httpSigKey.id
2872
+ }];
2873
+ if (actorless) {
2874
+ const check = checkActorlessActivity(activity, {
2875
+ verified: true,
2876
+ requestSigners,
2877
+ documentSigners,
2878
+ originAuthenticated: [],
2879
+ expandedActivity: [],
2880
+ baseUrl: null
2881
+ });
2882
+ if (check.status === "noAuthenticatedPrincipal") {
2883
+ if (deferredLdSignatureError != null) throw deferredLdSignatureError;
2884
+ observation.authentication = {
2885
+ status: "rejected",
2886
+ reason: { type: "noAuthenticatedPrincipal" }
2887
+ };
2888
+ logger.error("The activity {activityId} declares no actor, and no principal is authenticated for it.", {
2889
+ activity: json,
2890
+ recipient,
2891
+ activityId: activity.id?.href
2892
+ });
2893
+ span.setStatus({
2894
+ code: SpanStatusCode.ERROR,
2895
+ message: "No principal is authenticated for the activity."
2896
+ });
2897
+ return new Response("No principal is authenticated for the activity.", {
2898
+ status: 401,
2899
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
2900
+ });
2901
+ } else if (check.status === "activityOriginMismatch") {
2902
+ if (deferredLdSignatureError != null) throw deferredLdSignatureError;
2903
+ observation.authentication = {
2904
+ status: "rejected",
2905
+ reason: {
2906
+ type: "activityOriginMismatch",
2907
+ activityId: new URL(activity.id.href),
2908
+ actorIds: check.principals.map((principal) => principal.id)
2909
+ }
2910
+ };
2911
+ logger.error("The activity ({activityId}) does not have the same origin as the principals that authenticated it.", {
2912
+ activity: json,
2913
+ recipient,
2914
+ activityId: activity.id?.href,
2915
+ principals: check.principals.map((principal) => principal.id.href)
2916
+ });
2917
+ span.setStatus({
2918
+ code: SpanStatusCode.ERROR,
2919
+ message: `The activity (${activity.id?.href}) does not have the same origin as the principals that authenticated it.`
2920
+ });
2921
+ return new Response("The activity and its signers do not have the same origin.", {
2922
+ status: 401,
2923
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
2924
+ });
2925
+ }
2926
+ }
2775
2927
  if (!skipSignatureVerification) {
2776
2928
  const compoundJson = Array.isArray(json) ? json : jsonWithoutSig;
2777
2929
  if (inspectCompoundPortableObjectApplicability(compoundJson, INBOX_COMPOUND_PROOF_LIMITS) !== "absent") {
@@ -2831,7 +2983,7 @@ async function handleInboxInternal(request, parameters, span) {
2831
2983
  return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
2832
2984
  }
2833
2985
  }
2834
- if (!skipSignatureVerification && activity.id != null && !actorsHaveSameOrigin(activity)) {
2986
+ if (!skipSignatureVerification && !actorless && activity.id != null && !actorsHaveSameOrigin(activity)) {
2835
2987
  observation.authentication = {
2836
2988
  status: "rejected",
2837
2989
  reason: {
@@ -2860,7 +3012,7 @@ async function handleInboxInternal(request, parameters, span) {
2860
3012
  attempts: observation.verification.attempts.filter((attempt) => attempt.status === "verified")
2861
3013
  };
2862
3014
  observation.stage = "dispatch";
2863
- if (activity.actorId == null) {
3015
+ if (!actorless && activity.actorId == null) {
2864
3016
  observation.result = {
2865
3017
  disposition: "rejected",
2866
3018
  reason: "missingActor"
@@ -2884,6 +3036,17 @@ async function handleInboxInternal(request, parameters, span) {
2884
3036
  originalJson: json,
2885
3037
  normalizedActivity: hasLdSignature && compactedJson !== json ? compactedJson : void 0,
2886
3038
  ldSignatureVerified: hasLdSignature ? ldSigVerified : void 0,
3039
+ authentication: createAuthenticationEvidence({
3040
+ verified: !skipSignatureVerification,
3041
+ requestSigners,
3042
+ documentSigners,
3043
+ originAuthenticated: [],
3044
+ expandedActivity: deepFreeze(view.expanded),
3045
+ baseUrl: null
3046
+ }),
3047
+ verifiedView: view.view,
3048
+ replayable: view.replayable,
3049
+ actorless,
2887
3050
  activity,
2888
3051
  recipient,
2889
3052
  inboxListeners,
@@ -3098,8 +3261,8 @@ var CustomCollectionHandler = class {
3098
3261
  * @param CollectionPage The CollectionPage constructor.
3099
3262
  * @param filterPredicate Optional filter predicate for items.
3100
3263
  */
3101
- constructor(name$1, values, context, callbacks, tracerProvider = trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate, portable) {
3102
- this.name = name$1;
3264
+ constructor(name$2, values, context, callbacks, tracerProvider = trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate, portable) {
3265
+ this.name = name$2;
3103
3266
  this.values = values;
3104
3267
  this.context = context;
3105
3268
  this.callbacks = callbacks;
@@ -3608,6 +3771,42 @@ const MIN_COMPONENTS = [
3608
3771
  "@authority"
3609
3772
  ];
3610
3773
  /**
3774
+ * Turns the signers of verified Object Integrity Proofs into principals.
3775
+ */
3776
+ function toProofPrincipals(signers) {
3777
+ return signers.map((signer) => ({
3778
+ kind: signer.kind,
3779
+ id: signer.id,
3780
+ mechanism: "objectIntegrityProofs",
3781
+ keyId: signer.keyId
3782
+ }));
3783
+ }
3784
+ /**
3785
+ * Gets the principal of an HTTP Signature key, whose owner was confirmed by
3786
+ * the owner's own document, or by the signed document of a portable actor,
3787
+ * when the key was fetched.
3788
+ */
3789
+ function getHttpKeyPrincipal(key) {
3790
+ const evidence = getVerifiedKeyOwnerEvidence(key);
3791
+ if (evidence != null) try {
3792
+ return {
3793
+ kind: "actor",
3794
+ id: parseIri(evidence.ownerId),
3795
+ mechanism: "httpSignatures",
3796
+ keyId: key.id
3797
+ };
3798
+ } catch {
3799
+ return null;
3800
+ }
3801
+ if (key.ownerId == null || isPortableId(key.ownerId)) return null;
3802
+ return {
3803
+ kind: "actor",
3804
+ id: key.ownerId,
3805
+ mechanism: "httpSignatures",
3806
+ keyId: key.id
3807
+ };
3808
+ }
3809
+ /**
3611
3810
  * Checks whether an HTTP Signature key is a key of an FEP-ef61 portable
3612
3811
  * actor, i.e., its ID is a compatible identifier or an `ap:` or `ap+ef61:`
3613
3812
  * URI, and it is owned by a portable actor, which only the portable actor's
@@ -5699,24 +5898,102 @@ var FederationImpl = class extends FederationBuilderImpl {
5699
5898
  let dispatched;
5700
5899
  let parseInput = void 0;
5701
5900
  let parseContextLoader = context.contextLoader;
5901
+ let authentication = getEmptyAuthenticationEvidence();
5902
+ let actorPresence = "present";
5903
+ if (message.verifiedView !== void 0) {
5904
+ const view = parseSerializedVerifiedActivityView(message.verifiedView);
5905
+ let restored;
5906
+ let restoredAuthentication = null;
5907
+ let failure;
5908
+ if (view == null) failure = /* @__PURE__ */ new TypeError("The queued activity has a malformed verified view.");
5909
+ else try {
5910
+ if (view.source === "normalizedActivity") assertSafeJsonLd(message.normalizedActivity);
5911
+ restored = await restoreVerifiedActivityView(view, message);
5912
+ } catch (error) {
5913
+ if (!(error instanceof ContextSnapshotMissError) && !isPermanentInboxParseError(error)) {
5914
+ await handleRetriableFailure(error);
5915
+ return;
5916
+ }
5917
+ failure = error;
5918
+ }
5919
+ if (restored != null) {
5920
+ const expandedActivity = deepFreeze(restored.expanded);
5921
+ restoredAuthentication = message.authentication === void 0 ? createAuthenticationEvidence({
5922
+ ...getEmptyAuthenticationEvidence(),
5923
+ expandedActivity,
5924
+ baseUrl: restored.baseUrl
5925
+ }) : deserializeAuthentication(message.authentication, expandedActivity, restored.baseUrl);
5926
+ if (restoredAuthentication == null) failure = /* @__PURE__ */ new TypeError("The queued activity has malformed authentication evidence.");
5927
+ }
5928
+ if (failure != null || restored == null || restoredAuthentication == null) {
5929
+ await reportInboxError(failure);
5930
+ logger.error("Failed to replay the queued incoming activity:\n{error}", {
5931
+ error: failure,
5932
+ trial: message.attempt,
5933
+ activity: message.activity,
5934
+ recipient: message.identifier
5935
+ });
5936
+ listenerSpan.setStatus({
5937
+ code: SpanStatusCode.ERROR,
5938
+ message: String(failure)
5939
+ });
5940
+ listenerSpan.end();
5941
+ return;
5942
+ }
5943
+ authentication = restoredAuthentication;
5944
+ actorPresence = getActorPresence(restored.expanded);
5945
+ const policy = view.policy;
5946
+ const replayLoader = createReleasableLoader(restored.loader, policy === "normalization" ? getNormalizationContextLoader(context.contextLoader) : wrapContextLoaderForJsonLd(context.contextLoader), policy);
5947
+ parseInput = restored.document;
5948
+ parseContextLoader = restored.loader;
5949
+ try {
5950
+ activity = await Activity.fromJsonLd(restored.document, {
5951
+ ...context,
5952
+ contextLoader: replayLoader.loader,
5953
+ ...restored.baseUrl == null ? {} : { baseUrl: restored.baseUrl }
5954
+ });
5955
+ } catch (error) {
5956
+ if (isPermanentInboxParseError(error)) {
5957
+ await reportInboxError(error);
5958
+ logger.error("Failed to parse the queued incoming activity:\n{error}", {
5959
+ error,
5960
+ trial: message.attempt,
5961
+ activity: message.activity,
5962
+ recipient: message.identifier
5963
+ });
5964
+ listenerSpan.setStatus({
5965
+ code: SpanStatusCode.ERROR,
5966
+ message: String(error)
5967
+ });
5968
+ listenerSpan.end();
5969
+ return;
5970
+ }
5971
+ await handleRetriableFailure(error);
5972
+ return;
5973
+ } finally {
5974
+ replayLoader.release();
5975
+ }
5976
+ }
5702
5977
  try {
5703
- const hasSignatureField = hasSignature(message.activity);
5704
- const shouldParseFromNormalizedSignedPayload = message.ldSignatureVerified === true || message.normalizedActivity != null || message.ldSignatureVerified == null && hasSignatureField;
5705
- const parseContext = hasSignatureField ? {
5706
- ...context,
5707
- contextLoader: getNormalizationContextLoader(context.contextLoader)
5708
- } : {
5709
- ...context,
5710
- contextLoader: wrapContextLoaderForJsonLd(context.contextLoader)
5711
- };
5712
- parseContextLoader = parseContext.contextLoader;
5713
- let normalizedActivity;
5714
- if (shouldParseFromNormalizedSignedPayload) {
5715
- normalizedActivity = message.normalizedActivity ?? await compactJsonLd(message.activity, context.contextLoader);
5716
- assertSafeJsonLd(normalizedActivity);
5978
+ if (activity == null) {
5979
+ const hasSignatureField = hasSignature(message.activity);
5980
+ const shouldParseFromNormalizedSignedPayload = message.ldSignatureVerified === true || message.normalizedActivity != null || message.ldSignatureVerified == null && hasSignatureField;
5981
+ const parseContext = hasSignatureField ? {
5982
+ ...context,
5983
+ contextLoader: getNormalizationContextLoader(context.contextLoader)
5984
+ } : {
5985
+ ...context,
5986
+ contextLoader: wrapContextLoaderForJsonLd(context.contextLoader)
5987
+ };
5988
+ parseContextLoader = parseContext.contextLoader;
5989
+ let normalizedActivity;
5990
+ if (shouldParseFromNormalizedSignedPayload) {
5991
+ normalizedActivity = message.normalizedActivity ?? await compactJsonLd(message.activity, context.contextLoader);
5992
+ assertSafeJsonLd(normalizedActivity);
5993
+ }
5994
+ parseInput = shouldParseFromNormalizedSignedPayload ? detachSignature(normalizedActivity) : hasSignatureField ? detachSignature(message.activity) : message.activity;
5995
+ activity = await Activity.fromJsonLd(parseInput, parseContext);
5717
5996
  }
5718
- parseInput = shouldParseFromNormalizedSignedPayload ? detachSignature(normalizedActivity) : hasSignatureField ? detachSignature(message.activity) : message.activity;
5719
- activity = await Activity.fromJsonLd(parseInput, parseContext);
5720
5997
  activityType = getTypeId(activity).href;
5721
5998
  span.setAttribute("activitypub.activity.type", activityType);
5722
5999
  listenerSpan.setAttribute("activitypub.activity.type", activityType);
@@ -5725,7 +6002,8 @@ var FederationImpl = class extends FederationBuilderImpl {
5725
6002
  span.setAttribute("activitypub.activity.id", activity.id.href);
5726
6003
  listenerSpan.setAttribute("activitypub.activity.id", activity.id.href);
5727
6004
  }
5728
- if (activity.actorId == null) {
6005
+ const actorless = actorPresence === "absent" && !this.skipSignatureVerification && authentication.verified && this.inboxListeners?.dispatchWithClass(activity)?.options.allowActorless === true && isActorlessActivityAuthenticated(activity, authentication);
6006
+ if (activity.actorId == null && !actorless) {
5729
6007
  logger.error("Missing actor in queued incoming activity.", {
5730
6008
  activityId: activity.id?.href,
5731
6009
  activity: message.activity,
@@ -5739,7 +6017,7 @@ var FederationImpl = class extends FederationBuilderImpl {
5739
6017
  listenerSpan.end();
5740
6018
  return;
5741
6019
  }
5742
- if (!this.skipSignatureVerification && activity.id != null && !actorsHaveSameOrigin(activity)) {
6020
+ if (!this.skipSignatureVerification && !actorless && activity.id != null && !actorsHaveSameOrigin(activity)) {
5743
6021
  logger.error("The queued activity ({activityId}) and its actors do not have the same origin.", {
5744
6022
  activityId: activity.id.href,
5745
6023
  actorIds: activity.actorIds.map((actor) => actor.href),
@@ -5754,22 +6032,18 @@ var FederationImpl = class extends FederationBuilderImpl {
5754
6032
  listenerSpan.end();
5755
6033
  return;
5756
6034
  }
5757
- cacheKey = activity.id == null ? null : [
5758
- ...this.kvPrefixes.activityIdempotence,
5759
- context.origin,
5760
- activity.id.href
5761
- ];
5762
- if (cacheKey != null) {
5763
- if (await this.kv.get(cacheKey) === true) {
5764
- logger.debug("Activity {activityId} has already been processed.", {
5765
- activityId: activity.id?.href,
5766
- activity: message.activity,
5767
- recipient: message.identifier
5768
- });
5769
- recordInboxActivity(this.meterProvider, "rejected", activityType);
5770
- listenerSpan.end();
5771
- return;
5772
- }
6035
+ const parsedActivity = activity;
6036
+ const parsedActivityType = activityType;
6037
+ cacheKey = await getInboxIdempotencyKey(this.idempotencyStrategy, () => context.toInboxContext(message.identifier, message.activity, parsedActivity.id?.href, parsedActivityType, { authentication }), activity, context.origin, message.identifier, this.kvPrefixes.activityIdempotence);
6038
+ if (await isInboxActivityProcessed(this.kv, cacheKey, activity, context.origin, this.kvPrefixes.activityIdempotence)) {
6039
+ logger.debug("Activity {activityId} has already been processed.", {
6040
+ activityId: activity.id?.href,
6041
+ activity: message.activity,
6042
+ recipient: message.identifier
6043
+ });
6044
+ recordInboxActivity(this.meterProvider, "rejected", activityType);
6045
+ listenerSpan.end();
6046
+ return;
5773
6047
  }
5774
6048
  dispatched = this.inboxListeners?.dispatchWithClass(activity);
5775
6049
  } catch (error) {
@@ -5828,7 +6102,7 @@ var FederationImpl = class extends FederationBuilderImpl {
5828
6102
  try {
5829
6103
  const started = performance.now();
5830
6104
  try {
5831
- await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, activityType), activity);
6105
+ await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, activityType, { authentication }), activity);
5832
6106
  } finally {
5833
6107
  this.metrics.recordInboxProcessingDuration(activityType, getDurationMs(started));
5834
6108
  }
@@ -6230,7 +6504,7 @@ var FederationImpl = class extends FederationBuilderImpl {
6230
6504
  onNotAcceptable ??= notAcceptable;
6231
6505
  onUnauthorized ??= unauthorized;
6232
6506
  const url = new URL(request.url);
6233
- const route = this.router.route(url.pathname);
6507
+ const route = this.router.route(url.pathname, { allowUnencodedColon: true });
6234
6508
  if (route == null) {
6235
6509
  const media = this.hashlinkMediaDispatcher == null ? null : parseHashlinkGatewayRequest(url);
6236
6510
  if (media != null) return await this.#fetchHashlinkMedia(request, media, {
@@ -7135,7 +7409,7 @@ var ContextImpl = class ContextImpl {
7135
7409
  invokedFromActorKeyPairsDispatcher: this.invokedFromActorKeyPairsDispatcher
7136
7410
  });
7137
7411
  }
7138
- toInboxContext(recipient, activity, activityId, activityType) {
7412
+ toInboxContext(recipient, activity, activityId, activityType, metadata) {
7139
7413
  return new InboxContextImpl(recipient, activity, activityId, activityType, {
7140
7414
  url: this.url,
7141
7415
  federation: this.federation,
@@ -7143,7 +7417,7 @@ var ContextImpl = class ContextImpl {
7143
7417
  documentLoader: this.documentLoader,
7144
7418
  contextLoader: this.contextLoader,
7145
7419
  invokedFromActorKeyPairsDispatcher: this.invokedFromActorKeyPairsDispatcher
7146
- });
7420
+ }, metadata?.authentication);
7147
7421
  }
7148
7422
  toOutboxContext(identifier, activity, activityId, activityType) {
7149
7423
  return new OutboxContextImpl(identifier, activity, activityId, activityType, {
@@ -7758,12 +8032,20 @@ var ContextImpl = class ContextImpl {
7758
8032
  });
7759
8033
  }
7760
8034
  async routeActivityInternal(recipient, activity, options = {}, span) {
8035
+ const snapshot = createContextSnapshot(options.contextLoader ?? this.contextLoader);
8036
+ try {
8037
+ return await this.#routeActivityWithSnapshot(recipient, activity, options, span, snapshot);
8038
+ } finally {
8039
+ snapshot.release();
8040
+ }
8041
+ }
8042
+ async #routeActivityWithSnapshot(recipient, activity, options, span, snapshot) {
7761
8043
  const logger = getLogger([
7762
8044
  "fedify",
7763
8045
  "federation",
7764
8046
  "inbox"
7765
8047
  ]);
7766
- const contextLoader = options.contextLoader ?? this.contextLoader;
8048
+ const contextLoader = snapshot.loader("standard");
7767
8049
  let json = await activity.toJsonLd({ contextLoader });
7768
8050
  const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, {
7769
8051
  documentLoader: this.documentLoader,
@@ -7771,13 +8053,19 @@ var ContextImpl = class ContextImpl {
7771
8053
  tracerProvider: this.tracerProvider,
7772
8054
  keyTtl: this.federation.publicKeyTtl
7773
8055
  });
7774
- if (await verifyObject(Activity, json, {
8056
+ let documentSigners = [];
8057
+ let originAuthenticated = [];
8058
+ let viewSource;
8059
+ let fetchedView;
8060
+ const document = detachSignature(json);
8061
+ const verified = await verifyObjectDetailed(Activity, document, {
7775
8062
  contextLoader,
7776
8063
  documentLoader: options.documentLoader ?? this.documentLoader,
7777
8064
  meterProvider: this.meterProvider,
7778
8065
  tracerProvider: options.tracerProvider ?? this.tracerProvider,
7779
8066
  keyCache
7780
- }) == null) {
8067
+ });
8068
+ if (verified.status !== "verified") {
7781
8069
  logger.debug("Object Integrity Proofs are not verified.", {
7782
8070
  recipient,
7783
8071
  activity: json
@@ -7789,8 +8077,29 @@ var ContextImpl = class ContextImpl {
7789
8077
  });
7790
8078
  return false;
7791
8079
  }
7792
- const fetched = await this.lookupObject(activity.id, options);
7793
- if (fetched == null) {
8080
+ let candidate;
8081
+ let candidateView;
8082
+ const verifications = /* @__PURE__ */ new WeakMap();
8083
+ const fetched = await this.lookupObject(activity.id, {
8084
+ ...options,
8085
+ contextLoader,
8086
+ verifyPortableObject: async (document, verifierOptions) => {
8087
+ const result = await this.verifyPortableObject(document, verifierOptions);
8088
+ if (document != null && typeof document === "object") verifications.set(document, result);
8089
+ return result;
8090
+ },
8091
+ [lookupObserver]: { accept: async (accepted) => {
8092
+ candidate = accepted;
8093
+ candidateView = await buildVerifiedActivityView(createContextSnapshot(accepted.contextLoader), {
8094
+ policy: "standard",
8095
+ source: "activity",
8096
+ document: detachSignature(accepted.document),
8097
+ baseUrl: accepted.baseUrl
8098
+ });
8099
+ return true;
8100
+ } }
8101
+ });
8102
+ if (fetched == null || candidate == null || candidateView == null) {
7794
8103
  logger.debug("Failed to fetch the remote activity object {activityId}.", {
7795
8104
  recipient,
7796
8105
  activity: json,
@@ -7826,11 +8135,50 @@ var ContextImpl = class ContextImpl {
7826
8135
  }
7827
8136
  logger.debug("Successfully fetched the remote activity object {activityId}; ignore the original activity and use the fetched one, which is trustworthy.");
7828
8137
  activity = fetched;
7829
- json = await fetched.toJsonLd({ contextLoader });
7830
- } else logger.debug("Object Integrity Proofs are verified.", {
7831
- recipient,
7832
- activity: json
7833
- });
8138
+ json = candidate.document;
8139
+ fetchedView = candidateView;
8140
+ viewSource = {
8141
+ policy: "standard",
8142
+ source: "activity",
8143
+ document: detachSignature(candidate.document),
8144
+ baseUrl: candidate.baseUrl
8145
+ };
8146
+ if (isPortableId(fetched.id)) {
8147
+ const result = verifications.get(candidate.document);
8148
+ if (result?.verified === true && result.method === "proof") documentSigners = result.keys.flatMap((key) => {
8149
+ const signer = getProofSigner(key);
8150
+ return signer == null ? [] : [{
8151
+ kind: signer.kind,
8152
+ id: signer.id,
8153
+ mechanism: "objectIntegrityProofs",
8154
+ keyId: signer.keyId
8155
+ }];
8156
+ });
8157
+ } else originAuthenticated = fetched.actorIds.map((actorId) => ({
8158
+ kind: "actor",
8159
+ id: actorId,
8160
+ mechanism: "origin",
8161
+ keyId: null
8162
+ }));
8163
+ } else {
8164
+ logger.debug("Object Integrity Proofs are verified.", {
8165
+ recipient,
8166
+ activity: json
8167
+ });
8168
+ activity = verified.object;
8169
+ documentSigners = verified.signers.map((signer) => ({
8170
+ kind: signer.kind,
8171
+ id: signer.id,
8172
+ mechanism: "objectIntegrityProofs",
8173
+ keyId: signer.keyId
8174
+ }));
8175
+ viewSource = {
8176
+ policy: "standard",
8177
+ source: "activity",
8178
+ document,
8179
+ baseUrl: null
8180
+ };
8181
+ }
7834
8182
  if (activity.actorId == null) {
7835
8183
  logger.debug("Activity is missing an actor; unable to verify.", {
7836
8184
  recipient,
@@ -7845,10 +8193,21 @@ var ContextImpl = class ContextImpl {
7845
8193
  });
7846
8194
  return false;
7847
8195
  }
8196
+ const view = fetchedView ?? await buildVerifiedActivityView(snapshot, viewSource);
7848
8197
  const routeResult = await routeActivity({
7849
8198
  context: this,
7850
8199
  json,
7851
8200
  ldSignatureVerified: false,
8201
+ authentication: createAuthenticationEvidence({
8202
+ verified: true,
8203
+ requestSigners: [],
8204
+ documentSigners,
8205
+ originAuthenticated,
8206
+ expandedActivity: deepFreeze(view.expanded),
8207
+ baseUrl: viewSource.baseUrl
8208
+ }),
8209
+ verifiedView: view.view,
8210
+ replayable: view.replayable,
7852
8211
  activity,
7853
8212
  recipient,
7854
8213
  inboxListeners: this.federation.inboxListeners,
@@ -7964,52 +8323,92 @@ var RequestContextImpl = class RequestContextImpl extends ContextImpl {
7964
8323
  if (object instanceof Tombstone && !(object instanceof cls) && options?.tombstone !== "passthrough") return null;
7965
8324
  return object;
7966
8325
  }
7967
- #signedKey = void 0;
8326
+ #signedKey = null;
8327
+ #signedKeyOwner = null;
8328
+ #signatureChecks = /* @__PURE__ */ new WeakMap();
8329
+ #getSignatureCheck(documentLoader, contextLoader) {
8330
+ let checks = this.#signatureChecks.get(documentLoader);
8331
+ if (checks == null) {
8332
+ checks = /* @__PURE__ */ new WeakMap();
8333
+ this.#signatureChecks.set(documentLoader, checks);
8334
+ }
8335
+ let check = checks.get(contextLoader);
8336
+ if (check == null) {
8337
+ check = {};
8338
+ checks.set(contextLoader, check);
8339
+ }
8340
+ return check;
8341
+ }
7968
8342
  async getSignedKey(options = {}) {
7969
8343
  if (this.#signedKey != null) return this.#signedKey;
7970
- const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, {
7971
- documentLoader: options.documentLoader ?? this.documentLoader,
7972
- contextLoader: options.contextLoader ?? this.contextLoader,
8344
+ const documentLoader = options.documentLoader ?? this.documentLoader;
8345
+ const contextLoader = options.contextLoader ?? this.contextLoader;
8346
+ const check = this.#getSignatureCheck(documentLoader, contextLoader);
8347
+ if (check.key != null) return check.key;
8348
+ const keyCache = documentLoader === this.documentLoader && contextLoader === this.contextLoader ? new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, {
8349
+ documentLoader,
8350
+ contextLoader,
7973
8351
  tracerProvider: options.tracerProvider ?? this.tracerProvider,
7974
8352
  keyTtl: this.federation.publicKeyTtl
7975
- });
7976
- return this.#signedKey = await verifyRequest(this.request, {
8353
+ }) : void 0;
8354
+ const promise = verifyRequest(this.request, {
7977
8355
  ...this,
7978
- contextLoader: options.contextLoader ?? this.contextLoader,
7979
- documentLoader: options.documentLoader ?? this.documentLoader,
8356
+ contextLoader,
8357
+ documentLoader,
7980
8358
  timeWindow: this.federation.signatureTimeWindow,
7981
8359
  maxSignatures: this.federation.maxHttpSignatures,
8360
+ keyCache,
7982
8361
  meterProvider: this.meterProvider,
7983
- tracerProvider: options.tracerProvider ?? this.tracerProvider,
7984
- keyCache
8362
+ tracerProvider: options.tracerProvider ?? this.tracerProvider
8363
+ }).then((key) => {
8364
+ if (key != null) this.#signedKey ??= key;
8365
+ return key;
8366
+ }).catch((error) => {
8367
+ if (check.key === promise) check.key = void 0;
8368
+ throw error;
7985
8369
  });
8370
+ check.key = promise;
8371
+ return await promise;
7986
8372
  }
7987
- #signedKeyOwner = void 0;
7988
8373
  async getSignedKeyOwner(options = {}) {
7989
8374
  if (this.#signedKeyOwner != null) return this.#signedKeyOwner;
7990
- const key = await this.getSignedKey(options);
7991
- if (key == null) return this.#signedKeyOwner = null;
7992
- try {
7993
- return this.#signedKeyOwner = await getKeyOwner(key, {
7994
- contextLoader: options.contextLoader ?? this.contextLoader,
7995
- documentLoader: options.documentLoader ?? this.documentLoader,
7996
- tracerProvider: options.tracerProvider ?? this.tracerProvider
7997
- });
7998
- } catch (error) {
7999
- if (error instanceof FetchError) {
8000
- getLogger([
8001
- "fedify",
8002
- "federation",
8003
- "actor"
8004
- ]).warn("Failed to fetch the key owner {keyOwner} of {keyId} while verifying the request signature; treating the request as unauthenticated: {error}", {
8005
- keyId: key.id?.href,
8006
- keyOwner: error.url.href,
8007
- error
8008
- });
8009
- return this.#signedKeyOwner = null;
8375
+ const normalizedOptions = {
8376
+ documentLoader: options.documentLoader ?? this.documentLoader,
8377
+ contextLoader: options.contextLoader ?? this.contextLoader,
8378
+ tracerProvider: options.tracerProvider ?? this.tracerProvider
8379
+ };
8380
+ const check = this.#getSignatureCheck(normalizedOptions.documentLoader, normalizedOptions.contextLoader);
8381
+ if (check.owner != null) return check.owner;
8382
+ const promise = this.getSignedKey(normalizedOptions).then(async (key) => {
8383
+ if (key == null) {
8384
+ if (check.owner === promise) check.owner = void 0;
8385
+ return null;
8386
+ }
8387
+ try {
8388
+ const owner = await getKeyOwner(key, normalizedOptions);
8389
+ if (owner != null) this.#signedKeyOwner ??= owner;
8390
+ return owner;
8391
+ } catch (error) {
8392
+ if (error instanceof FetchError) {
8393
+ getLogger([
8394
+ "fedify",
8395
+ "federation",
8396
+ "actor"
8397
+ ]).warn("Failed to fetch the key owner {keyOwner} of {keyId} while verifying the request signature; treating the request as unauthenticated: {error}", {
8398
+ keyId: key.id?.href,
8399
+ keyOwner: error.url.href,
8400
+ error
8401
+ });
8402
+ return null;
8403
+ }
8404
+ throw error;
8010
8405
  }
8406
+ }).catch((error) => {
8407
+ if (check.owner === promise) check.owner = void 0;
8011
8408
  throw error;
8012
- }
8409
+ });
8410
+ check.owner = promise;
8411
+ return await promise;
8013
8412
  }
8014
8413
  async isSignedByAudience(object, options = {}) {
8015
8414
  return await isInAudience(object, null) || await isInAudience(object, await this.getSignedKeyOwner(options), options);
@@ -8199,12 +8598,14 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
8199
8598
  activity;
8200
8599
  activityId;
8201
8600
  activityType;
8202
- constructor(recipient, activity, activityId, activityType, options) {
8601
+ authentication;
8602
+ constructor(recipient, activity, activityId, activityType, options, authentication) {
8203
8603
  super(options);
8204
8604
  this.recipient = recipient;
8205
8605
  this.activity = activity;
8206
8606
  this.activityId = activityId;
8207
8607
  this.activityType = activityType;
8608
+ this.authentication = authentication ?? getEmptyAuthenticationEvidence();
8208
8609
  }
8209
8610
  clone(data) {
8210
8611
  return new InboxContextImpl(this.recipient, this.activity, this.activityId, this.activityType, {
@@ -8214,7 +8615,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
8214
8615
  documentLoader: this.documentLoader,
8215
8616
  contextLoader: this.contextLoader,
8216
8617
  invokedFromActorKeyPairsDispatcher: this.invokedFromActorKeyPairsDispatcher
8217
- });
8618
+ }, this.authentication);
8218
8619
  }
8219
8620
  forwardActivity(forwarder, recipients, options) {
8220
8621
  return forwardActivity(this, "inbox", forwarder, recipients, options).then(() => void 0);