@fedify/fedify 2.5.0-dev.2378 → 2.5.0-dev.2424

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 (92) hide show
  1. package/dist/{builder-J1K0IJj6.mjs → builder-crKu0U3j.mjs} +2 -2
  2. package/dist/compat/mod.d.cts +1 -1
  3. package/dist/compat/mod.d.ts +1 -1
  4. package/dist/compat/transformers.test.mjs +1 -1
  5. package/dist/{compound-proof-DtmVrMV7.mjs → compound-proof-D5pMfQau.mjs} +2 -2
  6. package/dist/{context-C2-UDo2c.d.ts → context-2wLkQrjb.d.ts} +11 -0
  7. package/dist/{context-BjD_CTxh.d.cts → context-DPocjp1l.d.cts} +11 -0
  8. package/dist/{deno-Ci6tSK9-.mjs → deno-Dgtb5dvg.mjs} +1 -1
  9. package/dist/{docloader-DZ9h6KJS.mjs → docloader-C8QI5jg2.mjs} +4 -2
  10. package/dist/federation/builder.test.mjs +1 -1
  11. package/dist/federation/compound-fanout.test.mjs +3 -3
  12. package/dist/federation/handler-compound-proof.test.mjs +5 -5
  13. package/dist/federation/handler.test.mjs +258 -5
  14. package/dist/federation/hashlink-media.test.mjs +2 -2
  15. package/dist/federation/idempotency.test.mjs +2 -2
  16. package/dist/federation/inbox-report.test.mjs +30 -5
  17. package/dist/federation/inbox.test.mjs +43 -0
  18. package/dist/federation/metrics.test.mjs +1 -1
  19. package/dist/federation/middleware.test.mjs +254 -11
  20. package/dist/federation/mod.cjs +1 -1
  21. package/dist/federation/mod.d.cts +2 -2
  22. package/dist/federation/mod.d.ts +2 -2
  23. package/dist/federation/mod.js +1 -1
  24. package/dist/federation/outgoing-proof.test.mjs +4 -4
  25. package/dist/federation/portable-actor.test.mjs +3 -3
  26. package/dist/federation/portable-chain.test.mjs +3 -3
  27. package/dist/federation/portable-collection.test.mjs +4 -4
  28. package/dist/federation/portable-delivery.test.mjs +2 -2
  29. package/dist/federation/portable-gateway-keys.test.mjs +4 -4
  30. package/dist/federation/portable-inbox.test.mjs +4 -4
  31. package/dist/federation/portable-parse-uri.test.mjs +1 -1
  32. package/dist/federation/portable-route-activity.test.mjs +2 -2
  33. package/dist/federation/portable.test.mjs +3 -3
  34. package/dist/federation/send.test.mjs +3 -3
  35. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  36. package/dist/federation/tasks/tasks.test.mjs +2 -2
  37. package/dist/federation/temporal.test.mjs +1 -1
  38. package/dist/federation/webfinger.test.mjs +1 -1
  39. package/dist/{federation-lzy7M3hT.cjs → federation-XZF9Yna_.cjs} +133 -21
  40. package/dist/{http-CFyizTHa.mjs → http-CO8l72H1.mjs} +4 -4
  41. package/dist/{http-Cmz7x6Iw.js → http-CRRQ6LBq.js} +1 -1
  42. package/dist/{http-D1RPHoq3.cjs → http-DZpLusNJ.cjs} +1 -1
  43. package/dist/inbox-q6uJubdj.mjs +188 -0
  44. package/dist/{kv-cache-rOQX3I3c.mjs → kv-cache-C-20uhXH.mjs} +1 -1
  45. package/dist/{kv-cache-C0-HuvwP.js → kv-cache-D5EHCk1_.js} +3 -1
  46. package/dist/{kv-cache-Jym5nP3J.cjs → kv-cache-DB0oTO06.cjs} +3 -1
  47. package/dist/{ld-DJ--ZUpr.mjs → ld-DqV2dhgT.mjs} +2 -2
  48. package/dist/{metrics-Dwgav7s_.mjs → metrics--5oGNIHa.mjs} +1 -1
  49. package/dist/{middleware-BbBsa5iR.mjs → middleware-BahtLJeT.mjs} +115 -180
  50. package/dist/{middleware-CJWxuUy5.mjs → middleware-Cna-mkwy.mjs} +1 -1
  51. package/dist/{middleware-CqgRIsWM.js → middleware-Mn7MeLDZ.js} +133 -21
  52. package/dist/{mod-BBPd4M_0.d.cts → mod-DKGoPoQC.d.cts} +1 -1
  53. package/dist/{mod-CUYBGKof.d.ts → mod-Dm-7RdhR.d.ts} +1 -1
  54. package/dist/mod.cjs +4 -4
  55. package/dist/mod.d.cts +2 -2
  56. package/dist/mod.d.ts +2 -2
  57. package/dist/mod.js +4 -4
  58. package/dist/nodeinfo/handler.test.mjs +1 -1
  59. package/dist/{owner-Btd7SwMj.mjs → owner-Cb6Kalag.mjs} +3 -3
  60. package/dist/{portable-collection-DwQT28O2.js → portable-collection-BweSVeOo.js} +1 -1
  61. package/dist/{portable-collection-BvWxS1sL.cjs → portable-collection-C3FBNHhB.cjs} +1 -1
  62. package/dist/{portable-collection-gb9V8XEO.mjs → portable-collection-DatZLGgt.mjs} +2 -2
  63. package/dist/{portable-key-Cwti99nP.mjs → portable-key-C2jzDc2S.mjs} +1 -1
  64. package/dist/{proof-Bwzv6mXZ.mjs → proof-BpQd-cat.mjs} +3 -3
  65. package/dist/{send-BrQYUSb4.mjs → send-CrgC-GYC.mjs} +3 -3
  66. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  67. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  68. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  69. package/dist/sig/compound-proof.test.mjs +2 -2
  70. package/dist/sig/http.test.mjs +2 -2
  71. package/dist/sig/key.test.mjs +1 -1
  72. package/dist/sig/ld.test.mjs +1 -1
  73. package/dist/sig/mitra-receive-interop.test.mjs +4 -4
  74. package/dist/sig/mitra-send-interop.test.mjs +3 -3
  75. package/dist/sig/mod.cjs +2 -2
  76. package/dist/sig/mod.js +2 -2
  77. package/dist/sig/owner.test.mjs +1 -1
  78. package/dist/sig/portable-collection.test.mjs +1 -1
  79. package/dist/sig/portable-interop.test.mjs +3 -3
  80. package/dist/sig/portable-key.test.mjs +5 -5
  81. package/dist/sig/proof.test.mjs +3 -3
  82. package/dist/sig/tootik-request-interop.test.mjs +4 -4
  83. package/dist/sig/tootik-send-interop.test.mjs +3 -3
  84. package/dist/sig/verification.test.mjs +3 -3
  85. package/dist/{temporal-BRaCTxVe.mjs → temporal-BjBxALiF.mjs} +1 -1
  86. package/dist/testing/kv.test.mjs +1 -1
  87. package/dist/testing/mod.d.mts +11 -0
  88. package/dist/utils/docloader.test.mjs +112 -37
  89. package/dist/utils/kv-cache.test.mjs +1 -1
  90. package/dist/utils/mod.cjs +1 -1
  91. package/dist/utils/mod.js +1 -1
  92. package/package.json +6 -6
@@ -5,9 +5,9 @@ import { t as esm_default } from "../esm-BHXXx4Wx.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
6
6
  import "../std__assert-DvMDRPes.mjs";
7
7
  import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
8
- import { f as verifyRequest } from "../http-CFyizTHa.mjs";
8
+ import { f as verifyRequest } from "../http-CO8l72H1.mjs";
9
9
  import { i as rsaPrivateKey2 } from "../keys-DIJNHW-Y.mjs";
10
- import { t as getAuthenticatedDocumentLoader } from "../docloader-DZ9h6KJS.mjs";
10
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-C8QI5jg2.mjs";
11
11
  import { configure, reset } from "@logtape/logtape";
12
12
  import { FetchError, UrlError } from "@fedify/vocab-runtime";
13
13
  import { mockDocumentLoader, test } from "@fedify/fixture";
@@ -99,45 +99,50 @@ test("getAuthenticatedDocumentLoader() validates redirects", async (t) => {
99
99
  });
100
100
  esm_default.hardReset();
101
101
  });
102
- test("getAuthenticatedDocumentLoader() cancellation", {
103
- sanitizeResources: false,
104
- sanitizeOps: false
105
- }, async (t) => {
102
+ test("getAuthenticatedDocumentLoader() cancellation", async (t) => {
106
103
  esm_default.spyGlobal();
107
- await t.step("document loader cancellation", async () => {
108
- esm_default.get("https://example.com/slow-object", () => new Promise((resolve) => {
109
- setTimeout(() => {
110
- resolve({
111
- status: 200,
112
- headers: { "Content-Type": "application/activity+json" },
113
- body: {
114
- "@context": "https://www.w3.org/ns/activitystreams",
115
- type: "Note",
116
- content: "Slow response"
117
- }
104
+ try {
105
+ await t.step("document loader cancellation", async () => {
106
+ let responseTimer;
107
+ try {
108
+ esm_default.get("https://example.com/slow-object", () => new Promise((resolve) => {
109
+ responseTimer = setTimeout(() => {
110
+ resolve({
111
+ status: 200,
112
+ headers: { "Content-Type": "application/activity+json" },
113
+ body: {
114
+ "@context": "https://www.w3.org/ns/activitystreams",
115
+ type: "Note",
116
+ content: "Slow response"
117
+ }
118
+ });
119
+ }, 1e3);
120
+ }));
121
+ const loader = getAuthenticatedDocumentLoader({
122
+ keyId: new URL("https://example.com/key2"),
123
+ privateKey: rsaPrivateKey2
118
124
  });
119
- }, 1e3);
120
- }));
121
- const loader = getAuthenticatedDocumentLoader({
122
- keyId: new URL("https://example.com/key2"),
123
- privateKey: rsaPrivateKey2
125
+ const controller = new AbortController();
126
+ const promise = loader("https://example.com/slow-object", { signal: controller.signal });
127
+ controller.abort();
128
+ await assertRejects(() => promise, Error);
129
+ await assertRejects(() => loader("https://example.com/object", { signal: controller.signal }), Error);
130
+ } finally {
131
+ clearTimeout(responseTimer);
132
+ }
124
133
  });
125
- const controller = new AbortController();
126
- const promise = loader("https://example.com/slow-object", { signal: controller.signal });
127
- controller.abort();
128
- await assertRejects(() => promise, Error);
129
- await assertRejects(() => loader("https://example.com/object", { signal: controller.signal }), Error);
130
- });
131
- await t.step("immediate cancellation", async () => {
132
- const loader = getAuthenticatedDocumentLoader({
133
- keyId: new URL("https://example.com/key2"),
134
- privateKey: rsaPrivateKey2
134
+ await t.step("immediate cancellation", async () => {
135
+ const loader = getAuthenticatedDocumentLoader({
136
+ keyId: new URL("https://example.com/key2"),
137
+ privateKey: rsaPrivateKey2
138
+ });
139
+ const controller = new AbortController();
140
+ controller.abort();
141
+ await assertRejects(() => loader("https://example.com/object", { signal: controller.signal }), Error);
135
142
  });
136
- const controller = new AbortController();
137
- controller.abort();
138
- await assertRejects(() => loader("https://example.com/object", { signal: controller.signal }), Error);
139
- });
140
- esm_default.hardReset();
143
+ } finally {
144
+ esm_default.hardReset();
145
+ }
141
146
  });
142
147
  test("getAuthenticatedDocumentLoader() bounds JSON after redirects", async () => {
143
148
  esm_default.mockGlobal();
@@ -625,5 +630,75 @@ test("getAuthenticatedDocumentLoader() times out", async (t) => {
625
630
  }
626
631
  });
627
632
  });
633
+ const unsupportedUrls = [
634
+ "ftp://example.com/collection",
635
+ "file:///collection",
636
+ `data:application/ld+json,${encodeURIComponent(JSON.stringify({ id: "https://example.com/data" }))}`
637
+ ];
638
+ function isUnsupportedProtocolError(error, url) {
639
+ return error instanceof UrlError && error.message === `Unsupported protocol: ${new URL(url).protocol}` && error.reason === "disallowed";
640
+ }
641
+ async function withFetchStub(respond, callback) {
642
+ const fetched = [];
643
+ const originalFetch = globalThis.fetch;
644
+ globalThis.fetch = ((input, init) => {
645
+ const request = input instanceof Request && init == null ? input : new Request(input, init);
646
+ fetched.push(request);
647
+ return Promise.resolve(respond(request));
648
+ });
649
+ try {
650
+ await callback(fetched);
651
+ } finally {
652
+ globalThis.fetch = originalFetch;
653
+ }
654
+ }
655
+ for (const url of unsupportedUrls) {
656
+ const scheme = new URL(url).protocol;
657
+ const loader = getAuthenticatedDocumentLoader({
658
+ keyId: new URL("https://example.com/key2"),
659
+ privateKey: rsaPrivateKey2
660
+ }, { allowPrivateAddress: true });
661
+ test(`getAuthenticatedDocumentLoader() rejects ${scheme} URLs with private addresses allowed before fetching`, async () => {
662
+ await withFetchStub(() => Response.json({}), async (fetched) => {
663
+ await rejects(loader(url), (e) => isUnsupportedProtocolError(e, url));
664
+ deepStrictEqual(fetched, []);
665
+ });
666
+ });
667
+ test(`getAuthenticatedDocumentLoader() rejects redirects to ${scheme} URLs with private addresses allowed`, async () => {
668
+ const start = "https://example.com/redirect-to-unsupported";
669
+ await withFetchStub(() => Response.redirect(url, 302), async (fetched) => {
670
+ await rejects(loader(start), (e) => isUnsupportedProtocolError(e, url));
671
+ deepStrictEqual(fetched.map((r) => r.url), [start]);
672
+ });
673
+ });
674
+ for (const firstSpec of ["rfc9421", "draft-cavage-http-signatures-12"]) test(`getAuthenticatedDocumentLoader() rejects redirects to ${scheme} URLs after signature fallback from ${firstSpec}`, async () => {
675
+ const start = "https://example.com/fallback-redirect-to-unsupported";
676
+ const fallbackLoader = getAuthenticatedDocumentLoader({
677
+ keyId: new URL("https://example.com/key2"),
678
+ privateKey: rsaPrivateKey2
679
+ }, {
680
+ allowPrivateAddress: true,
681
+ specDeterminer: {
682
+ determineSpec: () => firstSpec,
683
+ rememberSpec: () => {}
684
+ }
685
+ });
686
+ await withFetchStub((request) => request.headers.has("Signature-Input") === (firstSpec === "rfc9421") ? new Response("Unauthorized", { status: 401 }) : Response.redirect(url, 302), async (fetched) => {
687
+ await rejects(fallbackLoader(start), (e) => isUnsupportedProtocolError(e, url));
688
+ deepStrictEqual(fetched.map((r) => r.url), [start, start]);
689
+ deepStrictEqual(fetched.map((r) => r.headers.has("Signature-Input")), [firstSpec === "rfc9421", firstSpec !== "rfc9421"]);
690
+ });
691
+ });
692
+ for (const html of [false, true]) test(`getAuthenticatedDocumentLoader() rejects ${html ? "HTML" : "Link header"} alternates to ${scheme} URLs with private addresses allowed`, async () => {
693
+ const start = "https://example.com/alternate-to-unsupported";
694
+ await withFetchStub(() => html ? new Response(`<link rel="alternate" type="application/activity+json" href="${url}">`, { headers: { "Content-Type": "text/html" } }) : new Response("", { headers: {
695
+ "Content-Type": "text/plain",
696
+ Link: `<${url}>; rel="alternate"; type="application/activity+json"`
697
+ } }), async (fetched) => {
698
+ await rejects(loader(start), (e) => isUnsupportedProtocolError(e, url));
699
+ deepStrictEqual(fetched.map((r) => r.url), [start]);
700
+ });
701
+ });
702
+ }
628
703
  //#endregion
629
704
  export {};
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as kvCache, t as MockKvStore } from "../kv-cache-rOQX3I3c.mjs";
4
+ import { n as kvCache, t as MockKvStore } from "../kv-cache-C-20uhXH.mjs";
5
5
  import { preloadedContexts } from "@fedify/vocab-runtime";
6
6
  import { deepStrictEqual, throws } from "node:assert";
7
7
  import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
@@ -1,5 +1,5 @@
1
1
  const { URLPattern } = require("urlpattern-polyfill");
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_kv_cache = require("../kv-cache-Jym5nP3J.cjs");
3
+ const require_kv_cache = require("../kv-cache-DB0oTO06.cjs");
4
4
  exports.getAuthenticatedDocumentLoader = require_kv_cache.getAuthenticatedDocumentLoader;
5
5
  exports.kvCache = require_kv_cache.kvCache;
package/dist/utils/mod.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-C0-HuvwP.js";
3
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-D5EHCk1_.js";
4
4
  export { getAuthenticatedDocumentLoader, kvCache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/fedify",
3
- "version": "2.5.0-dev.2378+fea9c751",
3
+ "version": "2.5.0-dev.2424+97214632",
4
4
  "description": "An ActivityPub server framework",
5
5
  "keywords": [
6
6
  "ActivityPub",
@@ -151,10 +151,10 @@
151
151
  "structured-field-values": "^2.0.4",
152
152
  "temporal-polyfill": "^1.0.1",
153
153
  "urlpattern-polyfill": "^10.1.0",
154
- "@fedify/uri-template": "2.5.0-dev.2378+fea9c751",
155
- "@fedify/webfinger": "2.5.0-dev.2378+fea9c751",
156
- "@fedify/vocab-runtime": "2.5.0-dev.2378+fea9c751",
157
- "@fedify/vocab": "2.5.0-dev.2378+fea9c751"
154
+ "@fedify/uri-template": "2.5.0-dev.2424+97214632",
155
+ "@fedify/webfinger": "2.5.0-dev.2424+97214632",
156
+ "@fedify/vocab": "2.5.0-dev.2424+97214632",
157
+ "@fedify/vocab-runtime": "2.5.0-dev.2424+97214632"
158
158
  },
159
159
  "devDependencies": {
160
160
  "@std/assert": "npm:@jsr/std__assert@^0.226.0",
@@ -167,7 +167,7 @@
167
167
  "typescript": "^6.0.0",
168
168
  "wrangler": "^4.17.0",
169
169
  "@fedify/fixture": "2.0.0",
170
- "@fedify/vocab-tools": "^2.5.0-dev.2378+fea9c751"
170
+ "@fedify/vocab-tools": "^2.5.0-dev.2424+97214632"
171
171
  },
172
172
  "scripts": {
173
173
  "build:self": "tsdown",