@fedify/fedify 2.2.8 → 2.2.10

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 (45) hide show
  1. package/dist/{builder-Hr1c39Ha.mjs → builder-BSmTnJcC.mjs} +2 -2
  2. package/dist/compat/transformers.test.mjs +1 -1
  3. package/dist/{deno-B_vGx2Ji.mjs → deno-dpXHD1Cg.mjs} +1 -1
  4. package/dist/{docloader-DixiMoIZ.mjs → docloader-Cu6YO4sl.mjs} +13 -9
  5. package/dist/federation/builder.test.mjs +1 -1
  6. package/dist/federation/handler.test.mjs +3 -3
  7. package/dist/federation/idempotency.test.mjs +2 -2
  8. package/dist/federation/middleware.test.mjs +6 -6
  9. package/dist/federation/mod.cjs +1 -1
  10. package/dist/federation/mod.js +1 -1
  11. package/dist/federation/send.test.mjs +3 -3
  12. package/dist/federation/temporal.test.mjs +1 -1
  13. package/dist/federation/webfinger.test.mjs +1 -1
  14. package/dist/{http-BlHW6_Oi.mjs → http-CIzMKh05.mjs} +8 -6
  15. package/dist/{http-C-FdpmAl.js → http-l1HqLnRo.js} +8 -6
  16. package/dist/{http-DLRpF855.cjs → http-pf3AXy99.cjs} +8 -6
  17. package/dist/{key-6U1u5H_H.mjs → key-C6KGyqT_.mjs} +2 -2
  18. package/dist/{kv-cache-DKprbYof.cjs → kv-cache-B_HA4cvx.cjs} +12 -8
  19. package/dist/{kv-cache-BjlL4Zk0.js → kv-cache-m9KwvJeU.js} +12 -8
  20. package/dist/{ld-DDBxn1rq.mjs → ld-aaLZ9vtX.mjs} +2 -2
  21. package/dist/{middleware-Ds3ujCKo.mjs → middleware-BoGC27UL.mjs} +1 -1
  22. package/dist/{middleware-Bj5UFOaT.cjs → middleware-CMx-gvcd.cjs} +4 -4
  23. package/dist/{middleware-DOkcTiZ-.js → middleware-CWtQVZ8j.js} +3 -3
  24. package/dist/{middleware-BJM6vrlT.mjs → middleware-De7RGKlL.mjs} +10 -10
  25. package/dist/{middleware-DNJYfRV4.cjs → middleware-VpIBr58-.cjs} +1 -1
  26. package/dist/mod.cjs +4 -4
  27. package/dist/mod.js +4 -4
  28. package/dist/nodeinfo/handler.test.mjs +1 -1
  29. package/dist/{owner-vuyMTd_f.mjs → owner-Bxd_RFAX.mjs} +2 -2
  30. package/dist/{proof-BNGY2IU6.cjs → proof-BOHbpbMG.cjs} +1 -1
  31. package/dist/{proof-BGrdGhcb.mjs → proof-BaKRMbnC.mjs} +2 -2
  32. package/dist/{proof-DA_wkPds.js → proof-CIoNWttk.js} +1 -1
  33. package/dist/{send-BvazsIXC.mjs → send-B1UTCW8F.mjs} +2 -2
  34. package/dist/sig/http.test.mjs +65 -3
  35. package/dist/sig/key.test.mjs +46 -1
  36. package/dist/sig/ld.test.mjs +2 -2
  37. package/dist/sig/mod.cjs +2 -2
  38. package/dist/sig/mod.js +2 -2
  39. package/dist/sig/owner.test.mjs +1 -1
  40. package/dist/sig/proof.test.mjs +1 -1
  41. package/dist/{temporal-MdUFasAg.mjs → temporal-jgauoetb.mjs} +1 -1
  42. package/dist/utils/docloader.test.mjs +35 -2
  43. package/dist/utils/mod.cjs +1 -1
  44. package/dist/utils/mod.js +1 -1
  45. package/package.json +6 -6
@@ -2,7 +2,7 @@ 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-B_vGx2Ji.mjs";
5
+ import { n as version, t as name } from "./deno-dpXHD1Cg.mjs";
6
6
  import { t as ActivityListenerSet } from "./activity-listener-ell7W1s9.mjs";
7
7
  import { Tombstone, getTypeId } from "@fedify/vocab";
8
8
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
@@ -58,7 +58,7 @@ var FederationBuilderImpl = class {
58
58
  this.collectionTypeIds = {};
59
59
  }
60
60
  async build(options) {
61
- const { FederationImpl } = await import("./middleware-Ds3ujCKo.mjs");
61
+ const { FederationImpl } = await import("./middleware-BoGC27UL.mjs");
62
62
  const f = new FederationImpl(options);
63
63
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
64
64
  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-DikXweDx.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
8
- import { n as FederationImpl, v as actorDehydrator, y as autoIdAssigner } from "../middleware-BJM6vrlT.mjs";
8
+ import { n as FederationImpl, v as actorDehydrator, y as autoIdAssigner } from "../middleware-De7RGKlL.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.2.8";
6
+ var version = "2.2.10";
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 { o as validateCryptoKey } from "./key-6U1u5H_H.mjs";
5
- import { n as doubleKnock } from "./http-BlHW6_Oi.mjs";
4
+ import { o as validateCryptoKey } from "./key-C6KGyqT_.mjs";
5
+ import { n as doubleKnock } from "./http-CIzMKh05.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,17 @@ const logger = getLogger([
26
26
  function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedirection, 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
+ maxRedirection,
32
+ specDeterminer,
33
+ log: curry(logRequest)(logger),
34
+ tracerProvider,
35
+ signal: options?.signal,
36
+ validateRedirect: validateUrl
37
+ }), load);
38
+ }
39
+ async function validateUrl(url) {
29
40
  if (!allowPrivateAddress) try {
30
41
  await validatePublicUrl(url);
31
42
  } catch (error) {
@@ -35,13 +46,6 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedi
35
46
  });
36
47
  throw error;
37
48
  }
38
- return getRemoteDocument(url, await doubleKnock(createActivityPubRequest(url, { userAgent }), identity, {
39
- maxRedirection,
40
- specDeterminer,
41
- log: curry(logRequest)(logger),
42
- tracerProvider,
43
- signal: options?.signal
44
- }), load);
45
49
  }
46
50
  return load;
47
51
  }
@@ -6,7 +6,7 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
6
  import { i as assertExists } from "../std__assert-CRDpx_HF.mjs";
7
7
  import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
8
8
  import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
9
- import { n as createFederationBuilder } from "../builder-Hr1c39Ha.mjs";
9
+ import { n as createFederationBuilder } from "../builder-BSmTnJcC.mjs";
10
10
  import { test } from "@fedify/fixture";
11
11
  import { Activity, Note, Person } from "@fedify/vocab";
12
12
  //#region src/federation/builder.test.ts
@@ -8,11 +8,11 @@ import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
8
8
  import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
9
9
  import { t as assert } from "../assert-DikXweDx.mjs";
10
10
  import { r as parseAcceptSignature } from "../accept-CPkZzmGN.mjs";
11
- import { s as signRequest } from "../http-BlHW6_Oi.mjs";
11
+ import { s as signRequest } from "../http-CIzMKh05.mjs";
12
12
  import { a as rsaPrivateKey3, c as rsaPublicKey3, s as rsaPublicKey2 } from "../keys-DGu1NFwu.mjs";
13
- import { a as compactJsonLd, p as signJsonLd } from "../ld-DDBxn1rq.mjs";
13
+ import { a as compactJsonLd, p as signJsonLd } from "../ld-aaLZ9vtX.mjs";
14
14
  import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
15
- import { c as handleActor, d as handleInbox, f as handleObject, h as respondWithObjectIfAcceptable, l as handleCollection, m as respondWithObject, o as createFederation, p as handleOutbox, u as handleCustomCollection } from "../middleware-BJM6vrlT.mjs";
15
+ import { c as handleActor, d as handleInbox, f as handleObject, h as respondWithObjectIfAcceptable, l as handleCollection, m as respondWithObject, o as createFederation, p as handleOutbox, u as handleCustomCollection } from "../middleware-De7RGKlL.mjs";
16
16
  import { t as ActivityListenerSet } from "../activity-listener-ell7W1s9.mjs";
17
17
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
18
18
  import { Activity, Create, Note, Person, Tombstone } from "@fedify/vocab";
@@ -4,9 +4,9 @@ globalThis.addEventListener = () => {};
4
4
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import "../std__assert-CRDpx_HF.mjs";
6
6
  import { n as ed25519PrivateKey, r as ed25519PublicKey, t as ed25519Multikey } from "../keys-DGu1NFwu.mjs";
7
- import { r as signObject } from "../proof-BGrdGhcb.mjs";
7
+ import { r as signObject } from "../proof-BaKRMbnC.mjs";
8
8
  import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
9
- import { o as createFederation } from "../middleware-BJM6vrlT.mjs";
9
+ import { o as createFederation } from "../middleware-De7RGKlL.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
@@ -11,14 +11,14 @@ 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 assertStrictEquals } from "../assert_strict_equals-Dmjbg-bA.mjs";
13
13
  import { t as assert } from "../assert-DikXweDx.mjs";
14
- import { l as verifyRequest, s as signRequest } from "../http-BlHW6_Oi.mjs";
14
+ import { l as verifyRequest, s as signRequest } from "../http-CIzMKh05.mjs";
15
15
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DGu1NFwu.mjs";
16
- import { t as getAuthenticatedDocumentLoader } from "../docloader-DixiMoIZ.mjs";
17
- import { a as compactJsonLd, h as verifyJsonLd, p as signJsonLd, s as detachSignature } from "../ld-DDBxn1rq.mjs";
18
- import { t as doesActorOwnKey } from "../owner-vuyMTd_f.mjs";
19
- import { i as verifyObject, r as signObject } from "../proof-BGrdGhcb.mjs";
16
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-Cu6YO4sl.mjs";
17
+ import { a as compactJsonLd, h as verifyJsonLd, p as signJsonLd, s as detachSignature } from "../ld-aaLZ9vtX.mjs";
18
+ import { t as doesActorOwnKey } from "../owner-Bxd_RFAX.mjs";
19
+ import { i as verifyObject, r as signObject } from "../proof-BaKRMbnC.mjs";
20
20
  import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
21
- import { i as KvSpecDeterminer, n as FederationImpl, o as createFederation, r as InboxContextImpl, t as ContextImpl } from "../middleware-BJM6vrlT.mjs";
21
+ import { i as KvSpecDeterminer, n as FederationImpl, o as createFederation, r as InboxContextImpl, t as ContextImpl } from "../middleware-De7RGKlL.mjs";
22
22
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
23
23
  import * as vocab from "@fedify/vocab";
24
24
  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-Bj5UFOaT.cjs");
5
+ const require_middleware = require("../middleware-CMx-gvcd.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-DOkcTiZ-.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-CWtQVZ8j.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-DikXweDx.mjs";
11
- import { l as verifyRequest } from "../http-BlHW6_Oi.mjs";
11
+ import { l as verifyRequest } from "../http-CIzMKh05.mjs";
12
12
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DGu1NFwu.mjs";
13
- import { t as doesActorOwnKey } from "../owner-vuyMTd_f.mjs";
14
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-BvazsIXC.mjs";
13
+ import { t as doesActorOwnKey } from "../owner-Bxd_RFAX.mjs";
14
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-B1UTCW8F.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-CRDpx_HF.mjs";
5
5
  import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
6
6
  import { t as assert } from "../assert-DikXweDx.mjs";
7
- import { t as hasMalformedKnownTemporalLiteral } from "../temporal-MdUFasAg.mjs";
7
+ import { t as hasMalformedKnownTemporalLiteral } from "../temporal-jgauoetb.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 { r as createRequestContext } from "../context-Dk_tacqz.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
6
  import "../std__assert-CRDpx_HF.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
8
- import { o as createFederation, s as handleWebFinger } from "../middleware-BJM6vrlT.mjs";
8
+ import { o as createFederation, s as handleWebFinger } from "../middleware-De7RGKlL.mjs";
9
9
  import { test } from "@fedify/fixture";
10
10
  import { Image, Link, Person, Tombstone } from "@fedify/vocab";
11
11
  //#region src/federation/webfinger.test.ts
@@ -1,9 +1,9 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-B_vGx2Ji.mjs";
4
+ import { n as version, t as name } from "./deno-dpXHD1Cg.mjs";
5
5
  import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-CPkZzmGN.mjs";
6
- import { o as validateCryptoKey, r as fetchKeyDetailed } from "./key-6U1u5H_H.mjs";
6
+ import { o as validateCryptoKey, r as fetchKeyDetailed } from "./key-C6KGyqT_.mjs";
7
7
  import { CryptographicKey } from "@fedify/vocab";
8
8
  import { SpanStatusCode, trace } from "@opentelemetry/api";
9
9
  import { FetchError } from "@fedify/vocab-runtime";
@@ -824,10 +824,12 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
824
824
  * @param request The original request.
825
825
  * @param location The redirect location.
826
826
  * @param body The request body as ArrayBuffer or null.
827
+ * @param validateRedirect The function to validate the redirect URL.
827
828
  * @returns A new Request object for the redirect.
828
829
  */
829
- function createRedirectRequest(request, location, body) {
830
+ async function createRedirectRequest(request, location, body, validateRedirect) {
830
831
  const url = new URL(location, request.url);
832
+ await validateRedirect?.(url.href);
831
833
  return new Request(url, {
832
834
  method: request.method,
833
835
  headers: request.headers,
@@ -925,7 +927,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
925
927
  let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
926
928
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
927
929
  if (redirected >= maximumRedirection) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
928
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
930
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
929
931
  if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
930
932
  return doubleKnockInternal(redirectRequest, identity, {
931
933
  ...options,
@@ -973,7 +975,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
973
975
  redirect: "manual",
974
976
  signal
975
977
  });
976
- if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return doubleKnock(createRedirectRequest(request, response.headers.get("Location"), body), identity, {
978
+ if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return doubleKnock(await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect), identity, {
977
979
  ...options,
978
980
  body
979
981
  });
@@ -1000,7 +1002,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1000
1002
  response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1001
1003
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1002
1004
  if (redirected >= maximumRedirection) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
1003
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
1005
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
1004
1006
  if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1005
1007
  return doubleKnockInternal(redirectRequest, identity, {
1006
1008
  ...options,
@@ -10,7 +10,7 @@ import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } fro
10
10
  import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
11
11
  //#region deno.json
12
12
  var name = "@fedify/fedify";
13
- var version = "2.2.8";
13
+ var version = "2.2.10";
14
14
  //#endregion
15
15
  //#region src/sig/accept.ts
16
16
  /**
@@ -387,7 +387,7 @@ async function resolveFetchedKey(document, cacheKey, keyId, cls, { documentLoade
387
387
  }
388
388
  }
389
389
  let key = null;
390
- if (object instanceof cls) key = object;
390
+ if (object instanceof cls && (object.id == null || object.id.href === keyId)) key = object;
391
391
  else if (isActor(object)) {
392
392
  const keys = cls === CryptographicKey ? object.getPublicKeys({
393
393
  documentLoader,
@@ -1316,10 +1316,12 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1316
1316
  * @param request The original request.
1317
1317
  * @param location The redirect location.
1318
1318
  * @param body The request body as ArrayBuffer or null.
1319
+ * @param validateRedirect The function to validate the redirect URL.
1319
1320
  * @returns A new Request object for the redirect.
1320
1321
  */
1321
- function createRedirectRequest(request, location, body) {
1322
+ async function createRedirectRequest(request, location, body, validateRedirect) {
1322
1323
  const url = new URL(location, request.url);
1324
+ await validateRedirect?.(url.href);
1323
1325
  return new Request(url, {
1324
1326
  method: request.method,
1325
1327
  headers: request.headers,
@@ -1417,7 +1419,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1417
1419
  let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1418
1420
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1419
1421
  if (redirected >= maximumRedirection) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
1420
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
1422
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
1421
1423
  if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1422
1424
  return doubleKnockInternal(redirectRequest, identity, {
1423
1425
  ...options,
@@ -1465,7 +1467,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1465
1467
  redirect: "manual",
1466
1468
  signal
1467
1469
  });
1468
- if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return doubleKnock(createRedirectRequest(request, response.headers.get("Location"), body), identity, {
1470
+ if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return doubleKnock(await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect), identity, {
1469
1471
  ...options,
1470
1472
  body
1471
1473
  });
@@ -1492,7 +1494,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1492
1494
  response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1493
1495
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1494
1496
  if (redirected >= maximumRedirection) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
1495
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
1497
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
1496
1498
  if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1497
1499
  return doubleKnockInternal(redirectRequest, identity, {
1498
1500
  ...options,
@@ -11,7 +11,7 @@ let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conve
11
11
  let byte_encodings_base64 = require("byte-encodings/base64");
12
12
  //#region deno.json
13
13
  var name = "@fedify/fedify";
14
- var version = "2.2.8";
14
+ var version = "2.2.10";
15
15
  //#endregion
16
16
  //#region src/sig/accept.ts
17
17
  /**
@@ -388,7 +388,7 @@ async function resolveFetchedKey(document, cacheKey, keyId, cls, { documentLoade
388
388
  }
389
389
  }
390
390
  let key = null;
391
- if (object instanceof cls) key = object;
391
+ if (object instanceof cls && (object.id == null || object.id.href === keyId)) key = object;
392
392
  else if ((0, _fedify_vocab.isActor)(object)) {
393
393
  const keys = cls === _fedify_vocab.CryptographicKey ? object.getPublicKeys({
394
394
  documentLoader,
@@ -1317,10 +1317,12 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
1317
1317
  * @param request The original request.
1318
1318
  * @param location The redirect location.
1319
1319
  * @param body The request body as ArrayBuffer or null.
1320
+ * @param validateRedirect The function to validate the redirect URL.
1320
1321
  * @returns A new Request object for the redirect.
1321
1322
  */
1322
- function createRedirectRequest(request, location, body) {
1323
+ async function createRedirectRequest(request, location, body, validateRedirect) {
1323
1324
  const url = new URL(location, request.url);
1325
+ await validateRedirect?.(url.href);
1324
1326
  return new Request(url, {
1325
1327
  method: request.method,
1326
1328
  headers: request.headers,
@@ -1418,7 +1420,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1418
1420
  let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1419
1421
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1420
1422
  if (redirected >= maximumRedirection) throw new _fedify_vocab_runtime.FetchError(request.url, `Too many redirections (${redirected + 1})`);
1421
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
1423
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
1422
1424
  if (visited.has(redirectRequest.url)) throw new _fedify_vocab_runtime.FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1423
1425
  return doubleKnockInternal(redirectRequest, identity, {
1424
1426
  ...options,
@@ -1466,7 +1468,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1466
1468
  redirect: "manual",
1467
1469
  signal
1468
1470
  });
1469
- if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return doubleKnock(createRedirectRequest(request, response.headers.get("Location"), body), identity, {
1471
+ if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return doubleKnock(await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect), identity, {
1470
1472
  ...options,
1471
1473
  body
1472
1474
  });
@@ -1493,7 +1495,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1493
1495
  response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1494
1496
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1495
1497
  if (redirected >= maximumRedirection) throw new _fedify_vocab_runtime.FetchError(request.url, `Too many redirections (${redirected + 1})`);
1496
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
1498
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
1497
1499
  if (visited.has(redirectRequest.url)) throw new _fedify_vocab_runtime.FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1498
1500
  return doubleKnockInternal(redirectRequest, identity, {
1499
1501
  ...options,
@@ -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-B_vGx2Ji.mjs";
4
+ import { n as version, t as name } from "./deno-dpXHD1Cg.mjs";
5
5
  import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
6
6
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
7
7
  import { FetchError, getDocumentLoader } from "@fedify/vocab-runtime";
@@ -242,7 +242,7 @@ async function resolveFetchedKey(document, cacheKey, keyId, cls, { documentLoade
242
242
  }
243
243
  }
244
244
  let key = null;
245
- if (object instanceof cls) key = object;
245
+ if (object instanceof cls && (object.id == null || object.id.href === keyId)) key = object;
246
246
  else if (isActor(object)) {
247
247
  const keys = cls === CryptographicKey ? object.getPublicKeys({
248
248
  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-DLRpF855.cjs");
4
+ const require_http = require("./http-pf3AXy99.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,17 @@ const logger$1 = (0, _logtape_logtape.getLogger)([
25
25
  function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedirection, 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
+ maxRedirection,
31
+ specDeterminer,
32
+ log: (0, es_toolkit.curry)(_fedify_vocab_runtime.logRequest)(logger$1),
33
+ tracerProvider,
34
+ signal: options?.signal,
35
+ validateRedirect: validateUrl
36
+ }), load);
37
+ }
38
+ async function validateUrl(url) {
28
39
  if (!allowPrivateAddress) try {
29
40
  await (0, _fedify_vocab_runtime.validatePublicUrl)(url);
30
41
  } catch (error) {
@@ -34,13 +45,6 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedi
34
45
  });
35
46
  throw error;
36
47
  }
37
- return (0, _fedify_vocab_runtime.getRemoteDocument)(url, await require_http.doubleKnock((0, _fedify_vocab_runtime.createActivityPubRequest)(url, { userAgent }), identity, {
38
- maxRedirection,
39
- specDeterminer,
40
- log: (0, es_toolkit.curry)(_fedify_vocab_runtime.logRequest)(logger$1),
41
- tracerProvider,
42
- signal: options?.signal
43
- }), load);
44
48
  }
45
49
  return load;
46
50
  }
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { d as validateCryptoKey, t as doubleKnock } from "./http-C-FdpmAl.js";
3
+ import { d as validateCryptoKey, t as doubleKnock } from "./http-l1HqLnRo.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,17 @@ const logger$1 = getLogger([
24
24
  function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedirection, 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
+ maxRedirection,
30
+ specDeterminer,
31
+ log: curry(logRequest)(logger$1),
32
+ tracerProvider,
33
+ signal: options?.signal,
34
+ validateRedirect: validateUrl
35
+ }), load);
36
+ }
37
+ async function validateUrl(url) {
27
38
  if (!allowPrivateAddress) try {
28
39
  await validatePublicUrl(url);
29
40
  } catch (error) {
@@ -33,13 +44,6 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedi
33
44
  });
34
45
  throw error;
35
46
  }
36
- return getRemoteDocument(url, await doubleKnock(createActivityPubRequest(url, { userAgent }), identity, {
37
- maxRedirection,
38
- specDeterminer,
39
- log: curry(logRequest)(logger$1),
40
- tracerProvider,
41
- signal: options?.signal
42
- }), load);
43
47
  }
44
48
  return load;
45
49
  }
@@ -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-B_vGx2Ji.mjs";
5
- import { n as fetchKey, o as validateCryptoKey } from "./key-6U1u5H_H.mjs";
4
+ import { n as version, t as name } from "./deno-dpXHD1Cg.mjs";
5
+ import { n as fetchKey, o as validateCryptoKey } from "./key-C6KGyqT_.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-BJM6vrlT.mjs";
4
+ import { n as FederationImpl } from "./middleware-De7RGKlL.mjs";
5
5
  export { FederationImpl };
@@ -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-DLRpF855.cjs");
6
- const require_proof = require("./proof-BNGY2IU6.cjs");
5
+ const require_http = require("./http-pf3AXy99.cjs");
6
+ const require_proof = require("./proof-BOHbpbMG.cjs");
7
7
  const require_types = require("./types-m8u9L86X.cjs");
8
- const require_kv_cache = require("./kv-cache-DKprbYof.cjs");
8
+ const require_kv_cache = require("./kv-cache-B_HA4cvx.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");
@@ -212,7 +212,7 @@ var FederationBuilderImpl = class {
212
212
  this.collectionTypeIds = {};
213
213
  }
214
214
  async build(options) {
215
- const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-DNJYfRV4.cjs"));
215
+ const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-VpIBr58-.cjs"));
216
216
  const f = new FederationImpl(options);
217
217
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
218
218
  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 { _ as version, a as verifyRequestDetailed, d as validateCryptoKey, f as formatAcceptSignature, g as name, i as verifyRequest, n as parseRfc9421SignatureInput, o as exportJwk, t as doubleKnock, u as importJwk } from "./http-C-FdpmAl.js";
6
- import { _ as hasSignatureLike, b as signJsonLd, c as getKeyOwner, f as compactJsonLd, g as hasSignature, h as getNormalizationContextLoader, i as verifyObject, l as InvalidContextReferenceError, m as detachSignature, n as hasProofLike, o as normalizeOutgoingActivityJsonLd, r as signObject, s as doesActorOwnKey, u as assertSafeJsonLd, v as isClearlyMalformedContextReference, w as wrapContextLoaderForJsonLd, x as verifyCompactJsonLd, y as isInvalidUrlTypeError } from "./proof-DA_wkPds.js";
5
+ import { _ as version, a as verifyRequestDetailed, d as validateCryptoKey, f as formatAcceptSignature, g as name, i as verifyRequest, n as parseRfc9421SignatureInput, o as exportJwk, t as doubleKnock, u as importJwk } from "./http-l1HqLnRo.js";
6
+ import { _ as hasSignatureLike, b as signJsonLd, c as getKeyOwner, f as compactJsonLd, g as hasSignature, h as getNormalizationContextLoader, i as verifyObject, l as InvalidContextReferenceError, m as detachSignature, n as hasProofLike, o as normalizeOutgoingActivityJsonLd, r as signObject, s as doesActorOwnKey, u as assertSafeJsonLd, v as isClearlyMalformedContextReference, w as wrapContextLoaderForJsonLd, x as verifyCompactJsonLd, y as isInvalidUrlTypeError } from "./proof-CIoNWttk.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-BjlL4Zk0.js";
8
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-m9KwvJeU.js";
9
9
  import { getLogger, withContext } from "@logtape/logtape";
10
10
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, Tombstone, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
11
11
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
@@ -2,25 +2,25 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { n as RouterError } from "./router-CrMLXoOr.mjs";
5
- import { n as version, t as name } from "./deno-B_vGx2Ji.mjs";
5
+ import { n as version, t as name } from "./deno-dpXHD1Cg.mjs";
6
6
  import { t as formatAcceptSignature } from "./accept-CPkZzmGN.mjs";
7
- import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-6U1u5H_H.mjs";
8
- import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-BlHW6_Oi.mjs";
9
- import { t as getAuthenticatedDocumentLoader } from "./docloader-DixiMoIZ.mjs";
7
+ import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-C6KGyqT_.mjs";
8
+ import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-CIzMKh05.mjs";
9
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-Cu6YO4sl.mjs";
10
10
  import { n as kvCache } from "./kv-cache-DYsF2MhP.mjs";
11
- import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-DDBxn1rq.mjs";
12
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-vuyMTd_f.mjs";
11
+ import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-aaLZ9vtX.mjs";
12
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-Bxd_RFAX.mjs";
13
13
  import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-CNmZLixq.mjs";
14
- import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-BGrdGhcb.mjs";
14
+ import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-BaKRMbnC.mjs";
15
15
  import { t as getNodeInfo } from "./client-dx126nMS.mjs";
16
16
  import { t as nodeInfoToJson } from "./types-J53Kw7so.mjs";
17
- import { t as FederationBuilderImpl } from "./builder-Hr1c39Ha.mjs";
17
+ import { t as FederationBuilderImpl } from "./builder-BSmTnJcC.mjs";
18
18
  import { t as buildCollectionSynchronizationHeader } from "./collection-D-HqUuA2.mjs";
19
19
  import { t as KvKeyCache } from "./keycache-EGATflN-.mjs";
20
20
  import { t as acceptsJsonLd } from "./negotiation-SQvQgUqe.mjs";
21
- import { t as hasMalformedKnownTemporalLiteral } from "./temporal-MdUFasAg.mjs";
21
+ import { t as hasMalformedKnownTemporalLiteral } from "./temporal-jgauoetb.mjs";
22
22
  import { t as createExponentialBackoffPolicy } from "./retry-v_sGLH1d.mjs";
23
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-BvazsIXC.mjs";
23
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-B1UTCW8F.mjs";
24
24
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, Tombstone, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
25
25
  import { lookupWebFinger } from "@fedify/webfinger";
26
26
  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-Bj5UFOaT.cjs");
3
+ const require_middleware = require("./middleware-CMx-gvcd.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-DLRpF855.cjs");
8
- const require_middleware = require("./middleware-Bj5UFOaT.cjs");
9
- const require_proof = require("./proof-BNGY2IU6.cjs");
7
+ const require_http = require("./http-pf3AXy99.cjs");
8
+ const require_middleware = require("./middleware-CMx-gvcd.cjs");
9
+ const require_proof = require("./proof-BOHbpbMG.cjs");
10
10
  const require_types = require("./types-m8u9L86X.cjs");
11
- const require_kv_cache = require("./kv-cache-DKprbYof.cjs");
11
+ const require_kv_cache = require("./kv-cache-B_HA4cvx.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 verifyRequestDetailed, c as fetchKeyDetailed, f as formatAcceptSignature, h as validateAcceptSignature, i as verifyRequest, l as generateCryptoKeyPair, m as parseAcceptSignature, o as exportJwk, p as fulfillAcceptSignature, r as signRequest, s as fetchKey, u as importJwk } from "./http-C-FdpmAl.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-DOkcTiZ-.js";
8
- import { C as verifySignature, S as verifyJsonLd, _ as hasSignatureLike, a as verifyProof, b as signJsonLd, c as getKeyOwner, d as attachSignature, i as verifyObject, m as detachSignature, n as hasProofLike, p as createSignature, r as signObject, s as doesActorOwnKey, t as createProof } from "./proof-DA_wkPds.js";
6
+ import { a as verifyRequestDetailed, c as fetchKeyDetailed, f as formatAcceptSignature, h as validateAcceptSignature, i as verifyRequest, l as generateCryptoKeyPair, m as parseAcceptSignature, o as exportJwk, p as fulfillAcceptSignature, r as signRequest, s as fetchKey, u as importJwk } from "./http-l1HqLnRo.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-CWtQVZ8j.js";
8
+ import { C as verifySignature, S as verifyJsonLd, _ as hasSignatureLike, a as verifyProof, b as signJsonLd, c as getKeyOwner, d as attachSignature, i as verifyObject, m as detachSignature, n as hasProofLike, p as createSignature, r as signObject, s as doesActorOwnKey, t as createProof } from "./proof-CIoNWttk.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-BjlL4Zk0.js";
10
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-m9KwvJeU.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 { r as createRequestContext } from "../context-Dk_tacqz.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
6
6
  import "../std__assert-CRDpx_HF.mjs";
7
7
  import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
8
- import { _ as handleNodeInfoJrd, g as handleNodeInfo, o as createFederation } from "../middleware-BJM6vrlT.mjs";
8
+ import { _ as handleNodeInfoJrd, g as handleNodeInfo, o as createFederation } from "../middleware-De7RGKlL.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-B_vGx2Ji.mjs";
5
- import "./key-6U1u5H_H.mjs";
4
+ import { n as version, t as name } from "./deno-dpXHD1Cg.mjs";
5
+ import "./key-C6KGyqT_.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,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-DLRpF855.cjs");
4
+ const require_http = require("./http-pf3AXy99.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,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-B_vGx2Ji.mjs";
5
- import { n as fetchKey, o as validateCryptoKey } from "./key-6U1u5H_H.mjs";
4
+ import { n as version, t as name } from "./deno-dpXHD1Cg.mjs";
5
+ import { n as fetchKey, o as validateCryptoKey } from "./key-C6KGyqT_.mjs";
6
6
  import { n as preloadedOnlyDocumentLoader } from "./public-audience-DYFHzm_c.mjs";
7
7
  import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-CNmZLixq.mjs";
8
8
  import { Activity, DataIntegrityProof, Multikey, getTypeId } from "@fedify/vocab";
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { _ as version, d as validateCryptoKey, g as name, s as fetchKey } from "./http-C-FdpmAl.js";
3
+ import { _ as version, d as validateCryptoKey, g as name, s as fetchKey } from "./http-l1HqLnRo.js";
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import { Activity, CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1, PUBLIC_COLLECTION, 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-B_vGx2Ji.mjs";
5
- import { n as doubleKnock } from "./http-BlHW6_Oi.mjs";
4
+ import { n as version, t as name } from "./deno-dpXHD1Cg.mjs";
5
+ import { n as doubleKnock } from "./http-CIzMKh05.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 { i as assertExists, t as assertStringIncludes } from "../std__assert-CRD
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-DikXweDx.mjs";
10
- import { t as exportJwk } from "../key-6U1u5H_H.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, u as verifyRequestDetailed } from "../http-BlHW6_Oi.mjs";
10
+ import { t as exportJwk } from "../key-C6KGyqT_.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, u as verifyRequestDetailed } from "../http-CIzMKh05.mjs";
12
12
  import { i as rsaPrivateKey2, l as rsaPublicKey5, o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-DGu1NFwu.mjs";
13
13
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
14
14
  import { FetchError, exportSpki } from "@fedify/vocab-runtime";
@@ -794,6 +794,7 @@ test("doubleKnock() function with redirect handling", async () => {
794
794
  esm_default.spyGlobal();
795
795
  const requestedUrls = [];
796
796
  const responseCodes = [];
797
+ const validatedRedirects = [];
797
798
  esm_default.post("https://example.com/redirect-endpoint", (cl) => {
798
799
  requestedUrls.push(cl.url);
799
800
  responseCodes.push(302);
@@ -811,11 +812,41 @@ test("doubleKnock() function with redirect handling", async () => {
811
812
  }), {
812
813
  keyId: rsaPublicKey2.id,
813
814
  privateKey: rsaPrivateKey2
814
- })).status, 202, "Final response status should be 202 Accepted");
815
+ }, { validateRedirect(url) {
816
+ validatedRedirects.push(url);
817
+ } })).status, 202, "Final response status should be 202 Accepted");
815
818
  assertEquals(requestedUrls.length, 2, "Two URLs should have been requested");
816
819
  assertEquals(requestedUrls[0], "https://example.com/redirect-endpoint", "First request should be to redirect-endpoint");
817
820
  assertEquals(requestedUrls[1], "https://example.com/final-endpoint", "Second request should be to final-endpoint");
818
821
  assertEquals(responseCodes, [302, 202], "Response status codes should match expected sequence");
822
+ assertEquals(validatedRedirects, ["https://example.com/final-endpoint"]);
823
+ esm_default.hardReset();
824
+ });
825
+ test("doubleKnock() validates redirects after signature fallback", async () => {
826
+ esm_default.spyGlobal();
827
+ let requestCount = 0;
828
+ let privateRequestCount = 0;
829
+ esm_default.post("https://example.com/redirect-after-fallback", (cl) => {
830
+ requestCount++;
831
+ if (cl.request.headers.has("Signature-Input")) return new Response("Unauthorized", { status: 401 });
832
+ return Response.redirect("http://localhost/private", 302);
833
+ });
834
+ esm_default.post("http://localhost/private", () => {
835
+ privateRequestCount++;
836
+ return new Response("", { status: 202 });
837
+ });
838
+ const request = new Request("https://example.com/redirect-after-fallback", {
839
+ method: "POST",
840
+ body: "Test message"
841
+ });
842
+ await assertRejects(() => doubleKnock(request, {
843
+ keyId: rsaPublicKey2.id,
844
+ privateKey: rsaPrivateKey2
845
+ }, { validateRedirect(url) {
846
+ throw new Error(`Disallowed redirect: ${url}`);
847
+ } }), Error, "Disallowed redirect: http://localhost/private");
848
+ assertEquals(requestCount, 2);
849
+ assertEquals(privateRequestCount, 0);
819
850
  esm_default.hardReset();
820
851
  });
821
852
  test("doubleKnock() function with both specs rejected", async () => {
@@ -1608,6 +1639,37 @@ test("doubleKnock(): Accept-Signature challenge retry succeeds", async () => {
1608
1639
  assertEquals(requestCount, 2);
1609
1640
  esm_default.hardReset();
1610
1641
  });
1642
+ test("doubleKnock(): validates redirects after Accept-Signature challenge retry", async () => {
1643
+ esm_default.spyGlobal();
1644
+ let requestCount = 0;
1645
+ let privateRequestCount = 0;
1646
+ esm_default.post("https://example.com/inbox-challenge-redirect", () => {
1647
+ requestCount++;
1648
+ if (requestCount === 1) return new Response("Not Authorized", {
1649
+ status: 401,
1650
+ headers: { "Accept-Signature": "sig1=(\"@method\" \"@target-uri\" \"@authority\" \"content-digest\");created;nonce=\"challenge-nonce-redirect\"" }
1651
+ });
1652
+ return Response.redirect("http://localhost/private", 302);
1653
+ });
1654
+ esm_default.post("http://localhost/private", () => {
1655
+ privateRequestCount++;
1656
+ return new Response("", { status: 202 });
1657
+ });
1658
+ const request = new Request("https://example.com/inbox-challenge-redirect", {
1659
+ method: "POST",
1660
+ body: "Test message",
1661
+ headers: { "Content-Type": "text/plain" }
1662
+ });
1663
+ await assertRejects(() => doubleKnock(request, {
1664
+ keyId: rsaPublicKey2.id,
1665
+ privateKey: rsaPrivateKey2
1666
+ }, { validateRedirect(url) {
1667
+ throw new Error(`Disallowed redirect: ${url}`);
1668
+ } }), Error, "Disallowed redirect: http://localhost/private");
1669
+ assertEquals(requestCount, 2);
1670
+ assertEquals(privateRequestCount, 0);
1671
+ esm_default.hardReset();
1672
+ });
1611
1673
  test("doubleKnock(): unfulfillable Accept-Signature falls to legacy fallback", async () => {
1612
1674
  esm_default.spyGlobal();
1613
1675
  let requestCount = 0;
@@ -5,7 +5,7 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
5
5
  import "../std__assert-CRDpx_HF.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 importJwk, i as generateCryptoKeyPair, n as fetchKey, o as validateCryptoKey, r as fetchKeyDetailed, t as exportJwk } from "../key-6U1u5H_H.mjs";
8
+ import { a as importJwk, i as generateCryptoKeyPair, n as fetchKey, o as validateCryptoKey, r as fetchKeyDetailed, t as exportJwk } from "../key-C6KGyqT_.mjs";
9
9
  import { c as rsaPublicKey3, i as rsaPrivateKey2, o as rsaPublicKey1, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DGu1NFwu.mjs";
10
10
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
11
11
  import { CryptographicKey, Multikey } from "@fedify/vocab";
@@ -303,6 +303,51 @@ test("fetchKeyDetailed() returns detailed fetch errors", async () => {
303
303
  if (detailedError == null || !("error" in detailedError)) throw new Error("Expected non-HTTP fetch error details.");
304
304
  assertEquals(detailedError.error, failure);
305
305
  });
306
+ test("fetchKey() rejects standalone keys with a mismatched id", async () => {
307
+ for (const { keyId, standaloneKey, fetch } of [{
308
+ keyId: "https://example.com/key",
309
+ standaloneKey: rsaPublicKey1,
310
+ fetch: (keyId, options) => fetchKey(keyId, CryptographicKey, options)
311
+ }, {
312
+ keyId: "https://example.com/multikey",
313
+ standaloneKey: ed25519Multikey,
314
+ fetch: (keyId, options) => fetchKey(keyId, Multikey, options)
315
+ }]) {
316
+ const cache = {};
317
+ const options = {
318
+ async documentLoader(resource) {
319
+ if (resource === keyId) return {
320
+ contextUrl: null,
321
+ documentUrl: resource,
322
+ document: {
323
+ ...await standaloneKey.toJsonLd({ contextLoader: mockDocumentLoader }),
324
+ id: "https://example.com/different-key"
325
+ }
326
+ };
327
+ return await mockDocumentLoader(resource);
328
+ },
329
+ contextLoader: mockDocumentLoader,
330
+ keyCache: {
331
+ get(keyId) {
332
+ return Promise.resolve(cache[keyId.href]);
333
+ },
334
+ set(keyId, key) {
335
+ cache[keyId.href] = key;
336
+ return Promise.resolve();
337
+ }
338
+ }
339
+ };
340
+ assertEquals(await fetch(keyId, options), {
341
+ key: null,
342
+ cached: false
343
+ });
344
+ assertEquals(cache, { [keyId]: null });
345
+ assertEquals(await fetch(keyId, options), {
346
+ key: null,
347
+ cached: true
348
+ });
349
+ }
350
+ });
306
351
  test("fetchKey() returns null for a malformed actor publicKey", async () => {
307
352
  const actorId = "https://example.com/malformed-public-key";
308
353
  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-DikXweDx.mjs";
8
- import { i as generateCryptoKeyPair } from "../key-6U1u5H_H.mjs";
8
+ import { i as generateCryptoKeyPair } from "../key-C6KGyqT_.mjs";
9
9
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DGu1NFwu.mjs";
10
- import { a as compactJsonLd, f as isInvalidUrlTypeError, g as verifySignature, h as verifyJsonLd, i as attachSignature, n as UnsafeJsonLdError, o as createSignature, p as signJsonLd, s as detachSignature, u as hasSignatureLike } from "../ld-DDBxn1rq.mjs";
10
+ import { a as compactJsonLd, f as isInvalidUrlTypeError, g as verifySignature, h as verifyJsonLd, i as attachSignature, n as UnsafeJsonLdError, o as createSignature, p as signJsonLd, s as detachSignature, u as hasSignatureLike } from "../ld-aaLZ9vtX.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-DLRpF855.cjs");
5
- const require_proof = require("../proof-BNGY2IU6.cjs");
4
+ const require_http = require("../http-pf3AXy99.cjs");
5
+ const require_proof = require("../proof-BOHbpbMG.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 verifyRequestDetailed, c as fetchKeyDetailed, f as formatAcceptSignature, h as validateAcceptSignature, i as verifyRequest, l as generateCryptoKeyPair, m as parseAcceptSignature, o as exportJwk, p as fulfillAcceptSignature, r as signRequest, s as fetchKey, u as importJwk } from "../http-C-FdpmAl.js";
4
- import { C as verifySignature, S as verifyJsonLd, _ as hasSignatureLike, a as verifyProof, b as signJsonLd, c as getKeyOwner, d as attachSignature, i as verifyObject, m as detachSignature, n as hasProofLike, p as createSignature, r as signObject, s as doesActorOwnKey, t as createProof } from "../proof-DA_wkPds.js";
3
+ import { a as verifyRequestDetailed, c as fetchKeyDetailed, f as formatAcceptSignature, h as validateAcceptSignature, i as verifyRequest, l as generateCryptoKeyPair, m as parseAcceptSignature, o as exportJwk, p as fulfillAcceptSignature, r as signRequest, s as fetchKey, u as importJwk } from "../http-l1HqLnRo.js";
4
+ import { C as verifySignature, S as verifyJsonLd, _ as hasSignatureLike, a as verifyProof, b as signJsonLd, c as getKeyOwner, d as attachSignature, i as verifyObject, m as detachSignature, n as hasProofLike, p as createSignature, r as signObject, s as doesActorOwnKey, t as createProof } from "../proof-CIoNWttk.js";
5
5
  export { attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, fetchKeyDetailed, formatAcceptSignature, fulfillAcceptSignature, generateCryptoKeyPair, getKeyOwner, hasProofLike, hasSignatureLike, importJwk, parseAcceptSignature, signJsonLd, signObject, signRequest, validateAcceptSignature, verifyJsonLd, verifyObject, verifyProof, verifyRequest, verifyRequestDetailed, verifySignature };
@@ -6,7 +6,7 @@ import "../std__assert-CRDpx_HF.mjs";
6
6
  import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
7
7
  import { t as assert } from "../assert-DikXweDx.mjs";
8
8
  import { o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-DGu1NFwu.mjs";
9
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-vuyMTd_f.mjs";
9
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-Bxd_RFAX.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
@@ -8,7 +8,7 @@ import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
8
8
  import { t as assert } from "../assert-DikXweDx.mjs";
9
9
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DGu1NFwu.mjs";
10
10
  import { r as normalizeOutgoingActivityJsonLd } from "../outgoing-jsonld-CNmZLixq.mjs";
11
- import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-BGrdGhcb.mjs";
11
+ import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-BaKRMbnC.mjs";
12
12
  import { mockDocumentLoader, test } from "@fedify/fixture";
13
13
  import { Create, DataIntegrityProof, Document, Multikey, Note, PUBLIC_COLLECTION, Place } from "@fedify/vocab";
14
14
  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-DDBxn1rq.mjs";
4
+ import { c as getNormalizationContextLoader } from "./ld-aaLZ9vtX.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-CRDpx_HF.mjs";
7
7
  import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
8
- import { l as verifyRequest } from "../http-BlHW6_Oi.mjs";
8
+ import { l as verifyRequest } from "../http-CIzMKh05.mjs";
9
9
  import { i as rsaPrivateKey2 } from "../keys-DGu1NFwu.mjs";
10
- import { t as getAuthenticatedDocumentLoader } from "../docloader-DixiMoIZ.mjs";
10
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-Cu6YO4sl.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
@@ -63,6 +63,39 @@ test("getAuthenticatedDocumentLoader()", async (t) => {
63
63
  esm_default.hardReset();
64
64
  });
65
65
  });
66
+ test("getAuthenticatedDocumentLoader() validates redirects", async (t) => {
67
+ esm_default.spyGlobal();
68
+ let privateRequestCount = 0;
69
+ esm_default.get("https://example.com/redirect-to-private", () => Response.redirect("http://localhost/private", 302));
70
+ esm_default.get("http://localhost/private", () => {
71
+ privateRequestCount++;
72
+ return Response.json({ private: true });
73
+ });
74
+ await t.step("deny public-to-private redirects", async () => {
75
+ const loader = getAuthenticatedDocumentLoader({
76
+ keyId: new URL("https://example.com/key2"),
77
+ privateKey: rsaPrivateKey2
78
+ });
79
+ await assertRejects(() => loader("https://example.com/redirect-to-private"), UrlError);
80
+ assertEquals(privateRequestCount, 0);
81
+ });
82
+ esm_default.get("https://example.com/redirect-to-public", () => Response.redirect("https://www.example.com/document", 302));
83
+ esm_default.get("https://www.example.com/document", () => Response.json({ public: true }));
84
+ await t.step("allow public-to-public redirects", async () => {
85
+ assertEquals((await getAuthenticatedDocumentLoader({
86
+ keyId: new URL("https://example.com/key2"),
87
+ privateKey: rsaPrivateKey2
88
+ })("https://example.com/redirect-to-public")).document, { public: true });
89
+ });
90
+ await t.step("allow private redirects when explicitly enabled", async () => {
91
+ assertEquals((await getAuthenticatedDocumentLoader({
92
+ keyId: new URL("https://example.com/key2"),
93
+ privateKey: rsaPrivateKey2
94
+ }, { allowPrivateAddress: true })("https://example.com/redirect-to-private")).document, { private: true });
95
+ assertEquals(privateRequestCount, 1);
96
+ });
97
+ esm_default.hardReset();
98
+ });
66
99
  test("getAuthenticatedDocumentLoader() cancellation", {
67
100
  sanitizeResources: false,
68
101
  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-DKprbYof.cjs");
4
+ const require_kv_cache = require("../kv-cache-B_HA4cvx.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-BjlL4Zk0.js";
3
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-m9KwvJeU.js";
4
4
  export { getAuthenticatedDocumentLoader, kvCache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/fedify",
3
- "version": "2.2.8",
3
+ "version": "2.2.10",
4
4
  "description": "An ActivityPub server framework",
5
5
  "keywords": [
6
6
  "ActivityPub",
@@ -153,9 +153,9 @@
153
153
  "uri-template-router": "^1.0.0",
154
154
  "url-template": "^3.1.1",
155
155
  "urlpattern-polyfill": "^10.1.0",
156
- "@fedify/webfinger": "2.2.8",
157
- "@fedify/vocab": "2.2.8",
158
- "@fedify/vocab-runtime": "2.2.8"
156
+ "@fedify/vocab-runtime": "2.2.10",
157
+ "@fedify/vocab": "2.2.10",
158
+ "@fedify/webfinger": "2.2.10"
159
159
  },
160
160
  "devDependencies": {
161
161
  "@std/assert": "npm:@jsr/std__assert@^0.226.0",
@@ -167,8 +167,8 @@
167
167
  "tsx": "^4.19.4",
168
168
  "typescript": "^6.0.0",
169
169
  "wrangler": "^4.17.0",
170
- "@fedify/fixture": "2.0.0",
171
- "@fedify/vocab-tools": "^2.2.8"
170
+ "@fedify/vocab-tools": "^2.2.10",
171
+ "@fedify/fixture": "2.0.0"
172
172
  },
173
173
  "scripts": {
174
174
  "build:self": "tsdown",