@fedify/fedify 2.0.25-dev.1855 → 2.0.25-dev.1858

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 (47) hide show
  1. package/dist/{builder-BZuyzrJx.mjs → builder-CFpTg_eq.mjs} +3 -3
  2. package/dist/compat/transformers.test.mjs +1 -1
  3. package/dist/{deno-DVBhmegn.mjs → deno-DtJvlokL.mjs} +1 -1
  4. package/dist/{docloader-BgrNfXI0.mjs → docloader-82GdtA28.mjs} +12 -8
  5. package/dist/federation/builder.test.mjs +1 -1
  6. package/dist/federation/handler.test.mjs +4 -4
  7. package/dist/federation/idempotency.test.mjs +2 -2
  8. package/dist/federation/inbox.test.mjs +1 -1
  9. package/dist/federation/middleware.test.mjs +6 -6
  10. package/dist/federation/mod.cjs +1 -1
  11. package/dist/federation/mod.js +1 -1
  12. package/dist/federation/send.test.mjs +3 -3
  13. package/dist/federation/temporal.test.mjs +1 -1
  14. package/dist/federation/webfinger.test.mjs +1 -1
  15. package/dist/{http-BKQY6y2O.cjs → http-BJthm2J_.cjs} +7 -5
  16. package/dist/{http-CKFGX3Fg.js → http-BYWWBhOq.js} +7 -5
  17. package/dist/{http-BBFvvyzy.mjs → http-Bv_lhHFl.mjs} +7 -5
  18. package/dist/{inbox-IpFM-wJt.mjs → inbox-FUzEJku8.mjs} +1 -1
  19. package/dist/{key-CVzKd6R4.mjs → key-Bo826V_z.mjs} +2 -2
  20. package/dist/{kv-cache-lr0n2SFk.cjs → kv-cache-B12mrhnD.cjs} +11 -7
  21. package/dist/{kv-cache-Bkle1eMl.js → kv-cache-B6QgMaMJ.js} +11 -7
  22. package/dist/{ld-CXcn2Th9.mjs → ld-DF60LHml.mjs} +2 -2
  23. package/dist/{middleware-BelywT7K.mjs → middleware-B-8X6xxN.mjs} +1 -1
  24. package/dist/{middleware-CC-yLQIA.mjs → middleware-Bm-DjKyv.mjs} +11 -11
  25. package/dist/{middleware-Y6LTajaG.cjs → middleware-DFdGQXSw.cjs} +4 -4
  26. package/dist/{middleware-Dzd6rzUB.js → middleware-DVa5OLiF.js} +3 -3
  27. package/dist/{middleware-0LZvjCyB.cjs → middleware-UVrpolqn.cjs} +1 -1
  28. package/dist/mod.cjs +4 -4
  29. package/dist/mod.js +4 -4
  30. package/dist/nodeinfo/handler.test.mjs +1 -1
  31. package/dist/{owner-DYgd5LnW.mjs → owner-00ayi59L.mjs} +2 -2
  32. package/dist/{proof-g59DPu4Z.mjs → proof-BEyMkKly.mjs} +2 -2
  33. package/dist/{proof-D3HypmAh.cjs → proof-T9k7u0if.cjs} +1 -1
  34. package/dist/{proof-Dqjloko3.js → proof-hhPGZVKF.js} +1 -1
  35. package/dist/{send-BlS56oPU.mjs → send-C4zJrFaj.mjs} +2 -2
  36. package/dist/sig/http.test.mjs +34 -3
  37. package/dist/sig/key.test.mjs +46 -1
  38. package/dist/sig/ld.test.mjs +2 -2
  39. package/dist/sig/mod.cjs +2 -2
  40. package/dist/sig/mod.js +2 -2
  41. package/dist/sig/owner.test.mjs +1 -1
  42. package/dist/sig/proof.test.mjs +1 -1
  43. package/dist/{temporal-zPTsnAMK.mjs → temporal-hSmkqSXV.mjs} +1 -1
  44. package/dist/utils/docloader.test.mjs +35 -2
  45. package/dist/utils/mod.cjs +1 -1
  46. package/dist/utils/mod.js +1 -1
  47. package/package.json +6 -6
@@ -2,8 +2,8 @@ import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as RouterError, t as Router } from "./router-CrMLXoOr.mjs";
5
- import { n as version, t as name } from "./deno-DVBhmegn.mjs";
6
- import { t as InboxListenerSet } from "./inbox-IpFM-wJt.mjs";
5
+ import { n as version, t as name } from "./deno-DtJvlokL.mjs";
6
+ import { t as InboxListenerSet } from "./inbox-FUzEJku8.mjs";
7
7
  import { getTypeId } from "@fedify/vocab";
8
8
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
9
9
  import { getLogger } from "@logtape/logtape";
@@ -42,7 +42,7 @@ var FederationBuilderImpl = class {
42
42
  this.collectionTypeIds = {};
43
43
  }
44
44
  async build(options) {
45
- const { FederationImpl } = await import("./middleware-BelywT7K.mjs");
45
+ const { FederationImpl } = await import("./middleware-B-8X6xxN.mjs");
46
46
  const f = new FederationImpl(options);
47
47
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
48
48
  f.router = this.router.clone();
@@ -5,7 +5,7 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
6
6
  import { t as assert } from "../assert-ddO5KLpe.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
8
- import { _ as autoIdAssigner, g as actorDehydrator, n as FederationImpl } from "../middleware-CC-yLQIA.mjs";
8
+ import { _ as autoIdAssigner, g as actorDehydrator, n as FederationImpl } from "../middleware-Bm-DjKyv.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  import { Follow, Person } from "@fedify/vocab";
11
11
  //#region src/compat/transformers.test.ts
@@ -3,6 +3,6 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  //#region deno.json
5
5
  var name = "@fedify/fedify";
6
- var version = "2.0.25-dev.1855+e105cb5b";
6
+ var version = "2.0.25-dev.1858+d1757cc7";
7
7
  //#endregion
8
8
  export { version as n, name as t };
@@ -1,8 +1,8 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { a as validateCryptoKey } from "./key-CVzKd6R4.mjs";
5
- import { n as doubleKnock } from "./http-BBFvvyzy.mjs";
4
+ import { a as validateCryptoKey } from "./key-Bo826V_z.mjs";
5
+ import { n as doubleKnock } from "./http-Bv_lhHFl.mjs";
6
6
  import { curry } from "es-toolkit";
7
7
  import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, validatePublicUrl } from "@fedify/vocab-runtime";
8
8
  import { getLogger } from "@logtape/logtape";
@@ -26,6 +26,16 @@ const logger = getLogger([
26
26
  function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, userAgent, specDeterminer, tracerProvider } = {}) {
27
27
  validateCryptoKey(identity.privateKey);
28
28
  async function load(url, options) {
29
+ await validateUrl(url);
30
+ return getRemoteDocument(url, await doubleKnock(createActivityPubRequest(url, { userAgent }), identity, {
31
+ specDeterminer,
32
+ log: curry(logRequest)(logger),
33
+ tracerProvider,
34
+ signal: options?.signal,
35
+ validateRedirect: validateUrl
36
+ }), load);
37
+ }
38
+ async function validateUrl(url) {
29
39
  if (!allowPrivateAddress) try {
30
40
  await validatePublicUrl(url);
31
41
  } catch (error) {
@@ -35,12 +45,6 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, userAge
35
45
  });
36
46
  throw error;
37
47
  }
38
- return getRemoteDocument(url, await doubleKnock(createActivityPubRequest(url, { userAgent }), identity, {
39
- specDeterminer,
40
- log: curry(logRequest)(logger),
41
- tracerProvider,
42
- signal: options?.signal
43
- }), load);
44
48
  }
45
49
  return load;
46
50
  }
@@ -5,7 +5,7 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { a as assertExists } from "../std__assert-Duiq_YC9.mjs";
6
6
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
8
- import { n as createFederationBuilder } from "../builder-BZuyzrJx.mjs";
8
+ import { n as createFederationBuilder } from "../builder-CFpTg_eq.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  import { Activity, Note, Person } from "@fedify/vocab";
11
11
  //#region src/federation/builder.test.ts
@@ -6,12 +6,12 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
6
  import "../std__assert-Duiq_YC9.mjs";
7
7
  import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
8
8
  import { t as assert } from "../assert-ddO5KLpe.mjs";
9
- import { s as signRequest } from "../http-BBFvvyzy.mjs";
9
+ import { s as signRequest } from "../http-Bv_lhHFl.mjs";
10
10
  import { a as rsaPrivateKey3, c as rsaPublicKey3, s as rsaPublicKey2 } from "../keys-CtZLJq76.mjs";
11
- import { a as compactJsonLd, f as signJsonLd } from "../ld-CXcn2Th9.mjs";
11
+ import { a as compactJsonLd, f as signJsonLd } from "../ld-DF60LHml.mjs";
12
12
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
13
- import { a as createFederation, c as handleCollection, d as handleObject, f as respondWithObject, l as handleCustomCollection, p as respondWithObjectIfAcceptable, s as handleActor, u as handleInbox } from "../middleware-CC-yLQIA.mjs";
14
- import { t as InboxListenerSet } from "../inbox-IpFM-wJt.mjs";
13
+ import { a as createFederation, c as handleCollection, d as handleObject, f as respondWithObject, l as handleCustomCollection, p as respondWithObjectIfAcceptable, s as handleActor, u as handleInbox } from "../middleware-Bm-DjKyv.mjs";
14
+ import { t as InboxListenerSet } from "../inbox-FUzEJku8.mjs";
15
15
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
16
16
  import { Create, Note, Person } from "@fedify/vocab";
17
17
  //#region src/federation/handler.test.ts
@@ -4,9 +4,9 @@ globalThis.addEventListener = () => {};
4
4
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import "../std__assert-Duiq_YC9.mjs";
6
6
  import { n as ed25519PrivateKey, r as ed25519PublicKey, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
7
- import { n as signObject } from "../proof-g59DPu4Z.mjs";
7
+ import { n as signObject } from "../proof-BEyMkKly.mjs";
8
8
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
9
- import { a as createFederation } from "../middleware-CC-yLQIA.mjs";
9
+ import { a as createFederation } from "../middleware-Bm-DjKyv.mjs";
10
10
  import { mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { Create, Follow, Person } from "@fedify/vocab";
12
12
  //#region src/federation/idempotency.test.ts
@@ -3,7 +3,7 @@ import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
6
- import { t as InboxListenerSet } from "../inbox-IpFM-wJt.mjs";
6
+ import { t as InboxListenerSet } from "../inbox-FUzEJku8.mjs";
7
7
  import { test } from "@fedify/fixture";
8
8
  import { Activity, Create, Invite, Offer, Update } from "@fedify/vocab";
9
9
  //#region src/federation/inbox.test.ts
@@ -10,14 +10,14 @@ import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
10
10
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
11
11
  import { t as assertNotEquals } from "../assert_not_equals--wG9hV7u.mjs";
12
12
  import { t as assert } from "../assert-ddO5KLpe.mjs";
13
- import { l as verifyRequest, s as signRequest } from "../http-BBFvvyzy.mjs";
13
+ import { l as verifyRequest, s as signRequest } from "../http-Bv_lhHFl.mjs";
14
14
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
15
- import { t as getAuthenticatedDocumentLoader } from "../docloader-BgrNfXI0.mjs";
16
- import { a as compactJsonLd, f as signJsonLd, m as verifyJsonLd, s as detachSignature } from "../ld-CXcn2Th9.mjs";
17
- import { t as doesActorOwnKey } from "../owner-DYgd5LnW.mjs";
18
- import { n as signObject, r as verifyObject } from "../proof-g59DPu4Z.mjs";
15
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-82GdtA28.mjs";
16
+ import { a as compactJsonLd, f as signJsonLd, m as verifyJsonLd, s as detachSignature } from "../ld-DF60LHml.mjs";
17
+ import { t as doesActorOwnKey } from "../owner-00ayi59L.mjs";
18
+ import { n as signObject, r as verifyObject } from "../proof-BEyMkKly.mjs";
19
19
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
20
- import { a as createFederation, i as KvSpecDeterminer, n as FederationImpl, r as InboxContextImpl, t as ContextImpl } from "../middleware-CC-yLQIA.mjs";
20
+ import { a as createFederation, i as KvSpecDeterminer, n as FederationImpl, r as InboxContextImpl, t as ContextImpl } from "../middleware-Bm-DjKyv.mjs";
21
21
  import { mockDocumentLoader, test } from "@fedify/fixture";
22
22
  import * as vocab from "@fedify/vocab";
23
23
  import { Create, Offer, Person, getTypeId, lookupObject } from "@fedify/vocab";
@@ -2,7 +2,7 @@ const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
4
  require("../chunk-DDcVe30Y.cjs");
5
- const require_middleware = require("../middleware-Y6LTajaG.cjs");
5
+ const require_middleware = require("../middleware-DFdGQXSw.cjs");
6
6
  let es_toolkit = require("es-toolkit");
7
7
  //#region src/federation/kv.ts
8
8
  /**
@@ -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-Dzd6rzUB.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-DVa5OLiF.js";
4
4
  import { isEqual } from "es-toolkit";
5
5
  //#region src/federation/kv.ts
6
6
  /**
@@ -8,10 +8,10 @@ import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z
8
8
  import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
9
9
  import { t as assertNotEquals } from "../assert_not_equals--wG9hV7u.mjs";
10
10
  import { t as assert } from "../assert-ddO5KLpe.mjs";
11
- import { l as verifyRequest } from "../http-BBFvvyzy.mjs";
11
+ import { l as verifyRequest } from "../http-Bv_lhHFl.mjs";
12
12
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
13
- import { t as doesActorOwnKey } from "../owner-DYgd5LnW.mjs";
14
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-BlS56oPU.mjs";
13
+ import { t as doesActorOwnKey } from "../owner-00ayi59L.mjs";
14
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-C4zJrFaj.mjs";
15
15
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
16
16
  import { Activity, Application, Endpoints, Group, Person, Service } from "@fedify/vocab";
17
17
  //#region src/federation/send.test.ts
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
4
4
  import "../std__assert-Duiq_YC9.mjs";
5
5
  import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
6
6
  import { t as assert } from "../assert-ddO5KLpe.mjs";
7
- import { t as hasMalformedKnownTemporalLiteral } from "../temporal-zPTsnAMK.mjs";
7
+ import { t as hasMalformedKnownTemporalLiteral } from "../temporal-hSmkqSXV.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 () => {
@@ -5,7 +5,7 @@ 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
7
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
8
- import { a as createFederation, o as handleWebFinger } from "../middleware-CC-yLQIA.mjs";
8
+ import { a as createFederation, o as handleWebFinger } from "../middleware-Bm-DjKyv.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
@@ -11,7 +11,7 @@ let byte_encodings_base64 = require("byte-encodings/base64");
11
11
  let structured_field_values = require("structured-field-values");
12
12
  //#region deno.json
13
13
  var name = "@fedify/fedify";
14
- var version = "2.0.25-dev.1855+e105cb5b";
14
+ var version = "2.0.25-dev.1858+d1757cc7";
15
15
  //#endregion
16
16
  //#region src/sig/key.ts
17
17
  /**
@@ -199,7 +199,7 @@ async function fetchKeyInternal(keyId, cls, { documentLoader, contextLoader, key
199
199
  }
200
200
  }
201
201
  let key = null;
202
- if (object instanceof cls) key = object;
202
+ if (object instanceof cls && (object.id == null || object.id.href === keyId)) key = object;
203
203
  else if ((0, _fedify_vocab.isActor)(object)) {
204
204
  const keys = cls === _fedify_vocab.CryptographicKey ? object.getPublicKeys({
205
205
  documentLoader,
@@ -943,10 +943,12 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
943
943
  * @param request The original request.
944
944
  * @param location The redirect location.
945
945
  * @param body The request body as ArrayBuffer or null.
946
+ * @param validateRedirect The function to validate the redirect URL.
946
947
  * @returns A new Request object for the redirect.
947
948
  */
948
- function createRedirectRequest(request, location, body) {
949
+ async function createRedirectRequest(request, location, body, validateRedirect) {
949
950
  const url = new URL(location, request.url);
951
+ await validateRedirect?.(url.href);
950
952
  return new Request(url, {
951
953
  method: request.method,
952
954
  headers: request.headers,
@@ -1043,7 +1045,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1043
1045
  let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1044
1046
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1045
1047
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new _fedify_vocab_runtime.FetchError(request.url, `Too many redirections (${redirected + 1})`);
1046
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
1048
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
1047
1049
  if (visited.has(redirectRequest.url)) throw new _fedify_vocab_runtime.FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1048
1050
  return doubleKnockInternal(redirectRequest, identity, {
1049
1051
  ...options,
@@ -1070,7 +1072,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1070
1072
  response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1071
1073
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1072
1074
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new _fedify_vocab_runtime.FetchError(request.url, `Too many redirections (${redirected + 1})`);
1073
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
1075
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
1074
1076
  if (visited.has(redirectRequest.url)) throw new _fedify_vocab_runtime.FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1075
1077
  return doubleKnockInternal(redirectRequest, identity, {
1076
1078
  ...options,
@@ -10,7 +10,7 @@ import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
10
10
  import { Item, decodeDict, encodeItem } from "structured-field-values";
11
11
  //#region deno.json
12
12
  var name = "@fedify/fedify";
13
- var version = "2.0.25-dev.1855+e105cb5b";
13
+ var version = "2.0.25-dev.1858+d1757cc7";
14
14
  //#endregion
15
15
  //#region src/sig/key.ts
16
16
  /**
@@ -198,7 +198,7 @@ async function fetchKeyInternal(keyId, cls, { documentLoader, contextLoader, key
198
198
  }
199
199
  }
200
200
  let key = null;
201
- if (object instanceof cls) key = object;
201
+ if (object instanceof cls && (object.id == null || object.id.href === keyId)) key = object;
202
202
  else if (isActor(object)) {
203
203
  const keys = cls === CryptographicKey ? object.getPublicKeys({
204
204
  documentLoader,
@@ -942,10 +942,12 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
942
942
  * @param request The original request.
943
943
  * @param location The redirect location.
944
944
  * @param body The request body as ArrayBuffer or null.
945
+ * @param validateRedirect The function to validate the redirect URL.
945
946
  * @returns A new Request object for the redirect.
946
947
  */
947
- function createRedirectRequest(request, location, body) {
948
+ async function createRedirectRequest(request, location, body, validateRedirect) {
948
949
  const url = new URL(location, request.url);
950
+ await validateRedirect?.(url.href);
949
951
  return new Request(url, {
950
952
  method: request.method,
951
953
  headers: request.headers,
@@ -1042,7 +1044,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1042
1044
  let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1043
1045
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1044
1046
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
1045
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
1047
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
1046
1048
  if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1047
1049
  return doubleKnockInternal(redirectRequest, identity, {
1048
1050
  ...options,
@@ -1069,7 +1071,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1069
1071
  response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1070
1072
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1071
1073
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
1072
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
1074
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
1073
1075
  if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1074
1076
  return doubleKnockInternal(redirectRequest, identity, {
1075
1077
  ...options,
@@ -1,8 +1,8 @@
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-DVBhmegn.mjs";
5
- import { a as validateCryptoKey, n as fetchKey } from "./key-CVzKd6R4.mjs";
4
+ import { n as version, t as name } from "./deno-DtJvlokL.mjs";
5
+ import { a as validateCryptoKey, n as fetchKey } from "./key-Bo826V_z.mjs";
6
6
  import { CryptographicKey } from "@fedify/vocab";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { FetchError } from "@fedify/vocab-runtime";
@@ -685,10 +685,12 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
685
685
  * @param request The original request.
686
686
  * @param location The redirect location.
687
687
  * @param body The request body as ArrayBuffer or null.
688
+ * @param validateRedirect The function to validate the redirect URL.
688
689
  * @returns A new Request object for the redirect.
689
690
  */
690
- function createRedirectRequest(request, location, body) {
691
+ async function createRedirectRequest(request, location, body, validateRedirect) {
691
692
  const url = new URL(location, request.url);
693
+ await validateRedirect?.(url.href);
692
694
  return new Request(url, {
693
695
  method: request.method,
694
696
  headers: request.headers,
@@ -785,7 +787,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
785
787
  let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
786
788
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
787
789
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
788
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
790
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
789
791
  if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
790
792
  return doubleKnockInternal(redirectRequest, identity, {
791
793
  ...options,
@@ -812,7 +814,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
812
814
  response = await fetchDoubleKnockRequest(request, signedRequest, signal);
813
815
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
814
816
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
815
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
817
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
816
818
  if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
817
819
  return doubleKnockInternal(redirectRequest, identity, {
818
820
  ...options,
@@ -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-DVBhmegn.mjs";
4
+ import { n as version, t as name } from "./deno-DtJvlokL.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";
@@ -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-DVBhmegn.mjs";
4
+ import { n as version, t as name } from "./deno-DtJvlokL.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 { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -192,7 +192,7 @@ async function fetchKeyInternal(keyId, cls, { documentLoader, contextLoader, key
192
192
  }
193
193
  }
194
194
  let key = null;
195
- if (object instanceof cls) key = object;
195
+ if (object instanceof cls && (object.id == null || object.id.href === keyId)) key = object;
196
196
  else if (isActor(object)) {
197
197
  const keys = cls === CryptographicKey ? object.getPublicKeys({
198
198
  documentLoader,
@@ -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-BKQY6y2O.cjs");
4
+ const require_http = require("./http-BJthm2J_.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");
@@ -25,6 +25,16 @@ const logger$1 = (0, _logtape_logtape.getLogger)([
25
25
  function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, userAgent, specDeterminer, tracerProvider } = {}) {
26
26
  require_http.validateCryptoKey(identity.privateKey);
27
27
  async function load(url, options) {
28
+ await validateUrl(url);
29
+ return (0, _fedify_vocab_runtime.getRemoteDocument)(url, await require_http.doubleKnock((0, _fedify_vocab_runtime.createActivityPubRequest)(url, { userAgent }), identity, {
30
+ specDeterminer,
31
+ log: (0, es_toolkit.curry)(_fedify_vocab_runtime.logRequest)(logger$1),
32
+ tracerProvider,
33
+ signal: options?.signal,
34
+ validateRedirect: validateUrl
35
+ }), load);
36
+ }
37
+ async function validateUrl(url) {
28
38
  if (!allowPrivateAddress) try {
29
39
  await (0, _fedify_vocab_runtime.validatePublicUrl)(url);
30
40
  } catch (error) {
@@ -34,12 +44,6 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, userAge
34
44
  });
35
45
  throw error;
36
46
  }
37
- return (0, _fedify_vocab_runtime.getRemoteDocument)(url, await require_http.doubleKnock((0, _fedify_vocab_runtime.createActivityPubRequest)(url, { userAgent }), identity, {
38
- specDeterminer,
39
- log: (0, es_toolkit.curry)(_fedify_vocab_runtime.logRequest)(logger$1),
40
- tracerProvider,
41
- signal: options?.signal
42
- }), load);
43
47
  }
44
48
  return load;
45
49
  }
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { c as validateCryptoKey, t as doubleKnock } from "./http-CKFGX3Fg.js";
3
+ import { c as validateCryptoKey, t as doubleKnock } from "./http-BYWWBhOq.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { curry } from "es-toolkit";
6
6
  import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
@@ -24,6 +24,16 @@ const logger$1 = getLogger([
24
24
  function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, userAgent, specDeterminer, tracerProvider } = {}) {
25
25
  validateCryptoKey(identity.privateKey);
26
26
  async function load(url, options) {
27
+ await validateUrl(url);
28
+ return getRemoteDocument(url, await doubleKnock(createActivityPubRequest(url, { userAgent }), identity, {
29
+ specDeterminer,
30
+ log: curry(logRequest)(logger$1),
31
+ tracerProvider,
32
+ signal: options?.signal,
33
+ validateRedirect: validateUrl
34
+ }), load);
35
+ }
36
+ async function validateUrl(url) {
27
37
  if (!allowPrivateAddress) try {
28
38
  await validatePublicUrl(url);
29
39
  } catch (error) {
@@ -33,12 +43,6 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, userAge
33
43
  });
34
44
  throw error;
35
45
  }
36
- return getRemoteDocument(url, await doubleKnock(createActivityPubRequest(url, { userAgent }), identity, {
37
- specDeterminer,
38
- log: curry(logRequest)(logger$1),
39
- tracerProvider,
40
- signal: options?.signal
41
- }), load);
42
46
  }
43
47
  return load;
44
48
  }
@@ -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-DVBhmegn.mjs";
5
- import { a as validateCryptoKey, n as fetchKey } from "./key-CVzKd6R4.mjs";
4
+ import { n as version, t as name } from "./deno-DtJvlokL.mjs";
5
+ import { a as validateCryptoKey, n as fetchKey } from "./key-Bo826V_z.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";
@@ -1,5 +1,5 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as FederationImpl } from "./middleware-CC-yLQIA.mjs";
4
+ import { n as FederationImpl } from "./middleware-Bm-DjKyv.mjs";
5
5
  export { FederationImpl };
@@ -2,24 +2,24 @@ 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-DVBhmegn.mjs";
6
- import { a as validateCryptoKey, i as importJwk, t as exportJwk } from "./key-CVzKd6R4.mjs";
7
- import { l as verifyRequest } from "./http-BBFvvyzy.mjs";
8
- import { t as getAuthenticatedDocumentLoader } from "./docloader-BgrNfXI0.mjs";
5
+ import { n as version, t as name } from "./deno-DtJvlokL.mjs";
6
+ import { a as validateCryptoKey, i as importJwk, t as exportJwk } from "./key-Bo826V_z.mjs";
7
+ import { l as verifyRequest } from "./http-Bv_lhHFl.mjs";
8
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-82GdtA28.mjs";
9
9
  import { n as kvCache } from "./kv-cache-DqEKe5E0.mjs";
10
- 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-CXcn2Th9.mjs";
11
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-DYgd5LnW.mjs";
12
- import { n as signObject, r as verifyObject } from "./proof-g59DPu4Z.mjs";
10
+ 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-DF60LHml.mjs";
11
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-00ayi59L.mjs";
12
+ import { n as signObject, r as verifyObject } from "./proof-BEyMkKly.mjs";
13
13
  import { t as getNodeInfo } from "./client-HLLGHiTU.mjs";
14
14
  import { t as nodeInfoToJson } from "./types-C37hquWI.mjs";
15
- import { n as routeActivity } from "./inbox-IpFM-wJt.mjs";
16
- import { t as FederationBuilderImpl } from "./builder-BZuyzrJx.mjs";
15
+ import { n as routeActivity } from "./inbox-FUzEJku8.mjs";
16
+ import { t as FederationBuilderImpl } from "./builder-CFpTg_eq.mjs";
17
17
  import { t as buildCollectionSynchronizationHeader } from "./collection-ChgDTHLz.mjs";
18
18
  import { t as KvKeyCache } from "./keycache-DaQ3ndaJ.mjs";
19
19
  import { t as acceptsJsonLd } from "./negotiation-BehA2uul.mjs";
20
- import { t as hasMalformedKnownTemporalLiteral } from "./temporal-zPTsnAMK.mjs";
20
+ import { t as hasMalformedKnownTemporalLiteral } from "./temporal-hSmkqSXV.mjs";
21
21
  import { t as createExponentialBackoffPolicy } from "./retry-B_E3V_Dx.mjs";
22
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-BlS56oPU.mjs";
22
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-C4zJrFaj.mjs";
23
23
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
24
24
  import { lookupWebFinger } from "@fedify/webfinger";
25
25
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
@@ -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-BKQY6y2O.cjs");
6
- const require_proof = require("./proof-D3HypmAh.cjs");
5
+ const require_http = require("./http-BJthm2J_.cjs");
6
+ const require_proof = require("./proof-T9k7u0if.cjs");
7
7
  const require_types = require("./types-m8u9L86X.cjs");
8
- const require_kv_cache = require("./kv-cache-lr0n2SFk.cjs");
8
+ const require_kv_cache = require("./kv-cache-B12mrhnD.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-0LZvjCyB.cjs"));
338
+ const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-UVrpolqn.cjs"));
339
339
  const f = new FederationImpl(options);
340
340
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
341
341
  f.router = this.router.clone();
@@ -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-CKFGX3Fg.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-Dqjloko3.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-BYWWBhOq.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-hhPGZVKF.js";
7
7
  import { n as getNodeInfo, t as nodeInfoToJson } from "./types-DTONwNqL.js";
8
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-Bkle1eMl.js";
8
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-B6QgMaMJ.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";
@@ -1,4 +1,4 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
- const require_middleware = require("./middleware-Y6LTajaG.cjs");
3
+ const require_middleware = require("./middleware-DFdGQXSw.cjs");
4
4
  exports.FederationImpl = require_middleware.FederationImpl;
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-BKQY6y2O.cjs");
8
- const require_middleware = require("./middleware-Y6LTajaG.cjs");
9
- const require_proof = require("./proof-D3HypmAh.cjs");
7
+ const require_http = require("./http-BJthm2J_.cjs");
8
+ const require_middleware = require("./middleware-DFdGQXSw.cjs");
9
+ const require_proof = require("./proof-T9k7u0if.cjs");
10
10
  const require_types = require("./types-m8u9L86X.cjs");
11
- const require_kv_cache = require("./kv-cache-lr0n2SFk.cjs");
11
+ const require_kv_cache = require("./kv-cache-B12mrhnD.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.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-CKFGX3Fg.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-Dzd6rzUB.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-Dqjloko3.js";
6
+ import { a as fetchKey, i as exportJwk, n as signRequest, o as generateCryptoKeyPair, r as verifyRequest, s as importJwk } from "./http-BYWWBhOq.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-DVa5OLiF.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-hhPGZVKF.js";
9
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-Bkle1eMl.js";
10
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-B6QgMaMJ.js";
11
11
  import { InProcessMessageQueue, MemoryKvStore, ParallelMessageQueue } from "./federation/mod.js";
12
12
  import "./nodeinfo/mod.js";
13
13
  import "./runtime/mod.js";
@@ -5,7 +5,7 @@ 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
7
  import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
8
- import { a as createFederation, h as handleNodeInfoJrd, m as handleNodeInfo } from "../middleware-CC-yLQIA.mjs";
8
+ import { a as createFederation, h as handleNodeInfoJrd, m as handleNodeInfo } from "../middleware-Bm-DjKyv.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  //#region src/nodeinfo/handler.test.ts
11
11
  test("handleNodeInfo()", async () => {
@@ -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-DVBhmegn.mjs";
5
- import "./key-CVzKd6R4.mjs";
4
+ import { n as version, t as name } from "./deno-DtJvlokL.mjs";
5
+ import "./key-Bo826V_z.mjs";
6
6
  import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
7
7
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -1,8 +1,8 @@
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-DVBhmegn.mjs";
5
- import { a as validateCryptoKey, n as fetchKey } from "./key-CVzKd6R4.mjs";
4
+ import { n as version, t as name } from "./deno-DtJvlokL.mjs";
5
+ import { a as validateCryptoKey, n as fetchKey } from "./key-Bo826V_z.mjs";
6
6
  import { Activity, DataIntegrityProof, Multikey, getTypeId } from "@fedify/vocab";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { getLogger } from "@logtape/logtape";
@@ -1,7 +1,7 @@
1
1
  const { Temporal } = require("@js-temporal/polyfill");
2
2
  const { URLPattern } = require("urlpattern-polyfill");
3
3
  const require_chunk = require("./chunk-DDcVe30Y.cjs");
4
- const require_http = require("./http-BKQY6y2O.cjs");
4
+ const require_http = require("./http-BJthm2J_.cjs");
5
5
  let _logtape_logtape = require("@logtape/logtape");
6
6
  let _fedify_vocab = require("@fedify/vocab");
7
7
  let _opentelemetry_api = require("@opentelemetry/api");
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { a as fetchKey, c as validateCryptoKey, l as name, u as version } from "./http-CKFGX3Fg.js";
3
+ import { a as fetchKey, c as validateCryptoKey, l as name, u as version } from "./http-BYWWBhOq.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { Activity, CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1, getTypeId, isActor } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
@@ -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-DVBhmegn.mjs";
5
- import { n as doubleKnock } from "./http-BBFvvyzy.mjs";
4
+ import { n as version, t as name } from "./deno-DtJvlokL.mjs";
5
+ import { n as doubleKnock } from "./http-Bv_lhHFl.mjs";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
7
7
  import { getLogger } from "@logtape/logtape";
8
8
  //#region src/federation/send.ts
@@ -7,8 +7,8 @@ import { a as assertExists, t as assertStringIncludes } from "../std__assert-Dui
7
7
  import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
8
8
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
9
9
  import { t as assert } from "../assert-ddO5KLpe.mjs";
10
- import { t as exportJwk } from "../key-CVzKd6R4.mjs";
11
- import { a as parseRfc9421Signature, c as timingSafeEqual, i as formatRfc9421SignatureParameters, l as verifyRequest, n as doubleKnock, o as parseRfc9421SignatureInput, r as formatRfc9421Signature, s as signRequest, t as createRfc9421SignatureBase } from "../http-BBFvvyzy.mjs";
10
+ import { t as exportJwk } from "../key-Bo826V_z.mjs";
11
+ import { a as parseRfc9421Signature, c as timingSafeEqual, i as formatRfc9421SignatureParameters, l as verifyRequest, n as doubleKnock, o as parseRfc9421SignatureInput, r as formatRfc9421Signature, s as signRequest, t as createRfc9421SignatureBase } from "../http-Bv_lhHFl.mjs";
12
12
  import { i as rsaPrivateKey2, l as rsaPublicKey5, o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-CtZLJq76.mjs";
13
13
  import { mockDocumentLoader, test } from "@fedify/fixture";
14
14
  import { FetchError, exportSpki } from "@fedify/vocab-runtime";
@@ -668,6 +668,7 @@ test("doubleKnock() function with redirect handling", async () => {
668
668
  esm_default.spyGlobal();
669
669
  const requestedUrls = [];
670
670
  const responseCodes = [];
671
+ const validatedRedirects = [];
671
672
  esm_default.post("https://example.com/redirect-endpoint", (cl) => {
672
673
  requestedUrls.push(cl.url);
673
674
  responseCodes.push(302);
@@ -685,11 +686,41 @@ test("doubleKnock() function with redirect handling", async () => {
685
686
  }), {
686
687
  keyId: rsaPublicKey2.id,
687
688
  privateKey: rsaPrivateKey2
688
- })).status, 202, "Final response status should be 202 Accepted");
689
+ }, { validateRedirect(url) {
690
+ validatedRedirects.push(url);
691
+ } })).status, 202, "Final response status should be 202 Accepted");
689
692
  assertEquals(requestedUrls.length, 2, "Two URLs should have been requested");
690
693
  assertEquals(requestedUrls[0], "https://example.com/redirect-endpoint", "First request should be to redirect-endpoint");
691
694
  assertEquals(requestedUrls[1], "https://example.com/final-endpoint", "Second request should be to final-endpoint");
692
695
  assertEquals(responseCodes, [302, 202], "Response status codes should match expected sequence");
696
+ assertEquals(validatedRedirects, ["https://example.com/final-endpoint"]);
697
+ esm_default.hardReset();
698
+ });
699
+ test("doubleKnock() validates redirects after signature fallback", async () => {
700
+ esm_default.spyGlobal();
701
+ let requestCount = 0;
702
+ let privateRequestCount = 0;
703
+ esm_default.post("https://example.com/redirect-after-fallback", (cl) => {
704
+ requestCount++;
705
+ if (cl.request.headers.has("Signature-Input")) return new Response("Unauthorized", { status: 401 });
706
+ return Response.redirect("http://localhost/private", 302);
707
+ });
708
+ esm_default.post("http://localhost/private", () => {
709
+ privateRequestCount++;
710
+ return new Response("", { status: 202 });
711
+ });
712
+ const request = new Request("https://example.com/redirect-after-fallback", {
713
+ method: "POST",
714
+ body: "Test message"
715
+ });
716
+ await assertRejects(() => doubleKnock(request, {
717
+ keyId: rsaPublicKey2.id,
718
+ privateKey: rsaPrivateKey2
719
+ }, { validateRedirect(url) {
720
+ throw new Error(`Disallowed redirect: ${url}`);
721
+ } }), Error, "Disallowed redirect: http://localhost/private");
722
+ assertEquals(requestCount, 2);
723
+ assertEquals(privateRequestCount, 0);
693
724
  esm_default.hardReset();
694
725
  });
695
726
  test("doubleKnock() function with both specs rejected", async () => {
@@ -5,7 +5,7 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import "../std__assert-Duiq_YC9.mjs";
6
6
  import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
8
- import { a as validateCryptoKey, i as importJwk, n as fetchKey, r as generateCryptoKeyPair, t as exportJwk } from "../key-CVzKd6R4.mjs";
8
+ import { a as validateCryptoKey, i as importJwk, n as fetchKey, r as generateCryptoKeyPair, t as exportJwk } from "../key-Bo826V_z.mjs";
9
9
  import { c as rsaPublicKey3, i as rsaPrivateKey2, o as rsaPublicKey1, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
10
10
  import { mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { CryptographicKey, Multikey } from "@fedify/vocab";
@@ -236,6 +236,51 @@ test("fetchKey()", async () => {
236
236
  cached: false
237
237
  });
238
238
  });
239
+ test("fetchKey() rejects standalone keys with a mismatched id", async () => {
240
+ for (const { keyId, standaloneKey, fetch } of [{
241
+ keyId: "https://example.com/key",
242
+ standaloneKey: rsaPublicKey1,
243
+ fetch: (keyId, options) => fetchKey(keyId, CryptographicKey, options)
244
+ }, {
245
+ keyId: "https://example.com/multikey",
246
+ standaloneKey: ed25519Multikey,
247
+ fetch: (keyId, options) => fetchKey(keyId, Multikey, options)
248
+ }]) {
249
+ const cache = {};
250
+ const options = {
251
+ async documentLoader(resource) {
252
+ if (resource === keyId) return {
253
+ contextUrl: null,
254
+ documentUrl: resource,
255
+ document: {
256
+ ...await standaloneKey.toJsonLd({ contextLoader: mockDocumentLoader }),
257
+ id: "https://example.com/different-key"
258
+ }
259
+ };
260
+ return await mockDocumentLoader(resource);
261
+ },
262
+ contextLoader: mockDocumentLoader,
263
+ keyCache: {
264
+ get(keyId) {
265
+ return Promise.resolve(cache[keyId.href]);
266
+ },
267
+ set(keyId, key) {
268
+ cache[keyId.href] = key;
269
+ return Promise.resolve();
270
+ }
271
+ }
272
+ };
273
+ assertEquals(await fetch(keyId, options), {
274
+ key: null,
275
+ cached: false
276
+ });
277
+ assertEquals(cache, { [keyId]: null });
278
+ assertEquals(await fetch(keyId, options), {
279
+ key: null,
280
+ cached: true
281
+ });
282
+ }
283
+ });
239
284
  test("fetchKey() returns null for a malformed actor publicKey", async () => {
240
285
  const actorId = "https://example.com/malformed-public-key";
241
286
  const keyId = "https://example.com/malformed-public-key#main-key";
@@ -5,9 +5,9 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
6
6
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
7
7
  import { t as assert } from "../assert-ddO5KLpe.mjs";
8
- import { r as generateCryptoKeyPair } from "../key-CVzKd6R4.mjs";
8
+ import { r as generateCryptoKeyPair } from "../key-Bo826V_z.mjs";
9
9
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
10
- import { a as compactJsonLd, d as isInvalidUrlTypeError, f as signJsonLd, h as verifySignature, i as attachSignature, m as verifyJsonLd, n as UnsafeJsonLdError, o as createSignature, s as detachSignature } from "../ld-CXcn2Th9.mjs";
10
+ import { a as compactJsonLd, d as isInvalidUrlTypeError, f as signJsonLd, h as verifySignature, i as attachSignature, m as verifyJsonLd, n as UnsafeJsonLdError, o as createSignature, s as detachSignature } from "../ld-DF60LHml.mjs";
11
11
  import { mockDocumentLoader, test } from "@fedify/fixture";
12
12
  import { CryptographicKey } from "@fedify/vocab";
13
13
  import { encodeBase64 } from "byte-encodings/base64";
package/dist/sig/mod.cjs CHANGED
@@ -1,8 +1,8 @@
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_http = require("../http-BKQY6y2O.cjs");
5
- const require_proof = require("../proof-D3HypmAh.cjs");
4
+ const require_http = require("../http-BJthm2J_.cjs");
5
+ const require_proof = require("../proof-T9k7u0if.cjs");
6
6
  exports.attachSignature = require_proof.attachSignature;
7
7
  exports.createProof = require_proof.createProof;
8
8
  exports.createSignature = require_proof.createSignature;
package/dist/sig/mod.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { a as fetchKey, i as exportJwk, n as signRequest, o as generateCryptoKeyPair, r as verifyRequest, s as importJwk } from "../http-CKFGX3Fg.js";
4
- 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-Dqjloko3.js";
3
+ import { a as fetchKey, i as exportJwk, n as signRequest, o as generateCryptoKeyPair, r as verifyRequest, s as importJwk } from "../http-BYWWBhOq.js";
4
+ 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-hhPGZVKF.js";
5
5
  export { attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, generateCryptoKeyPair, getKeyOwner, importJwk, signJsonLd, signObject, signRequest, verifyJsonLd, verifyObject, verifyProof, verifyRequest, verifySignature };
@@ -6,7 +6,7 @@ import "../std__assert-Duiq_YC9.mjs";
6
6
  import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as assert } from "../assert-ddO5KLpe.mjs";
8
8
  import { o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-CtZLJq76.mjs";
9
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-DYgd5LnW.mjs";
9
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-00ayi59L.mjs";
10
10
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { Create, CryptographicKey, lookupObject } from "@fedify/vocab";
12
12
  //#region src/sig/owner.test.ts
@@ -6,7 +6,7 @@ import "../std__assert-Duiq_YC9.mjs";
6
6
  import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
8
8
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
9
- import { i as verifyProof, n as signObject, r as verifyObject, t as createProof } from "../proof-g59DPu4Z.mjs";
9
+ import { i as verifyProof, n as signObject, r as verifyObject, t as createProof } from "../proof-BEyMkKly.mjs";
10
10
  import { mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { Create, DataIntegrityProof, Multikey, Note, Place } from "@fedify/vocab";
12
12
  import { decodeMultibase, importMultibaseKey } from "@fedify/vocab-runtime";
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { c as getNormalizationContextLoader } from "./ld-CXcn2Th9.mjs";
4
+ import { c as getNormalizationContextLoader } from "./ld-DF60LHml.mjs";
5
5
  import jsonld from "@fedify/vocab-runtime/jsonld";
6
6
  //#region src/federation/temporal.ts
7
7
  function isPlainObject(value) {
@@ -5,9 +5,9 @@ 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
7
  import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
8
- import { l as verifyRequest } from "../http-BBFvvyzy.mjs";
8
+ import { l as verifyRequest } from "../http-Bv_lhHFl.mjs";
9
9
  import { i as rsaPrivateKey2 } from "../keys-CtZLJq76.mjs";
10
- import { t as getAuthenticatedDocumentLoader } from "../docloader-BgrNfXI0.mjs";
10
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-82GdtA28.mjs";
11
11
  import { mockDocumentLoader, test } from "@fedify/fixture";
12
12
  import { UrlError } from "@fedify/vocab-runtime";
13
13
  //#region src/utils/docloader.test.ts
@@ -47,6 +47,39 @@ test("getAuthenticatedDocumentLoader()", async (t) => {
47
47
  assertRejects(() => loader("http://localhost"), UrlError);
48
48
  });
49
49
  });
50
+ test("getAuthenticatedDocumentLoader() validates redirects", async (t) => {
51
+ esm_default.spyGlobal();
52
+ let privateRequestCount = 0;
53
+ esm_default.get("https://example.com/redirect-to-private", () => Response.redirect("http://localhost/private", 302));
54
+ esm_default.get("http://localhost/private", () => {
55
+ privateRequestCount++;
56
+ return Response.json({ private: true });
57
+ });
58
+ await t.step("deny public-to-private redirects", async () => {
59
+ const loader = getAuthenticatedDocumentLoader({
60
+ keyId: new URL("https://example.com/key2"),
61
+ privateKey: rsaPrivateKey2
62
+ });
63
+ await assertRejects(() => loader("https://example.com/redirect-to-private"), UrlError);
64
+ assertEquals(privateRequestCount, 0);
65
+ });
66
+ esm_default.get("https://example.com/redirect-to-public", () => Response.redirect("https://www.example.com/document", 302));
67
+ esm_default.get("https://www.example.com/document", () => Response.json({ public: true }));
68
+ await t.step("allow public-to-public redirects", async () => {
69
+ assertEquals((await getAuthenticatedDocumentLoader({
70
+ keyId: new URL("https://example.com/key2"),
71
+ privateKey: rsaPrivateKey2
72
+ })("https://example.com/redirect-to-public")).document, { public: true });
73
+ });
74
+ await t.step("allow private redirects when explicitly enabled", async () => {
75
+ assertEquals((await getAuthenticatedDocumentLoader({
76
+ keyId: new URL("https://example.com/key2"),
77
+ privateKey: rsaPrivateKey2
78
+ }, { allowPrivateAddress: true })("https://example.com/redirect-to-private")).document, { private: true });
79
+ assertEquals(privateRequestCount, 1);
80
+ });
81
+ esm_default.hardReset();
82
+ });
50
83
  test("getAuthenticatedDocumentLoader() cancellation", {
51
84
  sanitizeResources: false,
52
85
  sanitizeOps: false
@@ -1,6 +1,6 @@
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_kv_cache = require("../kv-cache-lr0n2SFk.cjs");
4
+ const require_kv_cache = require("../kv-cache-B12mrhnD.cjs");
5
5
  exports.getAuthenticatedDocumentLoader = require_kv_cache.getAuthenticatedDocumentLoader;
6
6
  exports.kvCache = require_kv_cache.kvCache;
package/dist/utils/mod.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-Bkle1eMl.js";
3
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-B6QgMaMJ.js";
4
4
  export { getAuthenticatedDocumentLoader, kvCache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/fedify",
3
- "version": "2.0.25-dev.1855+e105cb5b",
3
+ "version": "2.0.25-dev.1858+d1757cc7",
4
4
  "description": "An ActivityPub server framework",
5
5
  "keywords": [
6
6
  "ActivityPub",
@@ -144,9 +144,9 @@
144
144
  "uri-template-router": "^1.0.0",
145
145
  "url-template": "^3.1.1",
146
146
  "urlpattern-polyfill": "^10.1.0",
147
- "@fedify/vocab": "2.0.25-dev.1855+e105cb5b",
148
- "@fedify/vocab-runtime": "2.0.25-dev.1855+e105cb5b",
149
- "@fedify/webfinger": "2.0.25-dev.1855+e105cb5b"
147
+ "@fedify/vocab": "2.0.25-dev.1858+d1757cc7",
148
+ "@fedify/webfinger": "2.0.25-dev.1858+d1757cc7",
149
+ "@fedify/vocab-runtime": "2.0.25-dev.1858+d1757cc7"
150
150
  },
151
151
  "devDependencies": {
152
152
  "@std/assert": "npm:@jsr/std__assert@^0.226.0",
@@ -158,8 +158,8 @@
158
158
  "tsx": "^4.19.4",
159
159
  "typescript": "^6.0.0",
160
160
  "wrangler": "^4.17.0",
161
- "@fedify/vocab-tools": "^2.0.25-dev.1855+e105cb5b",
162
- "@fedify/fixture": "2.0.0"
161
+ "@fedify/fixture": "2.0.0",
162
+ "@fedify/vocab-tools": "^2.0.25-dev.1858+d1757cc7"
163
163
  },
164
164
  "scripts": {
165
165
  "build:self": "tsdown",