@fedify/fedify 2.5.0-dev.2440 → 2.5.0-dev.2448

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 (117) hide show
  1. package/dist/{activity-listener-C-BSbKI7.mjs → activity-listener-CELFAodc.mjs} +8 -4
  2. package/dist/{builder-CTasaZgj.mjs → builder-DbC8bn6k.mjs} +5 -5
  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-D5r-dQMr.mjs → compound-proof-heeXW2_A.mjs} +2 -2
  7. package/dist/{context-DPocjp1l.d.cts → context-BazwQrHn.d.cts} +307 -5
  8. package/dist/{context-8Tu9kea0.mjs → context-COHd1Rsh.mjs} +2 -0
  9. package/dist/{context-2wLkQrjb.d.ts → context-GlHrzdSP.d.ts} +307 -5
  10. package/dist/{deno-DR1uYWpm.mjs → deno-Dpewt_jJ.mjs} +1 -1
  11. package/dist/{docloader-BpCJ2dHm.mjs → docloader-CpsDyqVN.mjs} +2 -2
  12. package/dist/federation/builder.test.mjs +1 -1
  13. package/dist/federation/compound-fanout.test.mjs +3 -3
  14. package/dist/federation/handler-compound-proof.test.mjs +5 -5
  15. package/dist/federation/handler.test.mjs +21 -6
  16. package/dist/federation/hashlink-media.test.mjs +2 -2
  17. package/dist/federation/idempotency.test.mjs +2 -2
  18. package/dist/federation/inbox-actorless.test.d.mts +2 -0
  19. package/dist/federation/inbox-actorless.test.mjs +487 -0
  20. package/dist/federation/inbox-authentication.test.d.mts +2 -0
  21. package/dist/federation/inbox-authentication.test.mjs +116 -0
  22. package/dist/federation/inbox-report.test.mjs +5 -5
  23. package/dist/federation/inbox-view.test.d.mts +2 -0
  24. package/dist/federation/inbox-view.test.mjs +369 -0
  25. package/dist/federation/inbox.test.mjs +22 -12
  26. package/dist/federation/metrics.test.mjs +1 -1
  27. package/dist/federation/middleware.test.mjs +24 -9
  28. package/dist/federation/mod.cjs +2 -1
  29. package/dist/federation/mod.d.cts +3 -3
  30. package/dist/federation/mod.d.ts +3 -3
  31. package/dist/federation/mod.js +8 -2
  32. package/dist/federation/mq.test.mjs +36 -1
  33. package/dist/federation/outgoing-proof.test.mjs +4 -4
  34. package/dist/federation/portable-actor.test.mjs +3 -3
  35. package/dist/federation/portable-chain.test.mjs +3 -3
  36. package/dist/federation/portable-collection.test.mjs +4 -4
  37. package/dist/federation/portable-delivery.test.mjs +2 -2
  38. package/dist/federation/portable-gateway-keys.test.mjs +6 -6
  39. package/dist/federation/portable-inbox.test.mjs +4 -4
  40. package/dist/federation/portable-parse-uri.test.mjs +1 -1
  41. package/dist/federation/portable-route-activity.test.mjs +2 -2
  42. package/dist/federation/portable.test.mjs +3 -3
  43. package/dist/federation/send.test.mjs +3 -3
  44. package/dist/federation/tasks/enqueue.test.mjs +3 -3
  45. package/dist/federation/tasks/tasks.test.mjs +4 -4
  46. package/dist/federation/temporal.test.mjs +1 -1
  47. package/dist/federation/webfinger.test.mjs +2 -2
  48. package/dist/{federation-eYRUxkUW.cjs → federation-D8YexkP1.cjs} +1174 -132
  49. package/dist/{http-CgaoFGXV.js → http-BBr-VLil.js} +143 -16
  50. package/dist/{http-CRrg14tX.mjs → http-BZkyQIkb.mjs} +4 -4
  51. package/dist/{http-CmFHJm6o.cjs → http-CAl7Num5.cjs} +161 -16
  52. package/dist/inbox-authentication-DflPYlLL.mjs +171 -0
  53. package/dist/inbox-view-NE9wXdLo.mjs +385 -0
  54. package/dist/inbox-wDuMKaFW.mjs +312 -0
  55. package/dist/{kv-cache-MxJrD9gD.mjs → kv-cache-CTQSfkmp.mjs} +1 -1
  56. package/dist/{kv-cache-DvVRGOMw.cjs → kv-cache-CjgCOz3i.cjs} +1 -1
  57. package/dist/{kv-cache-DeagaIIB.js → kv-cache-U7uz5nx4.js} +1 -1
  58. package/dist/{ld-CUM16-EE.mjs → ld-CQFuiah9.mjs} +52 -9
  59. package/dist/ld-CcuZ4NZa.d.ts +250 -0
  60. package/dist/ld-Cel1RRZ5.d.cts +250 -0
  61. package/dist/{metrics-DIM8ZCKq.mjs → metrics-B-QxRSSR.mjs} +1 -1
  62. package/dist/{middleware-Bx_QxJ0s.mjs → middleware-BdlNa8BD.mjs} +1 -1
  63. package/dist/{middleware-CDdFG6xf.mjs → middleware-CuVa0UuS.mjs} +461 -99
  64. package/dist/{middleware-CGfFooYv.js → middleware-P-AZEQMn.js} +1171 -142
  65. package/dist/mod-B2783_3v.d.cts +154 -0
  66. package/dist/mod-BHQE-7WQ.d.ts +154 -0
  67. package/dist/{mod-Dm-7RdhR.d.ts → mod-DjZfJj9R.d.ts} +1 -1
  68. package/dist/{mod-DKGoPoQC.d.cts → mod-DvWOv2Ho.d.cts} +1 -1
  69. package/dist/mod.cjs +5 -4
  70. package/dist/mod.d.cts +6 -6
  71. package/dist/mod.d.ts +6 -6
  72. package/dist/mod.js +5 -5
  73. package/dist/{mq-Dm1Wmtm-.mjs → mq-eF96QxUT.mjs} +6 -0
  74. package/dist/nodeinfo/handler.test.mjs +2 -2
  75. package/dist/{owner-DoQDS_g0.mjs → owner-ccKkQOAf.mjs} +3 -3
  76. package/dist/{portable-collection-DiBqtGSM.mjs → portable-collection-CndnpXfo.mjs} +2 -2
  77. package/dist/{portable-collection-BVKSWfBe.js → portable-collection-DUlQ3s2M.js} +1 -1
  78. package/dist/{portable-collection-C-etRRF0.cjs → portable-collection-TC-kvkVI.cjs} +1 -1
  79. package/dist/{portable-key-DSRuCUpF.mjs → portable-key-D5tFOoV-.mjs} +1 -1
  80. package/dist/{proof-DWpruPWs.mjs → proof-DPoF06nz.mjs} +98 -10
  81. package/dist/{send-H0z9Ey5l.mjs → send-CF44O1Df.mjs} +3 -3
  82. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  83. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  84. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  85. package/dist/sig/compound-proof.test.mjs +2 -2
  86. package/dist/sig/http.test.mjs +2 -2
  87. package/dist/sig/key.test.mjs +1 -1
  88. package/dist/sig/ld.test.mjs +1 -1
  89. package/dist/sig/mitra-receive-interop.test.mjs +4 -4
  90. package/dist/sig/mitra-send-interop.test.mjs +3 -3
  91. package/dist/sig/mod.cjs +2 -2
  92. package/dist/sig/mod.d.cts +2 -2
  93. package/dist/sig/mod.d.ts +2 -2
  94. package/dist/sig/mod.js +2 -2
  95. package/dist/sig/owner.test.mjs +1 -1
  96. package/dist/sig/portable-collection.test.mjs +1 -1
  97. package/dist/sig/portable-interop.test.mjs +3 -3
  98. package/dist/sig/portable-key.test.mjs +5 -5
  99. package/dist/sig/proof.test.mjs +44 -4
  100. package/dist/sig/tootik-request-interop.test.mjs +4 -4
  101. package/dist/sig/tootik-send-interop.test.mjs +3 -3
  102. package/dist/sig/verification.test.mjs +3 -3
  103. package/dist/{temporal-BiSBCImA.mjs → temporal-XlZ4Wb94.mjs} +1 -1
  104. package/dist/testing/kv.test.mjs +1 -1
  105. package/dist/testing/mod.d.mts +265 -3
  106. package/dist/testing/mod.mjs +2 -2
  107. package/dist/{testing-t8xDeJZ5.mjs → testing-Dbr21vZk.mjs} +1 -1
  108. package/dist/utils/docloader.test.mjs +2 -2
  109. package/dist/utils/kv-cache.test.mjs +1 -1
  110. package/dist/utils/mod.cjs +1 -1
  111. package/dist/utils/mod.js +1 -1
  112. package/package.json +7 -7
  113. package/dist/inbox-BwPoSUEv.mjs +0 -188
  114. package/dist/mod-BRpER-B0.d.ts +0 -320
  115. package/dist/mod-xAfaLS4T.d.cts +0 -320
  116. package/dist/owner-BF0L9cMt.d.cts +0 -78
  117. 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-DR1uYWpm.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-DIM8ZCKq.mjs";
8
+ import { n as version, t as name } from "./deno-Dpewt_jJ.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-B-QxRSSR.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-CUM16-EE.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-CQFuiah9.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-DWpruPWs.mjs";
13
- import { a as listRequestSignatures, c as selectRequestSignature, d as validateMaxSignatures, f as verifyRequest, p as verifyRequestDetailed, s as parseRfc9421SignatureInput } from "./http-CRrg14tX.mjs";
14
- import { t as getAuthenticatedDocumentLoader } from "./docloader-BpCJ2dHm.mjs";
15
- import { n as kvCache } from "./kv-cache-MxJrD9gD.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-DPoF06nz.mjs";
15
+ import { a as listRequestSignatures, c as selectRequestSignature, d as validateMaxSignatures, f as verifyRequest, p as verifyRequestDetailed, s as parseRfc9421SignatureInput } from "./http-BZkyQIkb.mjs";
16
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-CpsDyqVN.mjs";
17
+ import { n as kvCache } from "./kv-cache-CTQSfkmp.mjs";
16
18
  import { d as readBoundedText, l as BodyTooLargeError, t as getNodeInfo, u as MAX_BODY_SIZE } from "./client-CEnNz8O7.mjs";
17
19
  import { t as nodeInfoToJson } from "./types-DE_LV1JB.mjs";
18
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-DoQDS_g0.mjs";
19
- import { t as verifyPortableObject } from "./portable-collection-DiBqtGSM.mjs";
20
- import { a as getOrderingDestination, i as sendActivityThroughGateways, n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-H0z9Ey5l.mjs";
21
- import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-CTasaZgj.mjs";
20
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-ccKkQOAf.mjs";
21
+ import { t as verifyPortableObject } from "./portable-collection-CndnpXfo.mjs";
22
+ import { a as getOrderingDestination, i as sendActivityThroughGateways, n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-CF44O1Df.mjs";
23
+ import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-DbC8bn6k.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-D5r-dQMr.mjs";
25
- import { n as routeActivity, t as actorsHaveSameOrigin } from "./inbox-BwPoSUEv.mjs";
26
+ import { a as inspectCompoundPortableObjectApplicability, c as verifyServedPortableObjects, i as findUnsupportedCompoundProofShape, o as verifyCompoundPortableObjectProofs, r as findEmbeddedProofWithoutContext, t as containsCompoundPortableObject } from "./compound-proof-heeXW2_A.mjs";
27
+ import { a as isActorlessActivityAuthenticated, i as getInboxIdempotencyKey, n as checkActorlessActivity, o as isInboxActivityProcessed, s as routeActivity, t as actorsHaveSameOrigin } from "./inbox-wDuMKaFW.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-NE9wXdLo.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-BiSBCImA.mjs";
31
+ import { t as hasMalformedKnownTemporalLiteral } from "./temporal-XlZ4Wb94.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
  }
@@ -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, {
@@ -7525,7 +7799,8 @@ var ContextImpl = class ContextImpl {
7525
7799
  userAgent: options.userAgent ?? this.federation.userAgent,
7526
7800
  tracerProvider: options.tracerProvider ?? this.tracerProvider,
7527
7801
  meterProvider: options.meterProvider ?? this.federation._meterProvider,
7528
- allowPrivateAddress: this.federation.allowPrivateAddress
7802
+ allowPrivateAddress: this.federation.allowPrivateAddress,
7803
+ withDiagnostics: false
7529
7804
  });
7530
7805
  }
7531
7806
  async enqueueTask(task, data, options = {}) {
@@ -7757,12 +8032,20 @@ var ContextImpl = class ContextImpl {
7757
8032
  });
7758
8033
  }
7759
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) {
7760
8043
  const logger = getLogger([
7761
8044
  "fedify",
7762
8045
  "federation",
7763
8046
  "inbox"
7764
8047
  ]);
7765
- const contextLoader = options.contextLoader ?? this.contextLoader;
8048
+ const contextLoader = snapshot.loader("standard");
7766
8049
  let json = await activity.toJsonLd({ contextLoader });
7767
8050
  const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, {
7768
8051
  documentLoader: this.documentLoader,
@@ -7770,13 +8053,19 @@ var ContextImpl = class ContextImpl {
7770
8053
  tracerProvider: this.tracerProvider,
7771
8054
  keyTtl: this.federation.publicKeyTtl
7772
8055
  });
7773
- 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, {
7774
8062
  contextLoader,
7775
8063
  documentLoader: options.documentLoader ?? this.documentLoader,
7776
8064
  meterProvider: this.meterProvider,
7777
8065
  tracerProvider: options.tracerProvider ?? this.tracerProvider,
7778
8066
  keyCache
7779
- }) == null) {
8067
+ });
8068
+ if (verified.status !== "verified") {
7780
8069
  logger.debug("Object Integrity Proofs are not verified.", {
7781
8070
  recipient,
7782
8071
  activity: json
@@ -7788,8 +8077,29 @@ var ContextImpl = class ContextImpl {
7788
8077
  });
7789
8078
  return false;
7790
8079
  }
7791
- const fetched = await this.lookupObject(activity.id, options);
7792
- 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) {
7793
8103
  logger.debug("Failed to fetch the remote activity object {activityId}.", {
7794
8104
  recipient,
7795
8105
  activity: json,
@@ -7825,11 +8135,50 @@ var ContextImpl = class ContextImpl {
7825
8135
  }
7826
8136
  logger.debug("Successfully fetched the remote activity object {activityId}; ignore the original activity and use the fetched one, which is trustworthy.");
7827
8137
  activity = fetched;
7828
- json = await fetched.toJsonLd({ contextLoader });
7829
- } else logger.debug("Object Integrity Proofs are verified.", {
7830
- recipient,
7831
- activity: json
7832
- });
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
+ }
7833
8182
  if (activity.actorId == null) {
7834
8183
  logger.debug("Activity is missing an actor; unable to verify.", {
7835
8184
  recipient,
@@ -7844,10 +8193,21 @@ var ContextImpl = class ContextImpl {
7844
8193
  });
7845
8194
  return false;
7846
8195
  }
8196
+ const view = fetchedView ?? await buildVerifiedActivityView(snapshot, viewSource);
7847
8197
  const routeResult = await routeActivity({
7848
8198
  context: this,
7849
8199
  json,
7850
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,
7851
8211
  activity,
7852
8212
  recipient,
7853
8213
  inboxListeners: this.federation.inboxListeners,
@@ -8198,12 +8558,14 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
8198
8558
  activity;
8199
8559
  activityId;
8200
8560
  activityType;
8201
- constructor(recipient, activity, activityId, activityType, options) {
8561
+ authentication;
8562
+ constructor(recipient, activity, activityId, activityType, options, authentication) {
8202
8563
  super(options);
8203
8564
  this.recipient = recipient;
8204
8565
  this.activity = activity;
8205
8566
  this.activityId = activityId;
8206
8567
  this.activityType = activityType;
8568
+ this.authentication = authentication ?? getEmptyAuthenticationEvidence();
8207
8569
  }
8208
8570
  clone(data) {
8209
8571
  return new InboxContextImpl(this.recipient, this.activity, this.activityId, this.activityType, {
@@ -8213,7 +8575,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
8213
8575
  documentLoader: this.documentLoader,
8214
8576
  contextLoader: this.contextLoader,
8215
8577
  invokedFromActorKeyPairsDispatcher: this.invokedFromActorKeyPairsDispatcher
8216
- });
8578
+ }, this.authentication);
8217
8579
  }
8218
8580
  forwardActivity(forwarder, recipients, options) {
8219
8581
  return forwardActivity(this, "inbox", forwarder, recipients, options).then(() => void 0);