@fedify/fedify 2.0.28-dev.1974 → 2.0.28-dev.1982

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 (96) hide show
  1. package/dist/{assert_instance_of-C4Ri6VuN.mjs → assert-BhQd8QHP.mjs} +19 -1
  2. package/dist/{builder-DBKy92BX.mjs → builder-DG5rS_Zv.mjs} +3 -3
  3. package/dist/{client-HLLGHiTU.mjs → client-glFHmpn4.mjs} +78 -4
  4. package/dist/compat/mod.d.cts +1 -1
  5. package/dist/compat/mod.d.ts +1 -1
  6. package/dist/compat/transformers.test.mjs +3 -4
  7. package/dist/{context-DnsFj3yK.d.ts → context-B21klrfz.d.ts} +4 -3
  8. package/dist/{context-CJZHWLmz.d.cts → context-M_MxoQgC.d.cts} +4 -3
  9. package/dist/{deno-CGtm12Ft.mjs → deno-eqaJj6JL.mjs} +1 -1
  10. package/dist/{docloader-_hXTUC-b.mjs → docloader-BXUqhXNd.mjs} +2 -2
  11. package/dist/federation/builder.test.mjs +2 -2
  12. package/dist/federation/collection.test.mjs +1 -1
  13. package/dist/federation/handler.test.mjs +125 -8
  14. package/dist/federation/idempotency.test.mjs +4 -4
  15. package/dist/federation/inbox.test.mjs +1 -1
  16. package/dist/federation/keycache.test.mjs +44 -10
  17. package/dist/federation/kv.test.mjs +1 -1
  18. package/dist/federation/middleware.test.mjs +99 -11
  19. package/dist/federation/mod.cjs +1 -1
  20. package/dist/federation/mod.d.cts +2 -2
  21. package/dist/federation/mod.d.ts +2 -2
  22. package/dist/federation/mod.js +1 -1
  23. package/dist/federation/mq.test.mjs +1 -1
  24. package/dist/federation/negotiation.test.mjs +2 -2
  25. package/dist/federation/retry.test.mjs +1 -1
  26. package/dist/federation/router.test.mjs +1 -1
  27. package/dist/federation/send.test.mjs +138 -6
  28. package/dist/federation/temporal.test.mjs +2 -2
  29. package/dist/federation/webfinger.test.mjs +2 -2
  30. package/dist/{http-BuaGj55w.cjs → http-BgOlx4n1.cjs} +163 -3
  31. package/dist/{http-C4D0ajx0.d.ts → http-Bs6thuCC.d.cts} +2 -2
  32. package/dist/{http--P33qRwW.mjs → http-Bu3NxfGb.mjs} +2 -2
  33. package/dist/{http-RYvZHWMc.d.cts → http-CDupyfOc.d.ts} +2 -2
  34. package/dist/{http-BP1pVF9m.js → http-CwcG2wDs.js} +152 -4
  35. package/dist/{inbox-BZNyUPzW.mjs → inbox-Hou2ZAjv.mjs} +1 -1
  36. package/dist/{key-rC9mW1U5.mjs → key-bSphUqhB.mjs} +152 -4
  37. package/dist/{keycache-DaQ3ndaJ.mjs → keycache-D239uGT9.mjs} +12 -4
  38. package/dist/{kv-cache-BVqMp1RC.cjs → kv-cache-B8GaLaNy.cjs} +1 -1
  39. package/dist/{kv-cache-CKg5W012.js → kv-cache-lbswb9pg.js} +1 -1
  40. package/dist/{ld-CN2nacLy.mjs → ld-D0uFMLmq.mjs} +2 -2
  41. package/dist/{middleware-DcmlYd2c.cjs → middleware-BKpP3cnZ.cjs} +1 -1
  42. package/dist/{middleware-DpEJSmjy.mjs → middleware-BuVM1K-J.mjs} +30 -19
  43. package/dist/{middleware-sbzAVAzo.mjs → middleware-DXPBIbm6.mjs} +1 -1
  44. package/dist/{middleware-BXwn4gnl.cjs → middleware-D_7wZH27.cjs} +90 -14
  45. package/dist/{middleware-CwIT91Nc.js → middleware-DomxFoLd.js} +90 -14
  46. package/dist/{mod-B2zB0rDg.d.cts → mod-Bt0eg_Lv.d.cts} +1 -1
  47. package/dist/{mod-COgmn-UO.d.ts → mod-D24V_w-K.d.ts} +1 -1
  48. package/dist/{mod-43DJyETz.d.cts → mod-Dp5dfH-i.d.cts} +1 -1
  49. package/dist/{mod-CiQNNAQL.d.ts → mod-E7YM72JZ.d.ts} +1 -1
  50. package/dist/{mod-CB6pc2pw.d.cts → mod-IOWUF5Yr.d.cts} +1 -1
  51. package/dist/{mod-CD1youdZ.d.ts → mod-XucBiDNd.d.ts} +1 -1
  52. package/dist/mod.cjs +5 -5
  53. package/dist/mod.d.cts +6 -6
  54. package/dist/mod.d.ts +6 -6
  55. package/dist/mod.js +5 -5
  56. package/dist/nodeinfo/client.test.mjs +28 -1
  57. package/dist/nodeinfo/handler.test.mjs +2 -2
  58. package/dist/nodeinfo/mod.cjs +1 -1
  59. package/dist/nodeinfo/mod.js +1 -1
  60. package/dist/nodeinfo/types.test.mjs +1 -1
  61. package/dist/otel/exporter.test.mjs +1 -1
  62. package/dist/{owner-DEvZuyOE.d.cts → owner-B3hNQCG8.d.cts} +11 -0
  63. package/dist/owner-Bzg6w7eA.mjs +175 -0
  64. package/dist/{owner-CnngXDNJ.d.ts → owner-CiBPcC6F.d.ts} +11 -0
  65. package/dist/{proof-CpEH24hi.mjs → proof-CgLA51pO.mjs} +2 -2
  66. package/dist/{proof-ftbx50PI.js → proof-DsJHFTkx.js} +112 -58
  67. package/dist/{proof-BTKH7fe9.cjs → proof-xCEe8t7U.cjs} +112 -58
  68. package/dist/{send-pXXMu19o.mjs → send-D89-FDX-.mjs} +64 -6
  69. package/dist/sig/http.test.mjs +4 -4
  70. package/dist/sig/key.test.mjs +169 -2
  71. package/dist/sig/ld.test.mjs +56 -4
  72. package/dist/sig/mod.cjs +2 -2
  73. package/dist/sig/mod.d.cts +3 -3
  74. package/dist/sig/mod.d.ts +3 -3
  75. package/dist/sig/mod.js +2 -2
  76. package/dist/sig/owner.test.mjs +105 -6
  77. package/dist/sig/proof.test.mjs +72 -3
  78. package/dist/{temporal-B4rBDksp.mjs → temporal-DPJlkHh3.mjs} +1 -1
  79. package/dist/{types-m8u9L86X.cjs → types-DWs-qZaY.cjs} +94 -2
  80. package/dist/{types-DTONwNqL.js → types-sXITXcWa.js} +78 -4
  81. package/dist/utils/docloader.test.mjs +28 -4
  82. package/dist/utils/kv-cache.test.mjs +1 -1
  83. package/dist/utils/mod.cjs +1 -1
  84. package/dist/utils/mod.d.cts +1 -1
  85. package/dist/utils/mod.d.ts +1 -1
  86. package/dist/utils/mod.js +1 -1
  87. package/package.json +5 -5
  88. package/dist/assert-ddO5KLpe.mjs +0 -23
  89. package/dist/owner-CFgyZgkz.mjs +0 -120
  90. /package/dist/{collection-ChgDTHLz.mjs → collection-DI6YzYpd.mjs} +0 -0
  91. /package/dist/{keys-CtZLJq76.mjs → keys-CCxRJhWa.mjs} +0 -0
  92. /package/dist/{kv-cache-DqEKe5E0.mjs → kv-cache-BrjuJue8.mjs} +0 -0
  93. /package/dist/{kv-BrZHNugx.mjs → kv-mI4Ix2EU.mjs} +0 -0
  94. /package/dist/{negotiation-BehA2uul.mjs → negotiation-TWEs6Cl8.mjs} +0 -0
  95. /package/dist/{retry-B_E3V_Dx.mjs → retry-Ddbq3AcK.mjs} +0 -0
  96. /package/dist/{types-C37hquWI.mjs → types-MNlFfxjv.mjs} +0 -0
@@ -2,10 +2,10 @@ const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  const require_chunk = require("./chunk-DDcVe30Y.cjs");
4
4
  const require_transformers = require("./transformers-NeAONrAq.cjs");
5
- const require_http = require("./http-BuaGj55w.cjs");
6
- const require_proof = require("./proof-BTKH7fe9.cjs");
7
- const require_types = require("./types-m8u9L86X.cjs");
8
- const require_kv_cache = require("./kv-cache-BVqMp1RC.cjs");
5
+ const require_http = require("./http-BgOlx4n1.cjs");
6
+ const require_types = require("./types-DWs-qZaY.cjs");
7
+ const require_proof = require("./proof-xCEe8t7U.cjs");
8
+ const require_kv_cache = require("./kv-cache-B8GaLaNy.cjs");
9
9
  let _logtape_logtape = require("@logtape/logtape");
10
10
  let _fedify_vocab = require("@fedify/vocab");
11
11
  let _opentelemetry_api = require("@opentelemetry/api");
@@ -335,7 +335,7 @@ var FederationBuilderImpl = class {
335
335
  this.collectionTypeIds = {};
336
336
  }
337
337
  async build(options) {
338
- const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-DcmlYd2c.cjs"));
338
+ const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-BKpP3cnZ.cjs"));
339
339
  const f = new FederationImpl(options);
340
340
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
341
341
  f.router = this.router.clone();
@@ -858,6 +858,7 @@ async function buildCollectionSynchronizationHeader(collectionId, actorIds) {
858
858
  //#region src/federation/keycache.ts
859
859
  const NULL_KEY_CACHE_VALUE = { _fedify: "key-unavailable" };
860
860
  const NULL_KEY_CACHE_TTL = Temporal.Duration.from({ minutes: 5 });
861
+ const KEY_CACHE_GENERATION = "2";
861
862
  function isNullKeyCacheValue(value) {
862
863
  return typeof value === "object" && value != null && "_fedify" in value && value._fedify === NULL_KEY_CACHE_VALUE._fedify;
863
864
  }
@@ -872,9 +873,16 @@ var KvKeyCache = class {
872
873
  this.nullKeys = /* @__PURE__ */ new Set();
873
874
  this.options = options;
874
875
  }
876
+ #entryKey(keyId) {
877
+ return [
878
+ ...this.prefix,
879
+ KEY_CACHE_GENERATION,
880
+ keyId.href
881
+ ];
882
+ }
875
883
  async get(keyId) {
876
884
  if (this.nullKeys.has(keyId.href)) return null;
877
- const serialized = await this.kv.get([...this.prefix, keyId.href]);
885
+ const serialized = await this.kv.get(this.#entryKey(keyId));
878
886
  if (serialized == null) return void 0;
879
887
  if (isNullKeyCacheValue(serialized)) {
880
888
  this.nullKeys.add(keyId.href);
@@ -886,7 +894,7 @@ var KvKeyCache = class {
886
894
  try {
887
895
  return await _fedify_vocab.Multikey.fromJsonLd(serialized, this.options);
888
896
  } catch {
889
- await this.kv.delete([...this.prefix, keyId.href]);
897
+ await this.kv.delete(this.#entryKey(keyId));
890
898
  return;
891
899
  }
892
900
  }
@@ -894,12 +902,12 @@ var KvKeyCache = class {
894
902
  async set(keyId, key) {
895
903
  if (key == null) {
896
904
  this.nullKeys.add(keyId.href);
897
- await this.kv.set([...this.prefix, keyId.href], NULL_KEY_CACHE_VALUE, { ttl: NULL_KEY_CACHE_TTL });
905
+ await this.kv.set(this.#entryKey(keyId), NULL_KEY_CACHE_VALUE, { ttl: NULL_KEY_CACHE_TTL });
898
906
  return;
899
907
  }
900
908
  this.nullKeys.delete(keyId.href);
901
909
  const serialized = await key.toJsonLd(this.options);
902
- await this.kv.set([...this.prefix, keyId.href], serialized);
910
+ await this.kv.set(this.#entryKey(keyId), serialized);
903
911
  }
904
912
  };
905
913
  //#endregion
@@ -1377,8 +1385,16 @@ async function handleInboxInternal(request, parameters, span) {
1377
1385
  }
1378
1386
  let json;
1379
1387
  try {
1380
- json = await request.clone().json();
1388
+ json = JSON.parse(await require_types.readBoundedText(request.clone(), require_types.MAX_BODY_SIZE, request.url));
1381
1389
  } catch (error) {
1390
+ if (error instanceof require_types.BodyTooLargeError) {
1391
+ request.body?.cancel(error).catch(() => {});
1392
+ span.setStatus({
1393
+ code: _opentelemetry_api.SpanStatusCode.ERROR,
1394
+ message: String(error)
1395
+ });
1396
+ return new Response("Inbox body too large.", { status: 413 });
1397
+ }
1382
1398
  logger.error("Failed to parse JSON:\n{error}", {
1383
1399
  recipient,
1384
1400
  error
@@ -2250,18 +2266,31 @@ async function readLimitedResponseBody(response, maxBytes) {
2250
2266
  if (truncated) result += "… (truncated)";
2251
2267
  return result;
2252
2268
  }
2253
- async function sendActivityInternal({ activity, activityId, keys, inbox, headers, specDeterminer, tracerProvider }, span) {
2269
+ async function sendActivityInternal({ activity, activityId, keys, inbox, allowPrivateAddress, headers, specDeterminer, tracerProvider }, span) {
2254
2270
  const logger = (0, _logtape_logtape.getLogger)([
2255
2271
  "fedify",
2256
2272
  "federation",
2257
2273
  "outbox"
2258
2274
  ]);
2275
+ async function validateUrl(url) {
2276
+ if (!allowPrivateAddress) try {
2277
+ await (0, _fedify_vocab_runtime.validatePublicUrl)(url);
2278
+ } catch (error) {
2279
+ if (error instanceof _fedify_vocab_runtime.UrlError) logger.error("Disallowed private URL: {url}", {
2280
+ url,
2281
+ error
2282
+ });
2283
+ throw error;
2284
+ }
2285
+ }
2286
+ await validateUrl(inbox.href);
2259
2287
  headers = new Headers(headers);
2260
2288
  headers.set("Content-Type", "application/activity+json");
2261
2289
  const request = new Request(inbox, {
2262
2290
  method: "POST",
2263
2291
  headers,
2264
- body: JSON.stringify(activity)
2292
+ body: JSON.stringify(activity),
2293
+ redirect: "manual"
2265
2294
  });
2266
2295
  let rsaKey = null;
2267
2296
  for (const key of keys) if (key.privateKey.algorithm.name === "RSASSA-PKCS1-v1_5") {
@@ -2277,9 +2306,10 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
2277
2306
  });
2278
2307
  let response;
2279
2308
  try {
2280
- response = rsaKey == null ? await fetch(request) : await require_http.doubleKnock(request, rsaKey, {
2309
+ response = rsaKey == null ? await fetchWithValidatedRedirects(request, validateUrl) : await require_http.doubleKnock(request, rsaKey, {
2281
2310
  tracerProvider,
2282
- specDeterminer
2311
+ specDeterminer,
2312
+ validateRedirect: validateUrl
2283
2313
  });
2284
2314
  } catch (error) {
2285
2315
  logger.error("Failed to send activity {activityId} to {inbox}:\n{error}", {
@@ -2311,6 +2341,49 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
2311
2341
  "activitypub.activity.id": activityId ?? ""
2312
2342
  });
2313
2343
  }
2344
+ async function fetchWithValidatedRedirects(request, validateUrl) {
2345
+ let body = await request.clone().text();
2346
+ for (let redirects = 0;; redirects++) {
2347
+ const response = await fetch(request, { redirect: "manual" });
2348
+ const location = response.headers.get("Location");
2349
+ if (![
2350
+ 301,
2351
+ 302,
2352
+ 303,
2353
+ 307,
2354
+ 308
2355
+ ].includes(response.status) || location == null) return response;
2356
+ await response.body?.cancel();
2357
+ if (redirects >= 20) throw new TypeError("Too many redirects");
2358
+ const url = new URL(location, request.url);
2359
+ await validateUrl(url.href);
2360
+ const headers = new Headers(request.headers);
2361
+ if (url.origin !== new URL(request.url).origin) {
2362
+ headers.delete("Authorization");
2363
+ headers.delete("Proxy-Authorization");
2364
+ headers.delete("Cookie");
2365
+ headers.delete("Host");
2366
+ }
2367
+ let method = request.method;
2368
+ if ((response.status === 301 || response.status === 302) && method === "POST" || response.status === 303 && method !== "GET" && method !== "HEAD") {
2369
+ method = "GET";
2370
+ body = void 0;
2371
+ for (const name of [
2372
+ "Content-Encoding",
2373
+ "Content-Language",
2374
+ "Content-Length",
2375
+ "Content-Location",
2376
+ "Content-Type"
2377
+ ]) headers.delete(name);
2378
+ }
2379
+ request = new Request(url, {
2380
+ method,
2381
+ headers,
2382
+ body,
2383
+ redirect: "manual"
2384
+ });
2385
+ }
2386
+ }
2314
2387
  /**
2315
2388
  * An error that is thrown when an activity fails to send to a remote inbox.
2316
2389
  * It contains structured information about the failure, including the HTTP
@@ -2809,6 +2882,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2809
2882
  }
2810
2883
  try {
2811
2884
  await sendActivity({
2885
+ allowPrivateAddress: this.allowPrivateAddress,
2812
2886
  keys,
2813
2887
  activity: message.activity,
2814
2888
  activityId: message.activityId,
@@ -3200,6 +3274,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3200
3274
  });
3201
3275
  const promises = [];
3202
3276
  for (const inbox in inboxes) promises.push(sendActivity({
3277
+ allowPrivateAddress: this.allowPrivateAddress,
3203
3278
  keys,
3204
3279
  activity: jsonLd,
3205
3280
  activityId: activity.id?.href,
@@ -4340,6 +4415,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
4340
4415
  else logger.debug("Forwarding activity immediately without queue since queue is not set.");
4341
4416
  const promises = [];
4342
4417
  for (const inbox in inboxes) promises.push(sendActivity({
4418
+ allowPrivateAddress: this.federation.allowPrivateAddress,
4343
4419
  keys,
4344
4420
  activity: this.activity,
4345
4421
  activityId: this.activityId,
@@ -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 { c as validateCryptoKey, i as exportJwk, l as name, r as verifyRequest, s as importJwk, t as doubleKnock, u as version } from "./http-BP1pVF9m.js";
6
- 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-ftbx50PI.js";
7
- import { n as getNodeInfo, t as nodeInfoToJson } from "./types-DTONwNqL.js";
8
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-CKg5W012.js";
5
+ import { c as importJwk, d as name, f as version, i as exportJwk, l as validateCryptoKey, r as verifyRequest, t as doubleKnock } from "./http-CwcG2wDs.js";
6
+ import { a as MAX_BODY_SIZE, i as BodyTooLargeError, n as getNodeInfo, o as readBoundedText, t as nodeInfoToJson } from "./types-sXITXcWa.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-DsJHFTkx.js";
8
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-lbswb9pg.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";
@@ -13,7 +13,7 @@ import { cloneDeep } from "es-toolkit";
13
13
  import { Router } from "uri-template-router";
14
14
  import { parseTemplate } from "url-template";
15
15
  import { encodeHex } from "byte-encodings/hex";
16
- import { getDocumentLoader } from "@fedify/vocab-runtime";
16
+ import { UrlError, getDocumentLoader, validatePublicUrl } from "@fedify/vocab-runtime";
17
17
  import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_HEADER, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
18
18
  import jsonld from "@fedify/vocab-runtime/jsonld";
19
19
  import { lookupWebFinger } from "@fedify/webfinger";
@@ -857,6 +857,7 @@ async function buildCollectionSynchronizationHeader(collectionId, actorIds) {
857
857
  //#region src/federation/keycache.ts
858
858
  const NULL_KEY_CACHE_VALUE = { _fedify: "key-unavailable" };
859
859
  const NULL_KEY_CACHE_TTL = Temporal.Duration.from({ minutes: 5 });
860
+ const KEY_CACHE_GENERATION = "2";
860
861
  function isNullKeyCacheValue(value) {
861
862
  return typeof value === "object" && value != null && "_fedify" in value && value._fedify === NULL_KEY_CACHE_VALUE._fedify;
862
863
  }
@@ -871,9 +872,16 @@ var KvKeyCache = class {
871
872
  this.nullKeys = /* @__PURE__ */ new Set();
872
873
  this.options = options;
873
874
  }
875
+ #entryKey(keyId) {
876
+ return [
877
+ ...this.prefix,
878
+ KEY_CACHE_GENERATION,
879
+ keyId.href
880
+ ];
881
+ }
874
882
  async get(keyId) {
875
883
  if (this.nullKeys.has(keyId.href)) return null;
876
- const serialized = await this.kv.get([...this.prefix, keyId.href]);
884
+ const serialized = await this.kv.get(this.#entryKey(keyId));
877
885
  if (serialized == null) return void 0;
878
886
  if (isNullKeyCacheValue(serialized)) {
879
887
  this.nullKeys.add(keyId.href);
@@ -885,7 +893,7 @@ var KvKeyCache = class {
885
893
  try {
886
894
  return await Multikey.fromJsonLd(serialized, this.options);
887
895
  } catch {
888
- await this.kv.delete([...this.prefix, keyId.href]);
896
+ await this.kv.delete(this.#entryKey(keyId));
889
897
  return;
890
898
  }
891
899
  }
@@ -893,12 +901,12 @@ var KvKeyCache = class {
893
901
  async set(keyId, key) {
894
902
  if (key == null) {
895
903
  this.nullKeys.add(keyId.href);
896
- await this.kv.set([...this.prefix, keyId.href], NULL_KEY_CACHE_VALUE, { ttl: NULL_KEY_CACHE_TTL });
904
+ await this.kv.set(this.#entryKey(keyId), NULL_KEY_CACHE_VALUE, { ttl: NULL_KEY_CACHE_TTL });
897
905
  return;
898
906
  }
899
907
  this.nullKeys.delete(keyId.href);
900
908
  const serialized = await key.toJsonLd(this.options);
901
- await this.kv.set([...this.prefix, keyId.href], serialized);
909
+ await this.kv.set(this.#entryKey(keyId), serialized);
902
910
  }
903
911
  };
904
912
  //#endregion
@@ -1376,8 +1384,16 @@ async function handleInboxInternal(request, parameters, span) {
1376
1384
  }
1377
1385
  let json;
1378
1386
  try {
1379
- json = await request.clone().json();
1387
+ json = JSON.parse(await readBoundedText(request.clone(), MAX_BODY_SIZE, request.url));
1380
1388
  } catch (error) {
1389
+ if (error instanceof BodyTooLargeError) {
1390
+ request.body?.cancel(error).catch(() => {});
1391
+ span.setStatus({
1392
+ code: SpanStatusCode.ERROR,
1393
+ message: String(error)
1394
+ });
1395
+ return new Response("Inbox body too large.", { status: 413 });
1396
+ }
1381
1397
  logger.error("Failed to parse JSON:\n{error}", {
1382
1398
  recipient,
1383
1399
  error
@@ -2249,18 +2265,31 @@ async function readLimitedResponseBody(response, maxBytes) {
2249
2265
  if (truncated) result += "… (truncated)";
2250
2266
  return result;
2251
2267
  }
2252
- async function sendActivityInternal({ activity, activityId, keys, inbox, headers, specDeterminer, tracerProvider }, span) {
2268
+ async function sendActivityInternal({ activity, activityId, keys, inbox, allowPrivateAddress, headers, specDeterminer, tracerProvider }, span) {
2253
2269
  const logger = getLogger([
2254
2270
  "fedify",
2255
2271
  "federation",
2256
2272
  "outbox"
2257
2273
  ]);
2274
+ async function validateUrl(url) {
2275
+ if (!allowPrivateAddress) try {
2276
+ await validatePublicUrl(url);
2277
+ } catch (error) {
2278
+ if (error instanceof UrlError) logger.error("Disallowed private URL: {url}", {
2279
+ url,
2280
+ error
2281
+ });
2282
+ throw error;
2283
+ }
2284
+ }
2285
+ await validateUrl(inbox.href);
2258
2286
  headers = new Headers(headers);
2259
2287
  headers.set("Content-Type", "application/activity+json");
2260
2288
  const request = new Request(inbox, {
2261
2289
  method: "POST",
2262
2290
  headers,
2263
- body: JSON.stringify(activity)
2291
+ body: JSON.stringify(activity),
2292
+ redirect: "manual"
2264
2293
  });
2265
2294
  let rsaKey = null;
2266
2295
  for (const key of keys) if (key.privateKey.algorithm.name === "RSASSA-PKCS1-v1_5") {
@@ -2276,9 +2305,10 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
2276
2305
  });
2277
2306
  let response;
2278
2307
  try {
2279
- response = rsaKey == null ? await fetch(request) : await doubleKnock(request, rsaKey, {
2308
+ response = rsaKey == null ? await fetchWithValidatedRedirects(request, validateUrl) : await doubleKnock(request, rsaKey, {
2280
2309
  tracerProvider,
2281
- specDeterminer
2310
+ specDeterminer,
2311
+ validateRedirect: validateUrl
2282
2312
  });
2283
2313
  } catch (error) {
2284
2314
  logger.error("Failed to send activity {activityId} to {inbox}:\n{error}", {
@@ -2310,6 +2340,49 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
2310
2340
  "activitypub.activity.id": activityId ?? ""
2311
2341
  });
2312
2342
  }
2343
+ async function fetchWithValidatedRedirects(request, validateUrl) {
2344
+ let body = await request.clone().text();
2345
+ for (let redirects = 0;; redirects++) {
2346
+ const response = await fetch(request, { redirect: "manual" });
2347
+ const location = response.headers.get("Location");
2348
+ if (![
2349
+ 301,
2350
+ 302,
2351
+ 303,
2352
+ 307,
2353
+ 308
2354
+ ].includes(response.status) || location == null) return response;
2355
+ await response.body?.cancel();
2356
+ if (redirects >= 20) throw new TypeError("Too many redirects");
2357
+ const url = new URL(location, request.url);
2358
+ await validateUrl(url.href);
2359
+ const headers = new Headers(request.headers);
2360
+ if (url.origin !== new URL(request.url).origin) {
2361
+ headers.delete("Authorization");
2362
+ headers.delete("Proxy-Authorization");
2363
+ headers.delete("Cookie");
2364
+ headers.delete("Host");
2365
+ }
2366
+ let method = request.method;
2367
+ if ((response.status === 301 || response.status === 302) && method === "POST" || response.status === 303 && method !== "GET" && method !== "HEAD") {
2368
+ method = "GET";
2369
+ body = void 0;
2370
+ for (const name of [
2371
+ "Content-Encoding",
2372
+ "Content-Language",
2373
+ "Content-Length",
2374
+ "Content-Location",
2375
+ "Content-Type"
2376
+ ]) headers.delete(name);
2377
+ }
2378
+ request = new Request(url, {
2379
+ method,
2380
+ headers,
2381
+ body,
2382
+ redirect: "manual"
2383
+ });
2384
+ }
2385
+ }
2313
2386
  /**
2314
2387
  * An error that is thrown when an activity fails to send to a remote inbox.
2315
2388
  * It contains structured information about the failure, including the HTTP
@@ -2815,6 +2888,7 @@ var FederationImpl = class extends FederationBuilderImpl {
2815
2888
  }
2816
2889
  try {
2817
2890
  await sendActivity({
2891
+ allowPrivateAddress: this.allowPrivateAddress,
2818
2892
  keys,
2819
2893
  activity: message.activity,
2820
2894
  activityId: message.activityId,
@@ -3206,6 +3280,7 @@ var FederationImpl = class extends FederationBuilderImpl {
3206
3280
  });
3207
3281
  const promises = [];
3208
3282
  for (const inbox in inboxes) promises.push(sendActivity({
3283
+ allowPrivateAddress: this.allowPrivateAddress,
3209
3284
  keys,
3210
3285
  activity: jsonLd,
3211
3286
  activityId: activity.id?.href,
@@ -4346,6 +4421,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
4346
4421
  else logger.debug("Forwarding activity immediately without queue since queue is not set.");
4347
4422
  const promises = [];
4348
4423
  for (const inbox in inboxes) promises.push(sendActivity({
4424
+ allowPrivateAddress: this.federation.allowPrivateAddress,
4349
4425
  keys,
4350
4426
  activity: this.activity,
4351
4427
  activityId: this.activityId,
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { n as HttpMessageSignaturesSpecDeterminer } from "./http-RYvZHWMc.cjs";
2
+ import { n as HttpMessageSignaturesSpecDeterminer } from "./http-Bs6thuCC.cjs";
3
3
  import { n as KvStore, t as KvKey } from "./kv-gJ8LYbxX.cjs";
4
4
  import { DocumentLoader, DocumentLoaderFactoryOptions } from "@fedify/vocab-runtime";
5
5
  import { TracerProvider } from "@opentelemetry/api";
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { X as ActorDispatcher, Y as ActorAliasMapper, Z as ActorHandleMapper, mt as WebFingerLinksDispatcher, s as RequestContext } from "./context-DnsFj3yK.js";
2
+ import { X as ActorDispatcher, Y as ActorAliasMapper, Z as ActorHandleMapper, mt as WebFingerLinksDispatcher, s as RequestContext } from "./context-B21klrfz.js";
3
3
  import { Span, Tracer } from "@opentelemetry/api";
4
4
 
5
5
  //#region src/federation/webfinger.d.ts
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { X as ActorDispatcher, Y as ActorAliasMapper, Z as ActorHandleMapper, mt as WebFingerLinksDispatcher, s as RequestContext } from "./context-CJZHWLmz.cjs";
2
+ import { X as ActorDispatcher, Y as ActorAliasMapper, Z as ActorHandleMapper, mt as WebFingerLinksDispatcher, s as RequestContext } from "./context-M_MxoQgC.cjs";
3
3
  import { Span, Tracer } from "@opentelemetry/api";
4
4
 
5
5
  //#region src/federation/webfinger.d.ts
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { l as KeyCache } from "./http-C4D0ajx0.js";
2
+ import { l as KeyCache } from "./http-CDupyfOc.js";
3
3
  import { CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1 } from "@fedify/vocab";
4
4
  import { TracerProvider } from "@opentelemetry/api";
5
5
  import { DocumentLoader } from "@fedify/vocab-runtime";
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { l as KeyCache } from "./http-RYvZHWMc.cjs";
2
+ import { l as KeyCache } from "./http-Bs6thuCC.cjs";
3
3
  import { CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1 } from "@fedify/vocab";
4
4
  import { DocumentLoader } from "@fedify/vocab-runtime";
5
5
  import { TracerProvider } from "@opentelemetry/api";
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { n as HttpMessageSignaturesSpecDeterminer } from "./http-C4D0ajx0.js";
2
+ import { n as HttpMessageSignaturesSpecDeterminer } from "./http-CDupyfOc.js";
3
3
  import { n as KvStore, t as KvKey } from "./kv-D6hNiMTK.js";
4
4
  import { TracerProvider } from "@opentelemetry/api";
5
5
  import { DocumentLoader, DocumentLoaderFactoryOptions } from "@fedify/vocab-runtime";
package/dist/mod.cjs CHANGED
@@ -4,11 +4,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
4
  require("./chunk-DDcVe30Y.cjs");
5
5
  const require_transformers = require("./transformers-NeAONrAq.cjs");
6
6
  require("./compat/mod.cjs");
7
- const require_http = require("./http-BuaGj55w.cjs");
8
- const require_middleware = require("./middleware-BXwn4gnl.cjs");
9
- const require_proof = require("./proof-BTKH7fe9.cjs");
10
- const require_types = require("./types-m8u9L86X.cjs");
11
- const require_kv_cache = require("./kv-cache-BVqMp1RC.cjs");
7
+ const require_http = require("./http-BgOlx4n1.cjs");
8
+ const require_middleware = require("./middleware-D_7wZH27.cjs");
9
+ const require_types = require("./types-DWs-qZaY.cjs");
10
+ const require_proof = require("./proof-xCEe8t7U.cjs");
11
+ const require_kv_cache = require("./kv-cache-B8GaLaNy.cjs");
12
12
  const require_federation_mod = require("./federation/mod.cjs");
13
13
  require("./nodeinfo/mod.cjs");
14
14
  require("./runtime/mod.cjs");
package/dist/mod.d.cts CHANGED
@@ -1,13 +1,13 @@
1
1
  /// <reference lib="esnext.temporal" />
2
2
  import { a as InboundService, c as OutboundService, d as Software, f as Usage, i as parseNodeInfo, l as Protocol, n as ParseNodeInfoOptions, o as JsonValue, p as nodeInfoToJson, r as getNodeInfo, s as NodeInfo, t as GetNodeInfoOptions, u as Services } from "./client-CAM_bQXx.cjs";
3
- import { a as signRequest, c as FetchKeyResult, d as fetchKey, f as generateCryptoKeyPair, i as VerifyRequestOptions, l as KeyCache, n as HttpMessageSignaturesSpecDeterminer, o as verifyRequest, p as importJwk, r as SignRequestOptions, s as FetchKeyOptions, t as HttpMessageSignaturesSpec, u as exportJwk } from "./http-RYvZHWMc.cjs";
4
- import { i as getKeyOwner, n as GetKeyOwnerOptions, r as doesActorOwnKey, t as DoesActorOwnKeyOptions } from "./owner-DEvZuyOE.cjs";
5
- import { $ as AuthorizePredicate, A as CreateExponentialBackoffPolicyOptions, B as RespondWithObjectOptions, C as InboxListenerSetters, D as FederationOrigin, E as FederationKvPrefixes, F as createFederationBuilder, G as MessageQueue, H as respondWithObjectIfAcceptable, I as Router, J as ParallelMessageQueue, K as MessageQueueEnqueueOptions, L as RouterError, M as RetryPolicy, N as createExponentialBackoffPolicy, O as FederationQueueOptions, P as Message, Q as ActorKeyPairsDispatcher, R as RouterOptions, S as IdempotencyStrategy, T as Rfc6570Expression, U as InProcessMessageQueue, V as respondWithObject, W as InProcessMessageQueueOptions, X as ActorDispatcher, Y as ActorAliasMapper, Z as ActorHandleMapper, _ as FederationBuilder, _t as PageItems, a as InboxContext, at as CustomCollectionDispatcher, b as FederationStartQueueOptions, bt as ActivityTransformer, c as RouteActivityOptions, ct as NodeInfoDispatcher, d as ActorCallbackSetters, dt as OutboxErrorHandler, et as CollectionCounter, f as CollectionCallbackSetters, ft as OutboxPermanentFailureHandler, g as Federation, gt as SenderKeyPair, h as Federatable, ht as SendActivityError, i as GetSignedKeyOptions, it as CustomCollectionCursor, j as RetryContext, k as createFederation, l as SendActivityOptions, lt as ObjectAuthorizePredicate, m as CustomCollectionCallbackSetters, mt as WebFingerLinksDispatcher, n as Context, nt as CollectionDispatcher, o as ParseUriResult, ot as InboxErrorHandler, p as ConstructorWithTypeId, pt as SharedInboxKeyDispatcher, q as MessageQueueListenOptions, r as ForwardActivityOptions, rt as CustomCollectionCounter, s as RequestContext, st as InboxListener, t as ActorKeyPair, tt as CollectionCursor, u as SendActivityOptionsForCollection, ut as ObjectDispatcher, v as FederationFetchOptions, vt as buildCollectionSynchronizationHeader, w as ObjectCallbackSetters, x as IdempotencyKeyCallback, y as FederationOptions, yt as digest, z as RouterRouteResult } from "./context-CJZHWLmz.cjs";
3
+ import { a as signRequest, c as FetchKeyResult, d as fetchKey, f as generateCryptoKeyPair, i as VerifyRequestOptions, l as KeyCache, n as HttpMessageSignaturesSpecDeterminer, o as verifyRequest, p as importJwk, r as SignRequestOptions, s as FetchKeyOptions, t as HttpMessageSignaturesSpec, u as exportJwk } from "./http-Bs6thuCC.cjs";
4
+ import { i as getKeyOwner, n as GetKeyOwnerOptions, r as doesActorOwnKey, t as DoesActorOwnKeyOptions } from "./owner-B3hNQCG8.cjs";
5
+ import { $ as AuthorizePredicate, A as CreateExponentialBackoffPolicyOptions, B as RespondWithObjectOptions, C as InboxListenerSetters, D as FederationOrigin, E as FederationKvPrefixes, F as createFederationBuilder, G as MessageQueue, H as respondWithObjectIfAcceptable, I as Router, J as ParallelMessageQueue, K as MessageQueueEnqueueOptions, L as RouterError, M as RetryPolicy, N as createExponentialBackoffPolicy, O as FederationQueueOptions, P as Message, Q as ActorKeyPairsDispatcher, R as RouterOptions, S as IdempotencyStrategy, T as Rfc6570Expression, U as InProcessMessageQueue, V as respondWithObject, W as InProcessMessageQueueOptions, X as ActorDispatcher, Y as ActorAliasMapper, Z as ActorHandleMapper, _ as FederationBuilder, _t as PageItems, a as InboxContext, at as CustomCollectionDispatcher, b as FederationStartQueueOptions, bt as ActivityTransformer, c as RouteActivityOptions, ct as NodeInfoDispatcher, d as ActorCallbackSetters, dt as OutboxErrorHandler, et as CollectionCounter, f as CollectionCallbackSetters, ft as OutboxPermanentFailureHandler, g as Federation, gt as SenderKeyPair, h as Federatable, ht as SendActivityError, i as GetSignedKeyOptions, it as CustomCollectionCursor, j as RetryContext, k as createFederation, l as SendActivityOptions, lt as ObjectAuthorizePredicate, m as CustomCollectionCallbackSetters, mt as WebFingerLinksDispatcher, n as Context, nt as CollectionDispatcher, o as ParseUriResult, ot as InboxErrorHandler, p as ConstructorWithTypeId, pt as SharedInboxKeyDispatcher, q as MessageQueueListenOptions, r as ForwardActivityOptions, rt as CustomCollectionCounter, s as RequestContext, st as InboxListener, t as ActorKeyPair, tt as CollectionCursor, u as SendActivityOptionsForCollection, ut as ObjectDispatcher, v as FederationFetchOptions, vt as buildCollectionSynchronizationHeader, w as ObjectCallbackSetters, x as IdempotencyKeyCallback, y as FederationOptions, yt as digest, z as RouterRouteResult } from "./context-M_MxoQgC.cjs";
6
6
  import { a as MemoryKvStore, i as KvStoreSetOptions, n as KvStore, r as KvStoreListEntry, t as KvKey } from "./kv-gJ8LYbxX.cjs";
7
7
  import { actorDehydrator, autoIdAssigner, getDefaultActivityTransformers } from "./compat/mod.cjs";
8
- import { n as handleWebFinger, t as WebFingerHandlerParameters } from "./mod-43DJyETz.cjs";
9
- import { _ as verifyJsonLd, a as createProof, c as verifyProof, d as VerifyJsonLdOptions, f as VerifySignatureOptions, g as signJsonLd, h as detachSignature, i as VerifyProofOptions, l as CreateSignatureOptions, m as createSignature, n as SignObjectOptions, o as signObject, p as attachSignature, r as VerifyObjectOptions, s as verifyObject, t as CreateProofOptions, u as SignJsonLdOptions, v as verifySignature } from "./mod-CB6pc2pw.cjs";
10
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./mod-B2zB0rDg.cjs";
8
+ import { n as handleWebFinger, t as WebFingerHandlerParameters } from "./mod-Dp5dfH-i.cjs";
9
+ import { _ as verifyJsonLd, a as createProof, c as verifyProof, d as VerifyJsonLdOptions, f as VerifySignatureOptions, g as signJsonLd, h as detachSignature, i as VerifyProofOptions, l as CreateSignatureOptions, m as createSignature, n as SignObjectOptions, o as signObject, p as attachSignature, r as VerifyObjectOptions, s as verifyObject, t as CreateProofOptions, u as SignJsonLdOptions, v as verifySignature } from "./mod-IOWUF5Yr.cjs";
10
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./mod-Bt0eg_Lv.cjs";
11
11
  export * from "@fedify/vocab-runtime";
12
12
 
13
13
  //#region src/mod.d.ts
package/dist/mod.d.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  /// <reference lib="esnext.temporal" />
2
2
  import { a as InboundService, c as OutboundService, d as Software, f as Usage, i as parseNodeInfo, l as Protocol, n as ParseNodeInfoOptions, o as JsonValue, p as nodeInfoToJson, r as getNodeInfo, s as NodeInfo, t as GetNodeInfoOptions, u as Services } from "./client-CSddvgWN.js";
3
- import { a as signRequest, c as FetchKeyResult, d as fetchKey, f as generateCryptoKeyPair, i as VerifyRequestOptions, l as KeyCache, n as HttpMessageSignaturesSpecDeterminer, o as verifyRequest, p as importJwk, r as SignRequestOptions, s as FetchKeyOptions, t as HttpMessageSignaturesSpec, u as exportJwk } from "./http-C4D0ajx0.js";
4
- import { i as getKeyOwner, n as GetKeyOwnerOptions, r as doesActorOwnKey, t as DoesActorOwnKeyOptions } from "./owner-CnngXDNJ.js";
5
- import { $ as AuthorizePredicate, A as CreateExponentialBackoffPolicyOptions, B as RespondWithObjectOptions, C as InboxListenerSetters, D as FederationOrigin, E as FederationKvPrefixes, F as createFederationBuilder, G as MessageQueue, H as respondWithObjectIfAcceptable, I as Router, J as ParallelMessageQueue, K as MessageQueueEnqueueOptions, L as RouterError, M as RetryPolicy, N as createExponentialBackoffPolicy, O as FederationQueueOptions, P as Message, Q as ActorKeyPairsDispatcher, R as RouterOptions, S as IdempotencyStrategy, T as Rfc6570Expression, U as InProcessMessageQueue, V as respondWithObject, W as InProcessMessageQueueOptions, X as ActorDispatcher, Y as ActorAliasMapper, Z as ActorHandleMapper, _ as FederationBuilder, _t as PageItems, a as InboxContext, at as CustomCollectionDispatcher, b as FederationStartQueueOptions, bt as ActivityTransformer, c as RouteActivityOptions, ct as NodeInfoDispatcher, d as ActorCallbackSetters, dt as OutboxErrorHandler, et as CollectionCounter, f as CollectionCallbackSetters, ft as OutboxPermanentFailureHandler, g as Federation, gt as SenderKeyPair, h as Federatable, ht as SendActivityError, i as GetSignedKeyOptions, it as CustomCollectionCursor, j as RetryContext, k as createFederation, l as SendActivityOptions, lt as ObjectAuthorizePredicate, m as CustomCollectionCallbackSetters, mt as WebFingerLinksDispatcher, n as Context, nt as CollectionDispatcher, o as ParseUriResult, ot as InboxErrorHandler, p as ConstructorWithTypeId, pt as SharedInboxKeyDispatcher, q as MessageQueueListenOptions, r as ForwardActivityOptions, rt as CustomCollectionCounter, s as RequestContext, st as InboxListener, t as ActorKeyPair, tt as CollectionCursor, u as SendActivityOptionsForCollection, ut as ObjectDispatcher, v as FederationFetchOptions, vt as buildCollectionSynchronizationHeader, w as ObjectCallbackSetters, x as IdempotencyKeyCallback, y as FederationOptions, yt as digest, z as RouterRouteResult } from "./context-DnsFj3yK.js";
3
+ import { a as signRequest, c as FetchKeyResult, d as fetchKey, f as generateCryptoKeyPair, i as VerifyRequestOptions, l as KeyCache, n as HttpMessageSignaturesSpecDeterminer, o as verifyRequest, p as importJwk, r as SignRequestOptions, s as FetchKeyOptions, t as HttpMessageSignaturesSpec, u as exportJwk } from "./http-CDupyfOc.js";
4
+ import { i as getKeyOwner, n as GetKeyOwnerOptions, r as doesActorOwnKey, t as DoesActorOwnKeyOptions } from "./owner-CiBPcC6F.js";
5
+ import { $ as AuthorizePredicate, A as CreateExponentialBackoffPolicyOptions, B as RespondWithObjectOptions, C as InboxListenerSetters, D as FederationOrigin, E as FederationKvPrefixes, F as createFederationBuilder, G as MessageQueue, H as respondWithObjectIfAcceptable, I as Router, J as ParallelMessageQueue, K as MessageQueueEnqueueOptions, L as RouterError, M as RetryPolicy, N as createExponentialBackoffPolicy, O as FederationQueueOptions, P as Message, Q as ActorKeyPairsDispatcher, R as RouterOptions, S as IdempotencyStrategy, T as Rfc6570Expression, U as InProcessMessageQueue, V as respondWithObject, W as InProcessMessageQueueOptions, X as ActorDispatcher, Y as ActorAliasMapper, Z as ActorHandleMapper, _ as FederationBuilder, _t as PageItems, a as InboxContext, at as CustomCollectionDispatcher, b as FederationStartQueueOptions, bt as ActivityTransformer, c as RouteActivityOptions, ct as NodeInfoDispatcher, d as ActorCallbackSetters, dt as OutboxErrorHandler, et as CollectionCounter, f as CollectionCallbackSetters, ft as OutboxPermanentFailureHandler, g as Federation, gt as SenderKeyPair, h as Federatable, ht as SendActivityError, i as GetSignedKeyOptions, it as CustomCollectionCursor, j as RetryContext, k as createFederation, l as SendActivityOptions, lt as ObjectAuthorizePredicate, m as CustomCollectionCallbackSetters, mt as WebFingerLinksDispatcher, n as Context, nt as CollectionDispatcher, o as ParseUriResult, ot as InboxErrorHandler, p as ConstructorWithTypeId, pt as SharedInboxKeyDispatcher, q as MessageQueueListenOptions, r as ForwardActivityOptions, rt as CustomCollectionCounter, s as RequestContext, st as InboxListener, t as ActorKeyPair, tt as CollectionCursor, u as SendActivityOptionsForCollection, ut as ObjectDispatcher, v as FederationFetchOptions, vt as buildCollectionSynchronizationHeader, w as ObjectCallbackSetters, x as IdempotencyKeyCallback, y as FederationOptions, yt as digest, z as RouterRouteResult } from "./context-B21klrfz.js";
6
6
  import { a as MemoryKvStore, i as KvStoreSetOptions, n as KvStore, r as KvStoreListEntry, t as KvKey } from "./kv-D6hNiMTK.js";
7
7
  import { actorDehydrator, autoIdAssigner, getDefaultActivityTransformers } from "./compat/mod.js";
8
- import { n as handleWebFinger, t as WebFingerHandlerParameters } from "./mod-COgmn-UO.js";
9
- import { _ as verifyJsonLd, a as createProof, c as verifyProof, d as VerifyJsonLdOptions, f as VerifySignatureOptions, g as signJsonLd, h as detachSignature, i as VerifyProofOptions, l as CreateSignatureOptions, m as createSignature, n as SignObjectOptions, o as signObject, p as attachSignature, r as VerifyObjectOptions, s as verifyObject, t as CreateProofOptions, u as SignJsonLdOptions, v as verifySignature } from "./mod-CiQNNAQL.js";
10
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./mod-CD1youdZ.js";
8
+ import { n as handleWebFinger, t as WebFingerHandlerParameters } from "./mod-D24V_w-K.js";
9
+ import { _ as verifyJsonLd, a as createProof, c as verifyProof, d as VerifyJsonLdOptions, f as VerifySignatureOptions, g as signJsonLd, h as detachSignature, i as VerifyProofOptions, l as CreateSignatureOptions, m as createSignature, n as SignObjectOptions, o as signObject, p as attachSignature, r as VerifyObjectOptions, s as verifyObject, t as CreateProofOptions, u as SignJsonLdOptions, v as verifySignature } from "./mod-E7YM72JZ.js";
10
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./mod-XucBiDNd.js";
11
11
  export * from "@fedify/vocab-runtime";
12
12
 
13
13
  //#region src/mod.d.ts
package/dist/mod.js CHANGED
@@ -3,11 +3,11 @@ import { URLPattern } from "urlpattern-polyfill";
3
3
  import "./chunk-CRNNMoPX.js";
4
4
  import { n as autoIdAssigner, r as getDefaultActivityTransformers, t as actorDehydrator } from "./transformers-BGMIq1cs.js";
5
5
  import "./compat/mod.js";
6
- import { a as fetchKey, i as exportJwk, n as signRequest, o as generateCryptoKeyPair, r as verifyRequest, s as importJwk } from "./http-BP1pVF9m.js";
7
- 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-CwIT91Nc.js";
8
- import { _ as signJsonLd, a as doesActorOwnKey, b as verifySignature, d as createSignature, f as detachSignature, i as verifyProof, l as attachSignature, n as signObject, o as getKeyOwner, r as verifyObject, t as createProof, y as verifyJsonLd } from "./proof-ftbx50PI.js";
9
- import { n as getNodeInfo, r as parseNodeInfo, t as nodeInfoToJson } from "./types-DTONwNqL.js";
10
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-CKg5W012.js";
6
+ import { c as importJwk, i as exportJwk, n as signRequest, o as fetchKey, r as verifyRequest, s as generateCryptoKeyPair } from "./http-CwcG2wDs.js";
7
+ 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-DomxFoLd.js";
8
+ import { n as getNodeInfo, r as parseNodeInfo, t as nodeInfoToJson } from "./types-sXITXcWa.js";
9
+ import { _ as signJsonLd, a as doesActorOwnKey, b as verifySignature, d as createSignature, f as detachSignature, i as verifyProof, l as attachSignature, n as signObject, o as getKeyOwner, r as verifyObject, t as createProof, y as verifyJsonLd } from "./proof-DsJHFTkx.js";
10
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-lbswb9pg.js";
11
11
  import { InProcessMessageQueue, MemoryKvStore, ParallelMessageQueue } from "./federation/mod.js";
12
12
  import "./nodeinfo/mod.js";
13
13
  import "./runtime/mod.js";
@@ -4,7 +4,7 @@ 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
6
  import "../std__assert-Duiq_YC9.mjs";
7
- import { a as parseProtocol, c as parseUsage, i as parseOutboundService, n as parseInboundService, o as parseServices, r as parseNodeInfo, s as parseSoftware, t as getNodeInfo } from "../client-HLLGHiTU.mjs";
7
+ import { a as parseProtocol, c as parseUsage, i as parseOutboundService, n as parseInboundService, o as parseServices, r as parseNodeInfo, s as parseSoftware, t as getNodeInfo } from "../client-glFHmpn4.mjs";
8
8
  import { test } from "@fedify/fixture";
9
9
  //#region src/nodeinfo/client.test.ts
10
10
  test("getNodeInfo()", async (t) => {
@@ -967,5 +967,32 @@ test("parseUsage()", () => {
967
967
  localComments: 456
968
968
  });
969
969
  });
970
+ test("getNodeInfo() bounds both discovery and document responses", async () => {
971
+ esm_default.mockGlobal();
972
+ const base = "https://8.8.8.8";
973
+ const descriptor = { links: [{
974
+ rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
975
+ href: `${base}/nodeinfo`
976
+ }] };
977
+ let oversizedDescriptor = true;
978
+ let oversizedDocument = true;
979
+ const data = { padding: "a".repeat(256) };
980
+ try {
981
+ esm_default.get(`${base}/.well-known/nodeinfo`, () => new Response(JSON.stringify(descriptor), { headers: oversizedDescriptor ? { "Content-Length": String(16777217) } : {} }));
982
+ esm_default.get(`${base}/nodeinfo`, () => new Response(JSON.stringify(data), { headers: oversizedDocument ? { "Content-Length": String(16777217) } : {} }));
983
+ assertEquals(await getNodeInfo(base), void 0);
984
+ assertEquals(esm_default.callHistory.calls(`${base}/nodeinfo`).length, 0);
985
+ oversizedDescriptor = false;
986
+ assertEquals(await getNodeInfo(base), void 0);
987
+ assertEquals(await getNodeInfo(`${base}/nodeinfo`, {
988
+ direct: true,
989
+ parse: "none"
990
+ }), void 0);
991
+ oversizedDocument = false;
992
+ assertEquals(await getNodeInfo(base, { parse: "none" }), data);
993
+ } finally {
994
+ esm_default.hardReset();
995
+ }
996
+ });
970
997
  //#endregion
971
998
  export {};
@@ -4,8 +4,8 @@ globalThis.addEventListener = () => {};
4
4
  import { n as createRequestContext } from "../context-Juj6bdHC.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
6
  import "../std__assert-Duiq_YC9.mjs";
7
- import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
8
- import { a as createFederation, h as handleNodeInfoJrd, m as handleNodeInfo } from "../middleware-DpEJSmjy.mjs";
7
+ import { t as MemoryKvStore } from "../kv-mI4Ix2EU.mjs";
8
+ import { a as createFederation, h as handleNodeInfoJrd, m as handleNodeInfo } from "../middleware-BuVM1K-J.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  //#region src/nodeinfo/handler.test.ts
11
11
  test("handleNodeInfo()", async () => {
@@ -1,7 +1,7 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
- const require_types = require("../types-m8u9L86X.cjs");
4
+ const require_types = require("../types-DWs-qZaY.cjs");
5
5
  exports.getNodeInfo = require_types.getNodeInfo;
6
6
  exports.nodeInfoToJson = require_types.nodeInfoToJson;
7
7
  exports.parseNodeInfo = require_types.parseNodeInfo;
@@ -1,4 +1,4 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { n as getNodeInfo, r as parseNodeInfo, t as nodeInfoToJson } from "../types-DTONwNqL.js";
3
+ import { n as getNodeInfo, r as parseNodeInfo, t as nodeInfoToJson } from "../types-sXITXcWa.js";
4
4
  export { getNodeInfo, nodeInfoToJson, parseNodeInfo };