@fedify/fedify 2.1.28 → 2.1.29

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 (60) hide show
  1. package/dist/{assert_rejects-B-qJtC9Z.mjs → assert_rejects-WyYSTDDX.mjs} +2 -20
  2. package/dist/{assert_throws-4NwKEy2q.mjs → assert_throws-D4DNWrux.mjs} +19 -1
  3. package/dist/{builder-CW1BrLbm.mjs → builder-Mg2G3qj8.mjs} +3 -3
  4. package/dist/compat/transformers.test.mjs +1 -1
  5. package/dist/{deno-CJgU2mcr.mjs → deno-BiYv5RT5.mjs} +1 -1
  6. package/dist/{docloader-o3fCIlIa.mjs → docloader-DrxXBFL8.mjs} +4 -2
  7. package/dist/federation/builder.test.mjs +3 -3
  8. package/dist/federation/collection.test.mjs +1 -1
  9. package/dist/federation/handler.test.mjs +262 -9
  10. package/dist/federation/idempotency.test.mjs +3 -3
  11. package/dist/federation/inbox.test.mjs +25 -2
  12. package/dist/federation/kv.test.mjs +1 -1
  13. package/dist/federation/middleware.test.mjs +128 -10
  14. package/dist/federation/mod.cjs +1 -1
  15. package/dist/federation/mod.js +1 -1
  16. package/dist/federation/mq.test.mjs +2 -2
  17. package/dist/federation/negotiation.test.mjs +2 -2
  18. package/dist/federation/retry.test.mjs +1 -1
  19. package/dist/federation/router.test.mjs +2 -3
  20. package/dist/federation/send.test.mjs +7 -6
  21. package/dist/federation/temporal.test.mjs +3 -3
  22. package/dist/federation/webfinger.test.mjs +2 -2
  23. package/dist/{http-DtypHuuK.js → http-B3rSb2GQ.js} +1 -1
  24. package/dist/{http-Dcj1ulAh.mjs → http-C1ga9WQu.mjs} +2 -2
  25. package/dist/{http-EEfKB8Qb.cjs → http-Cginz7L0.cjs} +1 -1
  26. package/dist/{inbox-CVYVJI0M.mjs → inbox-BWzL0xMU.mjs} +23 -10
  27. package/dist/{key-DRLvwDTh.mjs → key-O-ATwIGS.mjs} +1 -1
  28. package/dist/{kv-cache-CEJCaF4E.js → kv-cache-8Kg2CHiD.js} +3 -1
  29. package/dist/{kv-cache-BWVKAAmc.cjs → kv-cache-BdylAE9w.cjs} +3 -1
  30. package/dist/{ld-C5BZ98YK.mjs → ld-C-fCGM-z.mjs} +2 -2
  31. package/dist/{middleware-wCgWm4Eh.js → middleware-41MkquTV.js} +95 -25
  32. package/dist/{middleware-SSrXiJIV.mjs → middleware-C9UCWOqw.mjs} +82 -25
  33. package/dist/{middleware-Dw9sPiec.cjs → middleware-CVRFS7PZ.cjs} +96 -26
  34. package/dist/{middleware-CqQoREZ9.mjs → middleware-CxgFiKI3.mjs} +1 -1
  35. package/dist/{middleware-DZxmsbPB.cjs → middleware-VvrqPwHL.cjs} +1 -1
  36. package/dist/mod.cjs +4 -4
  37. package/dist/mod.js +4 -4
  38. package/dist/nodeinfo/client.test.mjs +1 -1
  39. package/dist/nodeinfo/handler.test.mjs +2 -2
  40. package/dist/nodeinfo/types.test.mjs +2 -2
  41. package/dist/otel/exporter.test.mjs +1 -1
  42. package/dist/{owner-cPOoPvmr.mjs → owner-C8IVASD3.mjs} +2 -2
  43. package/dist/{proof-De1y2j-e.cjs → proof-BbHMAkPG.cjs} +1 -1
  44. package/dist/{proof-BTknCsN7.mjs → proof-CUdcBgvg.mjs} +2 -2
  45. package/dist/{proof-DPU3poip.js → proof-cGfRPTiV.js} +1 -1
  46. package/dist/{send-DDuHNgHz.mjs → send-BoV4dyVO.mjs} +2 -2
  47. package/dist/sig/http.test.mjs +5 -5
  48. package/dist/sig/key.test.mjs +5 -5
  49. package/dist/sig/ld.test.mjs +4 -4
  50. package/dist/sig/mod.cjs +2 -2
  51. package/dist/sig/mod.js +2 -2
  52. package/dist/sig/owner.test.mjs +3 -3
  53. package/dist/sig/proof.test.mjs +3 -3
  54. package/dist/{std__assert-BUOJXi-Z.mjs → std__assert-DflMZha5.mjs} +2 -2
  55. package/dist/{temporal-CxXY--ZL.mjs → temporal-BJlnku_d.mjs} +1 -1
  56. package/dist/utils/docloader.test.mjs +114 -39
  57. package/dist/utils/mod.cjs +1 -1
  58. package/dist/utils/mod.js +1 -1
  59. package/package.json +6 -6
  60. /package/dist/{assert_not_equals--wG9hV7u.mjs → assert_not_equals-BkxW5QJI.mjs} +0 -0
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { a as createExponentialBackoffPolicy, c as buildCollectionSynchronizationHeader, d as Router, f as RouterError, i as SendActivityError, l as digest, o as respondWithObject, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as createFederationBuilder } from "../middleware-wCgWm4Eh.js";
3
+ import { a as createExponentialBackoffPolicy, c as buildCollectionSynchronizationHeader, d as Router, f as RouterError, i as SendActivityError, l as digest, o as respondWithObject, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as createFederationBuilder } from "../middleware-41MkquTV.js";
4
4
  import { isEqual } from "es-toolkit";
5
5
  //#region src/federation/kv.ts
6
6
  /**
@@ -2,8 +2,8 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
- import { r as assertGreaterOrEqual } from "../std__assert-BUOJXi-Z.mjs";
6
- import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
5
+ import { r as assertGreaterOrEqual } from "../std__assert-DflMZha5.mjs";
6
+ import { r as assertFalse } from "../assert_throws-D4DNWrux.mjs";
7
7
  import { t as assert } from "../assert-BhQd8QHP.mjs";
8
8
  import { test } from "@fedify/fixture";
9
9
  import { delay } from "es-toolkit";
@@ -1,8 +1,8 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import "../std__assert-BUOJXi-Z.mjs";
5
- import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
4
+ import "../std__assert-DflMZha5.mjs";
5
+ import { r as assertFalse } from "../assert_throws-D4DNWrux.mjs";
6
6
  import { t as assert } from "../assert-BhQd8QHP.mjs";
7
7
  import { t as acceptsJsonLd } from "../negotiation-BehA2uul.mjs";
8
8
  import { test } from "@fedify/fixture";
@@ -2,7 +2,7 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { l as AssertionError, t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
- import { t as assertNotEquals } from "../assert_not_equals--wG9hV7u.mjs";
5
+ import { t as assertNotEquals } from "../assert_not_equals-BkxW5QJI.mjs";
6
6
  import { t as createExponentialBackoffPolicy } from "../retry-B_E3V_Dx.mjs";
7
7
  import { test } from "@fedify/fixture";
8
8
  //#region src/federation/retry.test.ts
@@ -3,10 +3,9 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as RouterError, t as Router } from "../router-CrMLXoOr.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
- import "../std__assert-BUOJXi-Z.mjs";
7
- import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
6
+ import "../std__assert-DflMZha5.mjs";
7
+ import { r as assertFalse, t as assertThrows } from "../assert_throws-D4DNWrux.mjs";
8
8
  import { t as assert } from "../assert-BhQd8QHP.mjs";
9
- import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
10
9
  import { test } from "@fedify/fixture";
11
10
  //#region src/federation/router.test.ts
12
11
  function setUp(options = {}) {
@@ -3,14 +3,15 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { t as esm_default } from "../esm-DVILvP5e.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
- import "../std__assert-BUOJXi-Z.mjs";
7
- import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
6
+ import "../std__assert-DflMZha5.mjs";
7
+ import { r as assertFalse } from "../assert_throws-D4DNWrux.mjs";
8
8
  import { n as assertInstanceOf, t as assert } from "../assert-BhQd8QHP.mjs";
9
- import { t as assertNotEquals } from "../assert_not_equals--wG9hV7u.mjs";
10
- import { l as verifyRequest } from "../http-Dcj1ulAh.mjs";
9
+ import { t as assertNotEquals } from "../assert_not_equals-BkxW5QJI.mjs";
10
+ import { t as assertRejects } from "../assert_rejects-WyYSTDDX.mjs";
11
+ import { l as verifyRequest } from "../http-C1ga9WQu.mjs";
11
12
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
12
- import { t as doesActorOwnKey } from "../owner-cPOoPvmr.mjs";
13
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-DDuHNgHz.mjs";
13
+ import { t as doesActorOwnKey } from "../owner-C8IVASD3.mjs";
14
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-BoV4dyVO.mjs";
14
15
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
15
16
  import { Activity, Application, Endpoints, Group, Person, Service } from "@fedify/vocab";
16
17
  import { FetchError, UrlError } from "@fedify/vocab-runtime";
@@ -1,10 +1,10 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import "../std__assert-BUOJXi-Z.mjs";
5
- import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
4
+ import "../std__assert-DflMZha5.mjs";
5
+ import { r as assertFalse } from "../assert_throws-D4DNWrux.mjs";
6
6
  import { t as assert } from "../assert-BhQd8QHP.mjs";
7
- import { t as hasMalformedKnownTemporalLiteral } from "../temporal-CxXY--ZL.mjs";
7
+ import { t as hasMalformedKnownTemporalLiteral } from "../temporal-BJlnku_d.mjs";
8
8
  import { test } from "@fedify/fixture";
9
9
  //#region src/federation/temporal.test.ts
10
10
  test("hasMalformedKnownTemporalLiteral() detects expanded proof timestamps", async () => {
@@ -3,9 +3,9 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as createRequestContext } from "../context-Juj6bdHC.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
- import "../std__assert-BUOJXi-Z.mjs";
6
+ import "../std__assert-DflMZha5.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-HvthQAHr.mjs";
8
- import { a as createFederation, o as handleWebFinger } from "../middleware-SSrXiJIV.mjs";
8
+ import { a as createFederation, o as handleWebFinger } from "../middleware-C9UCWOqw.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  import { Image, Link, Person } from "@fedify/vocab";
11
11
  //#region src/federation/webfinger.test.ts
@@ -10,7 +10,7 @@ import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } fro
10
10
  import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
11
11
  //#region deno.json
12
12
  var name = "@fedify/fedify";
13
- var version = "2.1.28";
13
+ var version = "2.1.29";
14
14
  //#endregion
15
15
  //#region src/sig/accept.ts
16
16
  /**
@@ -1,9 +1,9 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-CJgU2mcr.mjs";
4
+ import { n as version, t as name } from "./deno-BiYv5RT5.mjs";
5
5
  import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-BavzedPB.mjs";
6
- import { i as fetchKeyDetailed, s as validateCryptoKey } from "./key-DRLvwDTh.mjs";
6
+ import { i as fetchKeyDetailed, s as validateCryptoKey } from "./key-O-ATwIGS.mjs";
7
7
  import { CryptographicKey } from "@fedify/vocab";
8
8
  import { SpanStatusCode, trace } from "@opentelemetry/api";
9
9
  import { FetchError } from "@fedify/vocab-runtime";
@@ -11,7 +11,7 @@ let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conve
11
11
  let byte_encodings_base64 = require("byte-encodings/base64");
12
12
  //#region deno.json
13
13
  var name = "@fedify/fedify";
14
- var version = "2.1.28";
14
+ var version = "2.1.29";
15
15
  //#endregion
16
16
  //#region src/sig/accept.ts
17
17
  /**
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-CJgU2mcr.mjs";
4
+ import { n as version, t as name } from "./deno-BiYv5RT5.mjs";
5
5
  import { Activity, getTypeId } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
7
7
  import { getLogger } from "@logtape/logtape";
@@ -39,12 +39,33 @@ var InboxListenerSet = class InboxListenerSet {
39
39
  return this.dispatchWithClass(activity)?.listener ?? null;
40
40
  }
41
41
  };
42
+ /**
43
+ * Checks whether an activity's ID and all of its actor IDs have the same
44
+ * non-opaque origin. Activities without an ID have no origin to authenticate.
45
+ *
46
+ * The caller is responsible for rejecting a missing primary actor ID before
47
+ * relying on this check.
48
+ * @internal
49
+ */
50
+ function actorsHaveSameOrigin(activity) {
51
+ if (activity.id == null) return true;
52
+ const origin = activity.id.origin;
53
+ return origin !== "null" && activity.actorIds.every((actor) => actor.origin === origin);
54
+ }
42
55
  async function routeActivity({ context: ctx, json, originalJson, normalizedActivity, ldSignatureVerified, activity, recipient, inboxListeners, inboxContextFactory, listenerInboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider, idempotencyStrategy }) {
43
56
  const logger = getLogger([
44
57
  "fedify",
45
58
  "federation",
46
59
  "inbox"
47
60
  ]);
61
+ if (activity.actorId == null) {
62
+ logger.error("Missing actor.", { activity: json });
63
+ span.setStatus({
64
+ code: SpanStatusCode.ERROR,
65
+ message: "Missing actor."
66
+ });
67
+ return "missingActor";
68
+ }
48
69
  let cacheKey = null;
49
70
  if (activity.id != null) {
50
71
  const inboxContext = inboxContextFactory(recipient, json, activity.id?.href, getTypeId(activity).href);
@@ -79,14 +100,6 @@ async function routeActivity({ context: ctx, json, originalJson, normalizedActiv
79
100
  return "alreadyProcessed";
80
101
  }
81
102
  }
82
- if (activity.actorId == null) {
83
- logger.error("Missing actor.", { activity: json });
84
- span.setStatus({
85
- code: SpanStatusCode.ERROR,
86
- message: "Missing actor."
87
- });
88
- return "missingActor";
89
- }
90
103
  span.setAttribute("activitypub.actor.id", activity.actorId.href);
91
104
  if (queue != null) {
92
105
  const carrier = {};
@@ -179,4 +192,4 @@ async function routeActivity({ context: ctx, json, originalJson, normalizedActiv
179
192
  });
180
193
  }
181
194
  //#endregion
182
- export { routeActivity as n, InboxListenerSet as t };
195
+ export { actorsHaveSameOrigin as n, routeActivity as r, InboxListenerSet as t };
@@ -1,7 +1,7 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-CJgU2mcr.mjs";
4
+ import { n as version, t as name } from "./deno-BiYv5RT5.mjs";
5
5
  import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
7
7
  import { FetchError, UrlError, getDocumentLoader } from "@fedify/vocab-runtime";
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { f as validateCryptoKey, t as doubleKnock } from "./http-DtypHuuK.js";
3
+ import { f as validateCryptoKey, t as doubleKnock } from "./http-B3rSb2GQ.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { curry } from "es-toolkit";
6
6
  import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
@@ -56,6 +56,8 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, userAge
56
56
  });
57
57
  }
58
58
  async function validateUrl(url) {
59
+ const protocol = new URL(url).protocol;
60
+ if (protocol !== "http:" && protocol !== "https:") throw new UrlError(`Unsupported protocol: ${protocol}`);
59
61
  if (!allowPrivateAddress) try {
60
62
  await validatePublicUrl(url);
61
63
  } catch (error) {
@@ -1,7 +1,7 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  require("./chunk-DDcVe30Y.cjs");
4
- const require_http = require("./http-EEfKB8Qb.cjs");
4
+ const require_http = require("./http-Cginz7L0.cjs");
5
5
  let _logtape_logtape = require("@logtape/logtape");
6
6
  let es_toolkit = require("es-toolkit");
7
7
  let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
@@ -57,6 +57,8 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, userAge
57
57
  });
58
58
  }
59
59
  async function validateUrl(url) {
60
+ const protocol = new URL(url).protocol;
61
+ if (protocol !== "http:" && protocol !== "https:") throw new _fedify_vocab_runtime.UrlError(`Unsupported protocol: ${protocol}`);
60
62
  if (!allowPrivateAddress) try {
61
63
  await (0, _fedify_vocab_runtime.validatePublicUrl)(url);
62
64
  } catch (error) {
@@ -1,8 +1,8 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-CJgU2mcr.mjs";
5
- import { r as fetchKey, s as validateCryptoKey } from "./key-DRLvwDTh.mjs";
4
+ import { n as version, t as name } from "./deno-BiYv5RT5.mjs";
5
+ import { r as fetchKey, s as validateCryptoKey } from "./key-O-ATwIGS.mjs";
6
6
  import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -2,10 +2,10 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  import { t as __exportAll } from "./chunk-CRNNMoPX.js";
4
4
  import { r as getDefaultActivityTransformers } from "./transformers-BGMIq1cs.js";
5
- import { a as verifyRequestDetailed, d as importJwk, f as validateCryptoKey, i as verifyRequest, m as formatAcceptSignature, n as parseRfc9421SignatureInput, o as exportJwk, t as doubleKnock, v as name, y as version } from "./http-DtypHuuK.js";
5
+ import { a as verifyRequestDetailed, d as importJwk, f as validateCryptoKey, i as verifyRequest, m as formatAcceptSignature, n as parseRfc9421SignatureInput, o as exportJwk, t as doubleKnock, v as name, y as version } from "./http-B3rSb2GQ.js";
6
6
  import { a as MAX_BODY_SIZE, i as BodyTooLargeError, n as getNodeInfo, o as readBoundedText, t as nodeInfoToJson } from "./types-miAYfiGO.js";
7
- import { _ as signJsonLd, a as doesActorOwnKey, c as assertSafeJsonLd, f as detachSignature, g as isInvalidUrlTypeError, h as isClearlyMalformedContextReference, m as hasSignature, n as signObject, o as getKeyOwner, p as getNormalizationContextLoader, r as verifyObject, s as InvalidContextReferenceError, u as compactJsonLd, v as verifyCompactJsonLd, x as wrapContextLoaderForJsonLd } from "./proof-DPU3poip.js";
8
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-CEJCaF4E.js";
7
+ import { _ as signJsonLd, a as doesActorOwnKey, c as assertSafeJsonLd, f as detachSignature, g as isInvalidUrlTypeError, h as isClearlyMalformedContextReference, m as hasSignature, n as signObject, o as getKeyOwner, p as getNormalizationContextLoader, r as verifyObject, s as InvalidContextReferenceError, u as compactJsonLd, v as verifyCompactJsonLd, x as wrapContextLoaderForJsonLd } from "./proof-cGfRPTiV.js";
8
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-8Kg2CHiD.js";
9
9
  import { getLogger, withContext } from "@logtape/logtape";
10
10
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
11
11
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
@@ -52,12 +52,33 @@ var InboxListenerSet = class InboxListenerSet {
52
52
  return this.dispatchWithClass(activity)?.listener ?? null;
53
53
  }
54
54
  };
55
+ /**
56
+ * Checks whether an activity's ID and all of its actor IDs have the same
57
+ * non-opaque origin. Activities without an ID have no origin to authenticate.
58
+ *
59
+ * The caller is responsible for rejecting a missing primary actor ID before
60
+ * relying on this check.
61
+ * @internal
62
+ */
63
+ function actorsHaveSameOrigin(activity) {
64
+ if (activity.id == null) return true;
65
+ const origin = activity.id.origin;
66
+ return origin !== "null" && activity.actorIds.every((actor) => actor.origin === origin);
67
+ }
55
68
  async function routeActivity({ context: ctx, json, originalJson, normalizedActivity, ldSignatureVerified, activity, recipient, inboxListeners, inboxContextFactory, listenerInboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider, idempotencyStrategy }) {
56
69
  const logger = getLogger([
57
70
  "fedify",
58
71
  "federation",
59
72
  "inbox"
60
73
  ]);
74
+ if (activity.actorId == null) {
75
+ logger.error("Missing actor.", { activity: json });
76
+ span.setStatus({
77
+ code: SpanStatusCode.ERROR,
78
+ message: "Missing actor."
79
+ });
80
+ return "missingActor";
81
+ }
61
82
  let cacheKey = null;
62
83
  if (activity.id != null) {
63
84
  const inboxContext = inboxContextFactory(recipient, json, activity.id?.href, getTypeId(activity).href);
@@ -92,14 +113,6 @@ async function routeActivity({ context: ctx, json, originalJson, normalizedActiv
92
113
  return "alreadyProcessed";
93
114
  }
94
115
  }
95
- if (activity.actorId == null) {
96
- logger.error("Missing actor.", { activity: json });
97
- span.setStatus({
98
- code: SpanStatusCode.ERROR,
99
- message: "Missing actor."
100
- });
101
- return "missingActor";
102
- }
103
116
  span.setAttribute("activitypub.actor.id", activity.actorId.href);
104
117
  if (queue != null) {
105
118
  const carrier = {};
@@ -1798,6 +1811,36 @@ async function handleInboxInternal(request, parameters, span) {
1798
1811
  return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
1799
1812
  }
1800
1813
  }
1814
+ if (activity.actorId == null) {
1815
+ logger.error("Missing actor.", {
1816
+ activity: json,
1817
+ recipient
1818
+ });
1819
+ span.setStatus({
1820
+ code: SpanStatusCode.ERROR,
1821
+ message: "Missing actor."
1822
+ });
1823
+ return new Response("Missing actor.", {
1824
+ status: 400,
1825
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
1826
+ });
1827
+ }
1828
+ if (!skipSignatureVerification && activity.id != null && !actorsHaveSameOrigin(activity)) {
1829
+ logger.error("The activity ({activityId}) and its actors do not have the same origin.", {
1830
+ activity: json,
1831
+ recipient,
1832
+ activityId: activity.id.href,
1833
+ actorIds: activity.actorIds.map((actor) => actor.href)
1834
+ });
1835
+ span.setStatus({
1836
+ code: SpanStatusCode.ERROR,
1837
+ message: `The activity (${activity.id.href}) and its actors do not have the same origin.`
1838
+ });
1839
+ return new Response("The activity and its actors do not have the same origin.", {
1840
+ status: 401,
1841
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
1842
+ });
1843
+ }
1801
1844
  const routeResult = await routeActivity({
1802
1845
  context: ctx,
1803
1846
  json,
@@ -3316,6 +3359,33 @@ var FederationImpl = class extends FederationBuilderImpl {
3316
3359
  activity = await Activity.fromJsonLd(parseInput, parseContext);
3317
3360
  span.setAttribute("activitypub.activity.type", getTypeId(activity).href);
3318
3361
  if (activity.id != null) span.setAttribute("activitypub.activity.id", activity.id.href);
3362
+ if (activity.actorId == null) {
3363
+ logger.error("Missing actor in queued incoming activity.", {
3364
+ activityId: activity.id?.href,
3365
+ activity: message.activity,
3366
+ recipient: message.identifier
3367
+ });
3368
+ span.setStatus({
3369
+ code: SpanStatusCode.ERROR,
3370
+ message: "Missing actor."
3371
+ });
3372
+ span.end();
3373
+ return;
3374
+ }
3375
+ if (!this.skipSignatureVerification && activity.id != null && !actorsHaveSameOrigin(activity)) {
3376
+ logger.error("The queued activity ({activityId}) and its actors do not have the same origin.", {
3377
+ activityId: activity.id.href,
3378
+ actorIds: activity.actorIds.map((actor) => actor.href),
3379
+ activity: message.activity,
3380
+ recipient: message.identifier
3381
+ });
3382
+ span.setStatus({
3383
+ code: SpanStatusCode.ERROR,
3384
+ message: `The activity (${activity.id.href}) and its actors do not have the same origin.`
3385
+ });
3386
+ span.end();
3387
+ return;
3388
+ }
3319
3389
  cacheKey = activity.id == null ? null : [
3320
3390
  ...this.kvPrefixes.activityIdempotence,
3321
3391
  context.origin,
@@ -4428,20 +4498,6 @@ var ContextImpl = class ContextImpl {
4428
4498
  activity: await fetched.toJsonLd({ contextLoader })
4429
4499
  });
4430
4500
  return false;
4431
- } else if (fetched.actorIds.length < 1) {
4432
- logger.debug("Fetched activity object is missing an actor; unable to verify.", {
4433
- recipient,
4434
- activity: await fetched.toJsonLd({ contextLoader })
4435
- });
4436
- return false;
4437
- }
4438
- const activityId = fetched.id;
4439
- if (!fetched.actorIds.every((actor) => actor.origin === activityId.origin)) {
4440
- logger.debug("Fetched activity object has actors from different origins; unable to verify.", {
4441
- recipient,
4442
- activity: await fetched.toJsonLd({ contextLoader })
4443
- });
4444
- return false;
4445
4501
  }
4446
4502
  logger.debug("Successfully fetched the remote activity object {activityId}; ignore the original activity and use the fetched one, which is trustworthy.");
4447
4503
  activity = fetched;
@@ -4450,6 +4506,20 @@ var ContextImpl = class ContextImpl {
4450
4506
  recipient,
4451
4507
  activity: json
4452
4508
  });
4509
+ if (activity.actorId == null) {
4510
+ logger.debug("Activity is missing an actor; unable to verify.", {
4511
+ recipient,
4512
+ activity: json
4513
+ });
4514
+ return false;
4515
+ }
4516
+ if (activity.id != null && !actorsHaveSameOrigin(activity)) {
4517
+ logger.debug("Activity has actors from different origins; unable to verify.", {
4518
+ recipient,
4519
+ activity: json
4520
+ });
4521
+ return false;
4522
+ }
4453
4523
  const routeResult = await routeActivity({
4454
4524
  context: this,
4455
4525
  json,
@@ -2,25 +2,25 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as RouterError } from "./router-CrMLXoOr.mjs";
5
- import { n as version, t as name } from "./deno-CJgU2mcr.mjs";
5
+ import { n as version, t as name } from "./deno-BiYv5RT5.mjs";
6
6
  import { t as formatAcceptSignature } from "./accept-BavzedPB.mjs";
7
- import { o as importJwk, s as validateCryptoKey, t as exportJwk } from "./key-DRLvwDTh.mjs";
8
- import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-Dcj1ulAh.mjs";
9
- import { t as getAuthenticatedDocumentLoader } from "./docloader-o3fCIlIa.mjs";
7
+ import { o as importJwk, s as validateCryptoKey, t as exportJwk } from "./key-O-ATwIGS.mjs";
8
+ import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-C1ga9WQu.mjs";
9
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-DrxXBFL8.mjs";
10
10
  import { n as kvCache } from "./kv-cache-DqEKe5E0.mjs";
11
11
  import { t as KvKeyCache } from "./keycache-RFlZObU3.mjs";
12
- import { a as compactJsonLd, c as getNormalizationContextLoader, d as isInvalidUrlTypeError, f as signJsonLd, g as wrapContextLoaderForJsonLd, l as hasSignature, p as verifyCompactJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as isClearlyMalformedContextReference } from "./ld-C5BZ98YK.mjs";
13
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-cPOoPvmr.mjs";
14
- import { n as signObject, r as verifyObject } from "./proof-BTknCsN7.mjs";
12
+ import { a as compactJsonLd, c as getNormalizationContextLoader, d as isInvalidUrlTypeError, f as signJsonLd, g as wrapContextLoaderForJsonLd, l as hasSignature, p as verifyCompactJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as isClearlyMalformedContextReference } from "./ld-C-fCGM-z.mjs";
13
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-C8IVASD3.mjs";
14
+ import { n as signObject, r as verifyObject } from "./proof-CUdcBgvg.mjs";
15
15
  import { d as readBoundedText, l as BodyTooLargeError, t as getNodeInfo, u as MAX_BODY_SIZE } from "./client-CjDMsn4a.mjs";
16
16
  import { t as nodeInfoToJson } from "./types-DCP0WLdt.mjs";
17
- import { n as routeActivity } from "./inbox-CVYVJI0M.mjs";
18
- import { t as FederationBuilderImpl } from "./builder-CW1BrLbm.mjs";
17
+ import { n as actorsHaveSameOrigin, r as routeActivity } from "./inbox-BWzL0xMU.mjs";
18
+ import { t as FederationBuilderImpl } from "./builder-Mg2G3qj8.mjs";
19
19
  import { t as buildCollectionSynchronizationHeader } from "./collection-BD6-SZ6O.mjs";
20
20
  import { t as acceptsJsonLd } from "./negotiation-BehA2uul.mjs";
21
- import { t as hasMalformedKnownTemporalLiteral } from "./temporal-CxXY--ZL.mjs";
21
+ import { t as hasMalformedKnownTemporalLiteral } from "./temporal-BJlnku_d.mjs";
22
22
  import { t as createExponentialBackoffPolicy } from "./retry-B_E3V_Dx.mjs";
23
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-DDuHNgHz.mjs";
23
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-BoV4dyVO.mjs";
24
24
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
25
25
  import { lookupWebFinger } from "@fedify/webfinger";
26
26
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
@@ -812,6 +812,36 @@ async function handleInboxInternal(request, parameters, span) {
812
812
  return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
813
813
  }
814
814
  }
815
+ if (activity.actorId == null) {
816
+ logger.error("Missing actor.", {
817
+ activity: json,
818
+ recipient
819
+ });
820
+ span.setStatus({
821
+ code: SpanStatusCode.ERROR,
822
+ message: "Missing actor."
823
+ });
824
+ return new Response("Missing actor.", {
825
+ status: 400,
826
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
827
+ });
828
+ }
829
+ if (!skipSignatureVerification && activity.id != null && !actorsHaveSameOrigin(activity)) {
830
+ logger.error("The activity ({activityId}) and its actors do not have the same origin.", {
831
+ activity: json,
832
+ recipient,
833
+ activityId: activity.id.href,
834
+ actorIds: activity.actorIds.map((actor) => actor.href)
835
+ });
836
+ span.setStatus({
837
+ code: SpanStatusCode.ERROR,
838
+ message: `The activity (${activity.id.href}) and its actors do not have the same origin.`
839
+ });
840
+ return new Response("The activity and its actors do not have the same origin.", {
841
+ status: 401,
842
+ headers: { "Content-Type": "text/plain; charset=utf-8" }
843
+ });
844
+ }
815
845
  const routeResult = await routeActivity({
816
846
  context: ctx,
817
847
  json,
@@ -2007,6 +2037,33 @@ var FederationImpl = class extends FederationBuilderImpl {
2007
2037
  activity = await Activity.fromJsonLd(parseInput, parseContext);
2008
2038
  span.setAttribute("activitypub.activity.type", getTypeId(activity).href);
2009
2039
  if (activity.id != null) span.setAttribute("activitypub.activity.id", activity.id.href);
2040
+ if (activity.actorId == null) {
2041
+ logger.error("Missing actor in queued incoming activity.", {
2042
+ activityId: activity.id?.href,
2043
+ activity: message.activity,
2044
+ recipient: message.identifier
2045
+ });
2046
+ span.setStatus({
2047
+ code: SpanStatusCode.ERROR,
2048
+ message: "Missing actor."
2049
+ });
2050
+ span.end();
2051
+ return;
2052
+ }
2053
+ if (!this.skipSignatureVerification && activity.id != null && !actorsHaveSameOrigin(activity)) {
2054
+ logger.error("The queued activity ({activityId}) and its actors do not have the same origin.", {
2055
+ activityId: activity.id.href,
2056
+ actorIds: activity.actorIds.map((actor) => actor.href),
2057
+ activity: message.activity,
2058
+ recipient: message.identifier
2059
+ });
2060
+ span.setStatus({
2061
+ code: SpanStatusCode.ERROR,
2062
+ message: `The activity (${activity.id.href}) and its actors do not have the same origin.`
2063
+ });
2064
+ span.end();
2065
+ return;
2066
+ }
2010
2067
  cacheKey = activity.id == null ? null : [
2011
2068
  ...this.kvPrefixes.activityIdempotence,
2012
2069
  context.origin,
@@ -3119,20 +3176,6 @@ var ContextImpl = class ContextImpl {
3119
3176
  activity: await fetched.toJsonLd({ contextLoader })
3120
3177
  });
3121
3178
  return false;
3122
- } else if (fetched.actorIds.length < 1) {
3123
- logger.debug("Fetched activity object is missing an actor; unable to verify.", {
3124
- recipient,
3125
- activity: await fetched.toJsonLd({ contextLoader })
3126
- });
3127
- return false;
3128
- }
3129
- const activityId = fetched.id;
3130
- if (!fetched.actorIds.every((actor) => actor.origin === activityId.origin)) {
3131
- logger.debug("Fetched activity object has actors from different origins; unable to verify.", {
3132
- recipient,
3133
- activity: await fetched.toJsonLd({ contextLoader })
3134
- });
3135
- return false;
3136
3179
  }
3137
3180
  logger.debug("Successfully fetched the remote activity object {activityId}; ignore the original activity and use the fetched one, which is trustworthy.");
3138
3181
  activity = fetched;
@@ -3141,6 +3184,20 @@ var ContextImpl = class ContextImpl {
3141
3184
  recipient,
3142
3185
  activity: json
3143
3186
  });
3187
+ if (activity.actorId == null) {
3188
+ logger.debug("Activity is missing an actor; unable to verify.", {
3189
+ recipient,
3190
+ activity: json
3191
+ });
3192
+ return false;
3193
+ }
3194
+ if (activity.id != null && !actorsHaveSameOrigin(activity)) {
3195
+ logger.debug("Activity has actors from different origins; unable to verify.", {
3196
+ recipient,
3197
+ activity: json
3198
+ });
3199
+ return false;
3200
+ }
3144
3201
  const routeResult = await routeActivity({
3145
3202
  context: this,
3146
3203
  json,