@fedify/fedify 2.1.20 → 2.1.21

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-BGAOx6I4.mjs → builder-BOR3Daoc.mjs} +3 -3
  2. package/dist/compat/transformers.test.mjs +1 -1
  3. package/dist/{deno-BBtJI5jH.mjs → deno-BKr6e8uY.mjs} +1 -1
  4. package/dist/{docloader-DfN4-Koe.mjs → docloader-iEu432Fw.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-6RJdarOh.mjs → http-C8E0OP9c.mjs} +8 -6
  16. package/dist/{http-BwW0QaNu.js → http-CLqgn9Jh.js} +8 -6
  17. package/dist/{http-DYhyI8oM.cjs → http-DjQHLsYQ.cjs} +8 -6
  18. package/dist/{inbox-BFkyrNC8.mjs → inbox-BmfcF5Br.mjs} +1 -1
  19. package/dist/{key-Dlv6nEER.mjs → key-CaELP2ph.mjs} +2 -2
  20. package/dist/{kv-cache-BjBQ1nMz.js → kv-cache-DE1Vf7DK.js} +11 -7
  21. package/dist/{kv-cache-B3wIm0jW.cjs → kv-cache-Odl-e0KH.cjs} +11 -7
  22. package/dist/{ld-tFPG-3Py.mjs → ld-D15LiIKe.mjs} +2 -2
  23. package/dist/{middleware-BdKmKQVN.js → middleware-Bk-4c-8L.js} +3 -3
  24. package/dist/{middleware-COfvRKeJ.cjs → middleware-CVzktDat.cjs} +1 -1
  25. package/dist/{middleware-Cz3MvIR9.cjs → middleware-DlKdnqX9.cjs} +4 -4
  26. package/dist/{middleware-Dv_3QqU2.mjs → middleware-DwRNhmyq.mjs} +1 -1
  27. package/dist/{middleware-qPjx43I5.mjs → middleware-jdGasCsA.mjs} +11 -11
  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-CLIF922S.mjs → owner-D0sAzTJN.mjs} +2 -2
  32. package/dist/{proof-BN8NQU4d.js → proof-B1Sd2Gkt.js} +1 -1
  33. package/dist/{proof-A0xdawSY.mjs → proof-BKfjzF2t.mjs} +2 -2
  34. package/dist/{proof-CW8cGLqW.cjs → proof-C0-VQw3l.cjs} +1 -1
  35. package/dist/{send-W_y4c7wJ.mjs → send-BtmOHBQy.mjs} +2 -2
  36. package/dist/sig/http.test.mjs +65 -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-BAxOchWE.mjs → temporal-DqNAe6lo.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 +5 -5
@@ -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-BBtJI5jH.mjs";
6
- import { t as InboxListenerSet } from "./inbox-BFkyrNC8.mjs";
5
+ import { n as version, t as name } from "./deno-BKr6e8uY.mjs";
6
+ import { t as InboxListenerSet } from "./inbox-BmfcF5Br.mjs";
7
7
  import { getTypeId } from "@fedify/vocab";
8
8
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
9
9
  import { getLogger } from "@logtape/logtape";
@@ -43,7 +43,7 @@ var FederationBuilderImpl = class {
43
43
  this.collectionTypeIds = {};
44
44
  }
45
45
  async build(options) {
46
- const { FederationImpl } = await import("./middleware-Dv_3QqU2.mjs");
46
+ const { FederationImpl } = await import("./middleware-DwRNhmyq.mjs");
47
47
  const f = new FederationImpl(options);
48
48
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
49
49
  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-tL2TOE9X.mjs";
8
- import { _ as autoIdAssigner, g as actorDehydrator, n as FederationImpl } from "../middleware-qPjx43I5.mjs";
8
+ import { _ as autoIdAssigner, g as actorDehydrator, n as FederationImpl } from "../middleware-jdGasCsA.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.1.20";
6
+ var version = "2.1.21";
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-Dlv6nEER.mjs";
5
- import { n as doubleKnock } from "./http-6RJdarOh.mjs";
4
+ import { o as validateCryptoKey } from "./key-CaELP2ph.mjs";
5
+ import { n as doubleKnock } from "./http-C8E0OP9c.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-tL2TOE9X.mjs";
8
- import { n as createFederationBuilder } from "../builder-BGAOx6I4.mjs";
8
+ import { n as createFederationBuilder } from "../builder-BOR3Daoc.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
@@ -7,12 +7,12 @@ 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
9
  import { r as parseAcceptSignature } from "../accept-Dd__NiUL.mjs";
10
- import { s as signRequest } from "../http-6RJdarOh.mjs";
10
+ import { s as signRequest } from "../http-C8E0OP9c.mjs";
11
11
  import { a as rsaPrivateKey3, c as rsaPublicKey3, s as rsaPublicKey2 } from "../keys-BAK-tUlf.mjs";
12
- import { a as compactJsonLd, f as signJsonLd } from "../ld-tFPG-3Py.mjs";
12
+ import { a as compactJsonLd, f as signJsonLd } from "../ld-D15LiIKe.mjs";
13
13
  import { t as MemoryKvStore } from "../kv-tL2TOE9X.mjs";
14
- 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-qPjx43I5.mjs";
15
- import { t as InboxListenerSet } from "../inbox-BFkyrNC8.mjs";
14
+ 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-jdGasCsA.mjs";
15
+ import { t as InboxListenerSet } from "../inbox-BmfcF5Br.mjs";
16
16
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
17
17
  import { Create, Note, Person } from "@fedify/vocab";
18
18
  import { FetchError } from "@fedify/vocab-runtime";
@@ -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-BAK-tUlf.mjs";
7
- import { n as signObject } from "../proof-A0xdawSY.mjs";
7
+ import { n as signObject } from "../proof-BKfjzF2t.mjs";
8
8
  import { t as MemoryKvStore } from "../kv-tL2TOE9X.mjs";
9
- import { a as createFederation } from "../middleware-qPjx43I5.mjs";
9
+ import { a as createFederation } from "../middleware-jdGasCsA.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-BFkyrNC8.mjs";
6
+ import { t as InboxListenerSet } from "../inbox-BmfcF5Br.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-6RJdarOh.mjs";
13
+ import { l as verifyRequest, s as signRequest } from "../http-C8E0OP9c.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-BAK-tUlf.mjs";
15
- import { t as getAuthenticatedDocumentLoader } from "../docloader-DfN4-Koe.mjs";
16
- import { a as compactJsonLd, f as signJsonLd, m as verifyJsonLd, s as detachSignature } from "../ld-tFPG-3Py.mjs";
17
- import { t as doesActorOwnKey } from "../owner-CLIF922S.mjs";
18
- import { n as signObject, r as verifyObject } from "../proof-A0xdawSY.mjs";
15
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-iEu432Fw.mjs";
16
+ import { a as compactJsonLd, f as signJsonLd, m as verifyJsonLd, s as detachSignature } from "../ld-D15LiIKe.mjs";
17
+ import { t as doesActorOwnKey } from "../owner-D0sAzTJN.mjs";
18
+ import { n as signObject, r as verifyObject } from "../proof-BKfjzF2t.mjs";
19
19
  import { t as MemoryKvStore } from "../kv-tL2TOE9X.mjs";
20
- import { a as createFederation, i as KvSpecDeterminer, n as FederationImpl, r as InboxContextImpl, t as ContextImpl } from "../middleware-qPjx43I5.mjs";
20
+ import { a as createFederation, i as KvSpecDeterminer, n as FederationImpl, r as InboxContextImpl, t as ContextImpl } from "../middleware-jdGasCsA.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-Cz3MvIR9.cjs");
5
+ const require_middleware = require("../middleware-DlKdnqX9.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-BdKmKQVN.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-Bk-4c-8L.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-6RJdarOh.mjs";
11
+ import { l as verifyRequest } from "../http-C8E0OP9c.mjs";
12
12
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.mjs";
13
- import { t as doesActorOwnKey } from "../owner-CLIF922S.mjs";
14
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-W_y4c7wJ.mjs";
13
+ import { t as doesActorOwnKey } from "../owner-D0sAzTJN.mjs";
14
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-BtmOHBQy.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-BAxOchWE.mjs";
7
+ import { t as hasMalformedKnownTemporalLiteral } from "../temporal-DqNAe6lo.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-tL2TOE9X.mjs";
8
- import { a as createFederation, o as handleWebFinger } from "../middleware-qPjx43I5.mjs";
8
+ import { a as createFederation, o as handleWebFinger } from "../middleware-jdGasCsA.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
@@ -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-BBtJI5jH.mjs";
4
+ import { n as version, t as name } from "./deno-BKr6e8uY.mjs";
5
5
  import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-Dd__NiUL.mjs";
6
- import { o as validateCryptoKey, r as fetchKeyDetailed } from "./key-Dlv6nEER.mjs";
6
+ import { o as validateCryptoKey, r as fetchKeyDetailed } from "./key-CaELP2ph.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,
@@ -924,7 +926,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
924
926
  let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
925
927
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
926
928
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
927
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
929
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
928
930
  if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
929
931
  return doubleKnockInternal(redirectRequest, identity, {
930
932
  ...options,
@@ -972,7 +974,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
972
974
  redirect: "manual",
973
975
  signal
974
976
  });
975
- if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return doubleKnock(createRedirectRequest(request, response.headers.get("Location"), body), identity, {
977
+ if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return doubleKnock(await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect), identity, {
976
978
  ...options,
977
979
  body
978
980
  });
@@ -999,7 +1001,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
999
1001
  response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1000
1002
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1001
1003
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
1002
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
1004
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
1003
1005
  if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1004
1006
  return doubleKnockInternal(redirectRequest, identity, {
1005
1007
  ...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.1.20";
13
+ var version = "2.1.21";
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,
@@ -1416,7 +1418,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1416
1418
  let response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1417
1419
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1418
1420
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
1419
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
1421
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
1420
1422
  if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1421
1423
  return doubleKnockInternal(redirectRequest, identity, {
1422
1424
  ...options,
@@ -1464,7 +1466,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1464
1466
  redirect: "manual",
1465
1467
  signal
1466
1468
  });
1467
- if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return doubleKnock(createRedirectRequest(request, response.headers.get("Location"), body), identity, {
1469
+ if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return doubleKnock(await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect), identity, {
1468
1470
  ...options,
1469
1471
  body
1470
1472
  });
@@ -1491,7 +1493,7 @@ async function doubleKnockInternal(request, identity, options, redirected = 0, v
1491
1493
  response = await fetchDoubleKnockRequest(request, signedRequest, signal);
1492
1494
  if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
1493
1495
  if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
1494
- const redirectRequest = createRedirectRequest(request, response.headers.get("Location"), body);
1496
+ const redirectRequest = await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect);
1495
1497
  if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1496
1498
  return doubleKnockInternal(redirectRequest, identity, {
1497
1499
  ...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.1.20";
14
+ var version = "2.1.21";
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,
@@ -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 >= DEFAULT_MAX_REDIRECTION) throw new _fedify_vocab_runtime.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 _fedify_vocab_runtime.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 >= DEFAULT_MAX_REDIRECTION) throw new _fedify_vocab_runtime.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 _fedify_vocab_runtime.FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
1497
1499
  return doubleKnockInternal(redirectRequest, identity, {
1498
1500
  ...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-BBtJI5jH.mjs";
4
+ import { n as version, t as name } from "./deno-BKr6e8uY.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-BBtJI5jH.mjs";
4
+ import { n as version, t as name } from "./deno-BKr6e8uY.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,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-BwW0QaNu.js";
3
+ import { d as validateCryptoKey, t as doubleKnock } from "./http-CLqgn9Jh.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,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-DYhyI8oM.cjs");
4
+ const require_http = require("./http-DjQHLsYQ.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,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-BBtJI5jH.mjs";
5
- import { n as fetchKey, o as validateCryptoKey } from "./key-Dlv6nEER.mjs";
4
+ import { n as version, t as name } from "./deno-BKr6e8uY.mjs";
5
+ import { n as fetchKey, o as validateCryptoKey } from "./key-CaELP2ph.mjs";
6
6
  import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
7
7
  import { SpanStatusCode, trace } from "@opentelemetry/api";
8
8
  import { getDocumentLoader } from "@fedify/vocab-runtime";
@@ -2,10 +2,10 @@ import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  import { t as __exportAll } from "./chunk-CRNNMoPX.js";
4
4
  import { r as getDefaultActivityTransformers } from "./transformers-BGMIq1cs.js";
5
- import { _ 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-BwW0QaNu.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-BN8NQU4d.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-CLqgn9Jh.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-B1Sd2Gkt.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-BjBQ1nMz.js";
8
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-DE1Vf7DK.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-Cz3MvIR9.cjs");
3
+ const require_middleware = require("./middleware-DlKdnqX9.cjs");
4
4
  exports.FederationImpl = require_middleware.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-DYhyI8oM.cjs");
6
- const require_proof = require("./proof-CW8cGLqW.cjs");
5
+ const require_http = require("./http-DjQHLsYQ.cjs");
6
+ const require_proof = require("./proof-C0-VQw3l.cjs");
7
7
  const require_types = require("./types-m8u9L86X.cjs");
8
- const require_kv_cache = require("./kv-cache-B3wIm0jW.cjs");
8
+ const require_kv_cache = require("./kv-cache-Odl-e0KH.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");
@@ -336,7 +336,7 @@ var FederationBuilderImpl = class {
336
336
  this.collectionTypeIds = {};
337
337
  }
338
338
  async build(options) {
339
- const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-COfvRKeJ.cjs"));
339
+ const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-CVzktDat.cjs"));
340
340
  const f = new FederationImpl(options);
341
341
  const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
342
342
  f.router = this.router.clone();
@@ -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-qPjx43I5.mjs";
4
+ import { n as FederationImpl } from "./middleware-jdGasCsA.mjs";
5
5
  export { FederationImpl };
@@ -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-BBtJI5jH.mjs";
5
+ import { n as version, t as name } from "./deno-BKr6e8uY.mjs";
6
6
  import { t as formatAcceptSignature } from "./accept-Dd__NiUL.mjs";
7
- import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-Dlv6nEER.mjs";
8
- import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-6RJdarOh.mjs";
9
- import { t as getAuthenticatedDocumentLoader } from "./docloader-DfN4-Koe.mjs";
7
+ import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-CaELP2ph.mjs";
8
+ import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-C8E0OP9c.mjs";
9
+ import { t as getAuthenticatedDocumentLoader } from "./docloader-iEu432Fw.mjs";
10
10
  import { n as kvCache } from "./kv-cache-FsT1ljhs.mjs";
11
- 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-tFPG-3Py.mjs";
12
- import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-CLIF922S.mjs";
13
- import { n as signObject, r as verifyObject } from "./proof-A0xdawSY.mjs";
11
+ 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-D15LiIKe.mjs";
12
+ import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-D0sAzTJN.mjs";
13
+ import { n as signObject, r as verifyObject } from "./proof-BKfjzF2t.mjs";
14
14
  import { t as getNodeInfo } from "./client-CZWLyLmp.mjs";
15
15
  import { t as nodeInfoToJson } from "./types-DCP0WLdt.mjs";
16
- import { n as routeActivity } from "./inbox-BFkyrNC8.mjs";
17
- import { t as FederationBuilderImpl } from "./builder-BGAOx6I4.mjs";
16
+ import { n as routeActivity } from "./inbox-BmfcF5Br.mjs";
17
+ import { t as FederationBuilderImpl } from "./builder-BOR3Daoc.mjs";
18
18
  import { t as buildCollectionSynchronizationHeader } from "./collection-BD6-SZ6O.mjs";
19
19
  import { t as KvKeyCache } from "./keycache-CCSwkQcY.mjs";
20
20
  import { t as acceptsJsonLd } from "./negotiation-DnsfFF8I.mjs";
21
- import { t as hasMalformedKnownTemporalLiteral } from "./temporal-BAxOchWE.mjs";
21
+ import { t as hasMalformedKnownTemporalLiteral } from "./temporal-DqNAe6lo.mjs";
22
22
  import { t as createExponentialBackoffPolicy } from "./retry-CJL0poaU.mjs";
23
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-W_y4c7wJ.mjs";
23
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-BtmOHBQy.mjs";
24
24
  import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
25
25
  import { lookupWebFinger } from "@fedify/webfinger";
26
26
  import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
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-DYhyI8oM.cjs");
8
- const require_middleware = require("./middleware-Cz3MvIR9.cjs");
9
- const require_proof = require("./proof-CW8cGLqW.cjs");
7
+ const require_http = require("./http-DjQHLsYQ.cjs");
8
+ const require_middleware = require("./middleware-DlKdnqX9.cjs");
9
+ const require_proof = require("./proof-C0-VQw3l.cjs");
10
10
  const require_types = require("./types-m8u9L86X.cjs");
11
- const require_kv_cache = require("./kv-cache-B3wIm0jW.cjs");
11
+ const require_kv_cache = require("./kv-cache-Odl-e0KH.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-BwW0QaNu.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-BdKmKQVN.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-BN8NQU4d.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-CLqgn9Jh.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-Bk-4c-8L.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-B1Sd2Gkt.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-BjBQ1nMz.js";
10
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-DE1Vf7DK.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-tL2TOE9X.mjs";
8
- import { a as createFederation, h as handleNodeInfoJrd, m as handleNodeInfo } from "../middleware-qPjx43I5.mjs";
8
+ import { a as createFederation, h as handleNodeInfoJrd, m as handleNodeInfo } from "../middleware-jdGasCsA.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-BBtJI5jH.mjs";
5
- import "./key-Dlv6nEER.mjs";
4
+ import { n as version, t as name } from "./deno-BKr6e8uY.mjs";
5
+ import "./key-CaELP2ph.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,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-BwW0QaNu.js";
3
+ import { _ as version, d as validateCryptoKey, g as name, s as fetchKey } from "./http-CLqgn9Jh.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 { Temporal } from "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-BBtJI5jH.mjs";
5
- import { n as fetchKey, o as validateCryptoKey } from "./key-Dlv6nEER.mjs";
4
+ import { n as version, t as name } from "./deno-BKr6e8uY.mjs";
5
+ import { n as fetchKey, o as validateCryptoKey } from "./key-CaELP2ph.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-DYhyI8oM.cjs");
4
+ const require_http = require("./http-DjQHLsYQ.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 "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "./deno-BBtJI5jH.mjs";
5
- import { n as doubleKnock } from "./http-6RJdarOh.mjs";
4
+ import { n as version, t as name } from "./deno-BKr6e8uY.mjs";
5
+ import { n as doubleKnock } from "./http-C8E0OP9c.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-Dlv6nEER.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-6RJdarOh.mjs";
10
+ import { t as exportJwk } from "../key-CaELP2ph.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-C8E0OP9c.mjs";
12
12
  import { i as rsaPrivateKey2, l as rsaPublicKey5, o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-BAK-tUlf.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 () => {
@@ -1588,6 +1619,37 @@ test("doubleKnock(): Accept-Signature challenge retry succeeds", async () => {
1588
1619
  assertEquals(requestCount, 2);
1589
1620
  esm_default.hardReset();
1590
1621
  });
1622
+ test("doubleKnock(): validates redirects after Accept-Signature challenge retry", async () => {
1623
+ esm_default.spyGlobal();
1624
+ let requestCount = 0;
1625
+ let privateRequestCount = 0;
1626
+ esm_default.post("https://example.com/inbox-challenge-redirect", () => {
1627
+ requestCount++;
1628
+ if (requestCount === 1) return new Response("Not Authorized", {
1629
+ status: 401,
1630
+ headers: { "Accept-Signature": "sig1=(\"@method\" \"@target-uri\" \"@authority\" \"content-digest\");created;nonce=\"challenge-nonce-redirect\"" }
1631
+ });
1632
+ return Response.redirect("http://localhost/private", 302);
1633
+ });
1634
+ esm_default.post("http://localhost/private", () => {
1635
+ privateRequestCount++;
1636
+ return new Response("", { status: 202 });
1637
+ });
1638
+ const request = new Request("https://example.com/inbox-challenge-redirect", {
1639
+ method: "POST",
1640
+ body: "Test message",
1641
+ headers: { "Content-Type": "text/plain" }
1642
+ });
1643
+ await assertRejects(() => doubleKnock(request, {
1644
+ keyId: rsaPublicKey2.id,
1645
+ privateKey: rsaPrivateKey2
1646
+ }, { validateRedirect(url) {
1647
+ throw new Error(`Disallowed redirect: ${url}`);
1648
+ } }), Error, "Disallowed redirect: http://localhost/private");
1649
+ assertEquals(requestCount, 2);
1650
+ assertEquals(privateRequestCount, 0);
1651
+ esm_default.hardReset();
1652
+ });
1591
1653
  test("doubleKnock(): unfulfillable Accept-Signature falls to legacy fallback", async () => {
1592
1654
  esm_default.spyGlobal();
1593
1655
  let requestCount = 0;
@@ -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 importJwk, i as generateCryptoKeyPair, n as fetchKey, o as validateCryptoKey, r as fetchKeyDetailed, t as exportJwk } from "../key-Dlv6nEER.mjs";
8
+ import { a as importJwk, i as generateCryptoKeyPair, n as fetchKey, o as validateCryptoKey, r as fetchKeyDetailed, t as exportJwk } from "../key-CaELP2ph.mjs";
9
9
  import { c as rsaPublicKey3, i as rsaPrivateKey2, o as rsaPublicKey1, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.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-ddO5KLpe.mjs";
8
- import { i as generateCryptoKeyPair } from "../key-Dlv6nEER.mjs";
8
+ import { i as generateCryptoKeyPair } from "../key-CaELP2ph.mjs";
9
9
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.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-tFPG-3Py.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-D15LiIKe.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-DYhyI8oM.cjs");
5
- const require_proof = require("../proof-CW8cGLqW.cjs");
4
+ const require_http = require("../http-DjQHLsYQ.cjs");
5
+ const require_proof = require("../proof-C0-VQw3l.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-BwW0QaNu.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-BN8NQU4d.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-CLqgn9Jh.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-B1Sd2Gkt.js";
5
5
  export { attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, fetchKeyDetailed, formatAcceptSignature, fulfillAcceptSignature, generateCryptoKeyPair, getKeyOwner, importJwk, parseAcceptSignature, signJsonLd, signObject, signRequest, validateAcceptSignature, verifyJsonLd, verifyObject, verifyProof, verifyRequest, verifyRequestDetailed, 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-BAK-tUlf.mjs";
9
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-CLIF922S.mjs";
9
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-D0sAzTJN.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-BAK-tUlf.mjs";
9
- import { i as verifyProof, n as signObject, r as verifyObject, t as createProof } from "../proof-A0xdawSY.mjs";
9
+ import { i as verifyProof, n as signObject, r as verifyObject, t as createProof } from "../proof-BKfjzF2t.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-tFPG-3Py.mjs";
4
+ import { c as getNormalizationContextLoader } from "./ld-D15LiIKe.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-6RJdarOh.mjs";
8
+ import { l as verifyRequest } from "../http-C8E0OP9c.mjs";
9
9
  import { i as rsaPrivateKey2 } from "../keys-BAK-tUlf.mjs";
10
- import { t as getAuthenticatedDocumentLoader } from "../docloader-DfN4-Koe.mjs";
10
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-iEu432Fw.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-B3wIm0jW.cjs");
4
+ const require_kv_cache = require("../kv-cache-Odl-e0KH.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-BjBQ1nMz.js";
3
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-DE1Vf7DK.js";
4
4
  export { getAuthenticatedDocumentLoader, kvCache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/fedify",
3
- "version": "2.1.20",
3
+ "version": "2.1.21",
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-runtime": "2.1.20",
148
- "@fedify/vocab": "2.1.20",
149
- "@fedify/webfinger": "2.1.20"
147
+ "@fedify/vocab-runtime": "2.1.21",
148
+ "@fedify/webfinger": "2.1.21",
149
+ "@fedify/vocab": "2.1.21"
150
150
  },
151
151
  "devDependencies": {
152
152
  "@std/assert": "npm:@jsr/std__assert@^0.226.0",
@@ -159,7 +159,7 @@
159
159
  "typescript": "^6.0.0",
160
160
  "wrangler": "^4.17.0",
161
161
  "@fedify/fixture": "2.0.0",
162
- "@fedify/vocab-tools": "^2.1.20"
162
+ "@fedify/vocab-tools": "^2.1.21"
163
163
  },
164
164
  "scripts": {
165
165
  "build:self": "tsdown",