@fedify/fedify 2.3.13 → 2.3.15-dev.2482

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 (52) hide show
  1. package/dist/{builder-BagNDcQw.mjs → builder-CocMrVkL.mjs} +2 -2
  2. package/dist/compat/transformers.test.mjs +1 -1
  3. package/dist/{deno-XpcjbHwj.mjs → deno-po8iekMB.mjs} +1 -1
  4. package/dist/{docloader-QDpF5t9M.mjs → docloader-BVj35vgR.mjs} +5 -3
  5. package/dist/federation/builder.test.mjs +1 -1
  6. package/dist/federation/handler.test.mjs +5 -5
  7. package/dist/federation/idempotency.test.mjs +2 -2
  8. package/dist/federation/inbox.test.mjs +1 -1
  9. package/dist/federation/keycache.test.mjs +18 -7
  10. package/dist/federation/metrics.test.mjs +1 -1
  11. package/dist/federation/middleware.test.mjs +72 -7
  12. package/dist/federation/mod.cjs +1 -1
  13. package/dist/federation/mod.js +1 -1
  14. package/dist/federation/send.test.mjs +3 -3
  15. package/dist/federation/temporal.test.mjs +1 -1
  16. package/dist/federation/webfinger.test.mjs +1 -1
  17. package/dist/{http-BRrpIDS1.mjs → http-BNCLeQJ-.mjs} +3 -3
  18. package/dist/{http-GHVGCeb5.js → http-Cdu8BGtv.js} +17 -3
  19. package/dist/{http-DwPnG87d.cjs → http-WcSdFbt1.cjs} +17 -3
  20. package/dist/{inbox-BzOuCPLY.mjs → inbox-g1sd_Vjn.mjs} +2 -2
  21. package/dist/{key-PdEu1lDF.mjs → key-BR2TRTXR.mjs} +18 -4
  22. package/dist/{keycache-Dkc_sflV.mjs → keycache-BimEQucx.mjs} +1 -1
  23. package/dist/{kv-cache-Clx3SwMp.mjs → kv-cache-8SigUtvX.mjs} +1 -1
  24. package/dist/{kv-cache-poF6Tqnz.cjs → kv-cache-Bw_gduSm.cjs} +4 -2
  25. package/dist/{kv-cache-BmqdF048.js → kv-cache-C0AqpjoS.js} +4 -2
  26. package/dist/{ld-D6UlzNnG.mjs → ld-CSNsWdYE.mjs} +3 -3
  27. package/dist/{metrics-62qolVUY.mjs → metrics-BS7YzLVA.mjs} +1 -1
  28. package/dist/{middleware-CfbFdEO-.mjs → middleware-B1RRLN7m.mjs} +15 -15
  29. package/dist/{middleware-DkrXqZO_.cjs → middleware-D-SL8Bkj.cjs} +5 -5
  30. package/dist/{middleware-C3Q3CoR8.mjs → middleware-Dlo7NnZl.mjs} +1 -1
  31. package/dist/{middleware-xw9fBZoB.js → middleware-WL-JfDiK.js} +5 -5
  32. package/dist/mod.cjs +4 -4
  33. package/dist/mod.js +4 -4
  34. package/dist/nodeinfo/handler.test.mjs +1 -1
  35. package/dist/{owner-DWnLg-vk.mjs → owner-DeggvxcG.mjs} +2 -2
  36. package/dist/{proof-mf6h7n4_.mjs → proof-DMcUrrp8.mjs} +3 -3
  37. package/dist/{proof-DF6CU-SU.cjs → proof-teNNYmFh.cjs} +1 -1
  38. package/dist/{proof-CUSzBztF.js → proof-v-IzWx7x.js} +1 -1
  39. package/dist/{send-LJUzNpVF.mjs → send-BsthcvPG.mjs} +3 -3
  40. package/dist/sig/http.test.mjs +3 -3
  41. package/dist/sig/key.test.mjs +197 -3
  42. package/dist/sig/ld.test.mjs +47 -2
  43. package/dist/sig/mod.cjs +2 -2
  44. package/dist/sig/mod.js +2 -2
  45. package/dist/sig/owner.test.mjs +46 -1
  46. package/dist/sig/proof.test.mjs +52 -1
  47. package/dist/{temporal-_3yIqdvy.mjs → temporal-Cji8Y8eQ.mjs} +1 -1
  48. package/dist/utils/docloader.test.mjs +66 -2
  49. package/dist/utils/kv-cache.test.mjs +1 -1
  50. package/dist/utils/mod.cjs +1 -1
  51. package/dist/utils/mod.js +1 -1
  52. package/package.json +6 -6
@@ -8,7 +8,7 @@ import { n as assertGreaterOrEqual, t as assertRejects } from "../assert_rejects
8
8
  import { n as assertInstanceOf, t as assert } from "../assert-CEO06XCw.mjs";
9
9
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.mjs";
10
10
  import { r as normalizeOutgoingActivityJsonLd } from "../outgoing-jsonld-D4iTv7uM.mjs";
11
- import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-mf6h7n4_.mjs";
11
+ import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-DMcUrrp8.mjs";
12
12
  import { Create, DataIntegrityProof, Document, Multikey, Note, PUBLIC_COLLECTION, Place } from "@fedify/vocab";
13
13
  import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
14
14
  import { decodeMultibase, importMultibaseKey } from "@fedify/vocab-runtime";
@@ -599,5 +599,56 @@ test("verifyObject() rejects a key that claims a forged controller", async () =>
599
599
  contextLoader: mockDocumentLoader
600
600
  }), null);
601
601
  });
602
+ test("verifyObject() rejects a key whose controller redirects to another actor", async () => {
603
+ const keyId = new URL("https://evil.example/keys/ed25519");
604
+ const victim = "https://victim.example/users/alice";
605
+ const mallory = "https://evil.example/users/mallory";
606
+ const multikeyDocument = await ed25519Multikey.toJsonLd({ contextLoader: mockDocumentLoader });
607
+ const signOptions = {
608
+ format: "compact",
609
+ contextLoader: mockDocumentLoader,
610
+ documentLoader: mockDocumentLoader,
611
+ context: ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/data-integrity/v1"]
612
+ };
613
+ assertEquals(await verifyObject(Create, await (await signObject(new Create({
614
+ id: new URL("https://victim.example/activities/forged"),
615
+ actor: new URL(victim),
616
+ object: new Note({
617
+ id: new URL("https://victim.example/notes/forged"),
618
+ attribution: new URL(victim),
619
+ content: "forged"
620
+ })
621
+ }), ed25519PrivateKey, keyId, signOptions)).toJsonLd(signOptions), {
622
+ documentLoader(resource) {
623
+ if (resource === keyId.href) return Promise.resolve({
624
+ contextUrl: null,
625
+ documentUrl: resource,
626
+ document: {
627
+ ...multikeyDocument,
628
+ id: keyId.href,
629
+ controller: victim
630
+ }
631
+ });
632
+ if (resource === victim || resource === mallory) return Promise.resolve({
633
+ contextUrl: null,
634
+ documentUrl: mallory,
635
+ document: {
636
+ "@context": [
637
+ "https://www.w3.org/ns/activitystreams",
638
+ "https://w3id.org/security/v1",
639
+ "https://w3id.org/security/multikey/v1",
640
+ "https://w3id.org/security/data-integrity/v1",
641
+ "https://www.w3.org/ns/did/v1"
642
+ ],
643
+ id: mallory,
644
+ type: "Person",
645
+ assertionMethod: [keyId.href]
646
+ }
647
+ });
648
+ return mockDocumentLoader(resource);
649
+ },
650
+ contextLoader: mockDocumentLoader
651
+ }), null);
652
+ });
602
653
  //#endregion
603
654
  export {};
@@ -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-D6UlzNnG.mjs";
4
+ import { c as getNormalizationContextLoader } from "./ld-CSNsWdYE.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-vrlUxr60.mjs";
5
5
  import { t as assertEquals } from "../assert_equals-C-ZRDbaf.mjs";
6
6
  import "../std__assert-BjJn2daJ.mjs";
7
7
  import { t as assertRejects } from "../assert_rejects-D1HYAik3.mjs";
8
- import { l as verifyRequest } from "../http-BRrpIDS1.mjs";
8
+ import { l as verifyRequest } from "../http-BNCLeQJ-.mjs";
9
9
  import { i as rsaPrivateKey2 } from "../keys-BAK-tUlf.mjs";
10
- import { t as getAuthenticatedDocumentLoader } from "../docloader-QDpF5t9M.mjs";
10
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-BVj35vgR.mjs";
11
11
  import { configure, reset } from "@logtape/logtape";
12
12
  import { mockDocumentLoader, test } from "@fedify/fixture";
13
13
  import { FetchError, UrlError } from "@fedify/vocab-runtime";
@@ -466,6 +466,70 @@ const unsupportedUrls = [
466
466
  "file:///collection",
467
467
  `data:application/ld+json,${encodeURIComponent(JSON.stringify({ id: "https://example.com/data" }))}`
468
468
  ];
469
+ function isCredentialUrlError(error) {
470
+ return error instanceof UrlError && error.reason === "disallowed" && error.message === "URLs with credentials are not allowed";
471
+ }
472
+ test("getAuthenticatedDocumentLoader() rejects URLs with credentials", async (t) => {
473
+ const identity = {
474
+ keyId: new URL("https://example.com/key2"),
475
+ privateKey: rsaPrivateKey2
476
+ };
477
+ const start = "https://8.8.8.8/start";
478
+ const target = "https://user:pass@8.8.8.8/document";
479
+ for (const allowPrivateAddress of [false, true]) {
480
+ const loader = getAuthenticatedDocumentLoader(identity, { allowPrivateAddress });
481
+ for (const path of [
482
+ "direct",
483
+ "redirect",
484
+ "Link",
485
+ "HTML"
486
+ ]) await t.step(`${path}, allowPrivateAddress=${allowPrivateAddress}`, async () => {
487
+ await withFetchStub((request) => {
488
+ if (request.url !== start) return Response.json({});
489
+ if (path === "redirect") return Response.redirect(target, 302);
490
+ if (path === "HTML") return new Response(`<link rel="alternate" type="application/activity+json" href="${target}">`, { headers: { "Content-Type": "text/html" } });
491
+ return new Response("", { headers: {
492
+ "Content-Type": "text/plain",
493
+ Link: `<${target}>; rel="alternate"; type="application/activity+json"`
494
+ } });
495
+ }, async (fetched) => {
496
+ await rejects(loader(path === "direct" ? target : start), isCredentialUrlError);
497
+ deepStrictEqual(fetched.map((r) => r.url), path === "direct" ? [] : [start]);
498
+ });
499
+ });
500
+ for (const url of [
501
+ "https://user@8.8.8.8/document",
502
+ "https://:pass@8.8.8.8/document",
503
+ "https://%75ser:p%40ss@8.8.8.8/document",
504
+ "http://user:pass@8.8.8.8/document"
505
+ ]) await t.step(`${url}, allowPrivateAddress=${allowPrivateAddress}`, async () => {
506
+ await withFetchStub(() => Response.json({}), async (fetched) => {
507
+ await rejects(loader(url), isCredentialUrlError);
508
+ deepStrictEqual(fetched, []);
509
+ });
510
+ });
511
+ for (const url of ["https://:@8.8.8.8/document", "https://8.8.8.8/@user?q=@pass"]) await t.step(`allows ${url}, allowPrivateAddress=${allowPrivateAddress}`, async () => {
512
+ await withFetchStub(() => Response.json({ done: true }), async (fetched) => {
513
+ deepStrictEqual((await loader(url)).document, { done: true });
514
+ deepStrictEqual(fetched.map((r) => r.url), [new URL(url).href]);
515
+ });
516
+ });
517
+ }
518
+ for (const firstSpec of ["rfc9421", "draft-cavage-http-signatures-12"]) await t.step(`redirect after fallback from ${firstSpec}`, async () => {
519
+ const loader = getAuthenticatedDocumentLoader(identity, {
520
+ allowPrivateAddress: true,
521
+ specDeterminer: {
522
+ determineSpec: () => firstSpec,
523
+ rememberSpec: () => {}
524
+ }
525
+ });
526
+ await withFetchStub((request) => request.url !== start ? Response.json({}) : request.headers.has("Signature-Input") === (firstSpec === "rfc9421") ? new Response(null, { status: 401 }) : Response.redirect(target, 302), async (fetched) => {
527
+ await rejects(loader(start), isCredentialUrlError);
528
+ deepStrictEqual(fetched.map((r) => r.url), [start, start]);
529
+ deepStrictEqual(fetched.map((r) => r.headers.has("Signature-Input")), [firstSpec === "rfc9421", firstSpec !== "rfc9421"]);
530
+ });
531
+ });
532
+ });
469
533
  function isUnsupportedProtocolError(error, url) {
470
534
  return error instanceof UrlError && error.message === `Unsupported protocol: ${new URL(url).protocol}` && error.reason === "disallowed";
471
535
  }
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "@js-temporal/polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as kvCache, t as MockKvStore } from "../kv-cache-Clx3SwMp.mjs";
4
+ import { n as kvCache, t as MockKvStore } from "../kv-cache-8SigUtvX.mjs";
5
5
  import { deepStrictEqual, throws } from "node:assert";
6
6
  import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
7
7
  import { preloadedContexts } from "@fedify/vocab-runtime";
@@ -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-poF6Tqnz.cjs");
4
+ const require_kv_cache = require("../kv-cache-Bw_gduSm.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-BmqdF048.js";
3
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-C0AqpjoS.js";
4
4
  export { getAuthenticatedDocumentLoader, kvCache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/fedify",
3
- "version": "2.3.13",
3
+ "version": "2.3.15-dev.2482+41d364a2",
4
4
  "description": "An ActivityPub server framework",
5
5
  "keywords": [
6
6
  "ActivityPub",
@@ -152,10 +152,10 @@
152
152
  "jsonld": "^9.0.0",
153
153
  "structured-field-values": "^2.0.4",
154
154
  "urlpattern-polyfill": "^10.1.0",
155
- "@fedify/uri-template": "2.3.13",
156
- "@fedify/vocab": "2.3.13",
157
- "@fedify/vocab-runtime": "2.3.13",
158
- "@fedify/webfinger": "2.3.13"
155
+ "@fedify/vocab": "2.3.15-dev.2482+41d364a2",
156
+ "@fedify/vocab-runtime": "2.3.15-dev.2482+41d364a2",
157
+ "@fedify/uri-template": "2.3.15-dev.2482+41d364a2",
158
+ "@fedify/webfinger": "2.3.15-dev.2482+41d364a2"
159
159
  },
160
160
  "devDependencies": {
161
161
  "@std/assert": "npm:@jsr/std__assert@^0.226.0",
@@ -168,7 +168,7 @@
168
168
  "typescript": "^6.0.0",
169
169
  "wrangler": "^4.17.0",
170
170
  "@fedify/fixture": "2.0.0",
171
- "@fedify/vocab-tools": "^2.3.13"
171
+ "@fedify/vocab-tools": "^2.3.15-dev.2482+41d364a2"
172
172
  },
173
173
  "scripts": {
174
174
  "build:self": "tsdown",