@fedify/fedify 2.4.0-dev.2159 → 2.4.0-dev.2169

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 (96) hide show
  1. package/dist/{builder-D89oOfHC.mjs → builder-B2d_Pt0j.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-B02Os8h2.mjs → compound-proof-D28gMFqP.mjs} +2 -2
  6. package/dist/{context-JDNkUtnu.d.ts → context-BykNUf04.d.ts} +1 -1
  7. package/dist/{context-DpsaHkk1.d.cts → context-L0Fnib9j.d.cts} +1 -1
  8. package/dist/{deno-CE_s0yQb.mjs → deno-DU8dvnWk.mjs} +1 -1
  9. package/dist/{docloader-C5p26tpa.mjs → docloader-CghLH7Zi.mjs} +2 -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 +3 -3
  13. package/dist/federation/handler.test.mjs +5 -5
  14. package/dist/federation/hashlink-media.test.mjs +2 -2
  15. package/dist/federation/idempotency.test.mjs +2 -2
  16. package/dist/federation/keycache.test.mjs +67 -1
  17. package/dist/federation/metrics.test.mjs +1 -1
  18. package/dist/federation/middleware.test.mjs +7 -7
  19. package/dist/federation/mod.cjs +1 -1
  20. package/dist/federation/mod.d.cts +2 -2
  21. package/dist/federation/mod.d.ts +2 -2
  22. package/dist/federation/mod.js +1 -1
  23. package/dist/federation/outgoing-proof.test.mjs +5 -5
  24. package/dist/federation/portable-actor.test.mjs +3 -3
  25. package/dist/federation/portable-chain.test.mjs +3 -3
  26. package/dist/federation/portable-collection.test.mjs +4 -4
  27. package/dist/federation/portable-gateway-keys.test.mjs +180 -6
  28. package/dist/federation/portable-inbox.test.mjs +4 -4
  29. package/dist/federation/portable-parse-uri.test.mjs +1 -1
  30. package/dist/federation/portable.test.mjs +3 -3
  31. package/dist/federation/send.test.mjs +3 -3
  32. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  33. package/dist/federation/tasks/tasks.test.mjs +2 -2
  34. package/dist/federation/temporal.test.mjs +1 -1
  35. package/dist/federation/webfinger.test.mjs +1 -1
  36. package/dist/{federation-dBOqmJcA.cjs → federation-DrNgkLfJ.cjs} +48 -24
  37. package/dist/{http-wdsia0-O.cjs → http-5CJBdU8n.cjs} +392 -65
  38. package/dist/{http-nTZuTacw.js → http-BGpexPO7.js} +368 -61
  39. package/dist/{http-DV_yW4dv.mjs → http-Bd6rZlJX.mjs} +7 -5
  40. package/dist/{http-C-x_OLSp.d.ts → http-Cok5-vIC.d.ts} +5 -0
  41. package/dist/{http-CjezPjFX.d.cts → http-DC1cqAQ2.d.cts} +5 -0
  42. package/dist/{key-C6jnekFI.mjs → key-gIhVZO3p.mjs} +58 -7
  43. package/dist/key-owner-evidence-Bo3yaeL5.mjs +108 -0
  44. package/dist/{keycache-BInaECGj.mjs → keycache-PiOM9pM0.mjs} +46 -21
  45. package/dist/{kv-cache-Bxm0a0Ww.mjs → kv-cache-D0qjSeWY.mjs} +1 -1
  46. package/dist/{kv-cache-BHNtQi9e.cjs → kv-cache-YRi_g8GB.cjs} +1 -1
  47. package/dist/{kv-cache-DhIl9YlV.js → kv-cache-iR55fqlk.js} +1 -1
  48. package/dist/{ld-ya2C1Xip.mjs → ld-BsTkRrwF.mjs} +3 -3
  49. package/dist/{metrics-ByOQOHHS.mjs → metrics-jUDFfVgi.mjs} +1 -1
  50. package/dist/{middleware-Bdwd_Gg8.mjs → middleware-Coqgp-K0.mjs} +15 -15
  51. package/dist/{middleware-WiaN4RS3.js → middleware-DlxMxVp5.js} +48 -24
  52. package/dist/{middleware-DoVWq8mE.mjs → middleware-Dq-OCmb6.mjs} +1 -1
  53. package/dist/{mod-Bz9tFXI2.d.ts → mod--jv6vyrP.d.ts} +1 -1
  54. package/dist/{mod-DaiBrWDW.d.ts → mod-B5z_q9TH.d.ts} +1 -1
  55. package/dist/{mod-Mt4aO3DX.d.cts → mod-BA_F2x53.d.cts} +1 -1
  56. package/dist/{mod-DSKkTwH2.d.cts → mod-BLOXGs6m.d.cts} +1 -1
  57. package/dist/{mod-S--JxYjo.d.cts → mod-CPPqkyV_.d.cts} +1 -1
  58. package/dist/{mod-_4K05HZF.d.ts → mod-DK0y9fd-.d.ts} +1 -1
  59. package/dist/mod.cjs +4 -4
  60. package/dist/mod.d.cts +5 -5
  61. package/dist/mod.d.ts +5 -5
  62. package/dist/mod.js +4 -4
  63. package/dist/nodeinfo/handler.test.mjs +1 -1
  64. package/dist/{owner-C6Nv5yyw.mjs → owner-D3GoetXS.mjs} +18 -3
  65. package/dist/{portable-collection-B-mU1F1-.js → portable-collection-Bkdh_WpL.js} +15 -1
  66. package/dist/{portable-collection-uWj3hfzv.mjs → portable-collection-C60_acmx.mjs} +2 -2
  67. package/dist/{portable-collection-C65SwL2l.cjs → portable-collection-CnlCamup.cjs} +15 -1
  68. package/dist/{portable-key-BXsVLSMa.mjs → portable-key-DyF5AnZo.mjs} +209 -55
  69. package/dist/{proof-BdO3BbLh.mjs → proof-CQAYqWdj.mjs} +4 -4
  70. package/dist/{send-BwANxryy.mjs → send-DjkQrxt5.mjs} +3 -3
  71. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  72. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  73. package/dist/sig/compound-proof-verification.test.mjs +2 -2
  74. package/dist/sig/compound-proof.test.mjs +2 -2
  75. package/dist/sig/http.test.mjs +2 -2
  76. package/dist/sig/key-owner-evidence.test.d.mts +2 -0
  77. package/dist/sig/key-owner-evidence.test.mjs +100 -0
  78. package/dist/sig/key.test.mjs +1 -1
  79. package/dist/sig/ld.test.mjs +2 -2
  80. package/dist/sig/mod.cjs +2 -2
  81. package/dist/sig/mod.d.cts +2 -2
  82. package/dist/sig/mod.d.ts +2 -2
  83. package/dist/sig/mod.js +2 -2
  84. package/dist/sig/owner.test.mjs +1 -1
  85. package/dist/sig/portable-collection.test.mjs +1 -1
  86. package/dist/sig/portable-key.test.mjs +253 -7
  87. package/dist/sig/proof.test.mjs +3 -3
  88. package/dist/{temporal-CbPfRGZq.mjs → temporal-oRKP803M.mjs} +1 -1
  89. package/dist/testing/kv.test.mjs +1 -1
  90. package/dist/utils/docloader.test.mjs +2 -2
  91. package/dist/utils/kv-cache.test.mjs +1 -1
  92. package/dist/utils/mod.cjs +1 -1
  93. package/dist/utils/mod.d.cts +1 -1
  94. package/dist/utils/mod.d.ts +1 -1
  95. package/dist/utils/mod.js +1 -1
  96. package/package.json +7 -7
@@ -1,4 +1,4 @@
1
- import "temporal-polyfill";
1
+ import { Temporal } from "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
4
  import { t as esm_default } from "../esm-BHXXx4Wx.mjs";
@@ -7,12 +7,14 @@ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
7
7
  import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
8
8
  import "../std__assert-DvMDRPes.mjs";
9
9
  import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
10
- import { p as signJsonLd } from "../ld-ya2C1Xip.mjs";
11
- import { l as signRequest } from "../http-DV_yW4dv.mjs";
12
- import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
13
- import { f as handleInbox, n as FederationImpl, o as createFederation } from "../middleware-Bdwd_Gg8.mjs";
10
+ import { r as getVerifiedKeyOwnerEvidence } from "../key-owner-evidence-Bo3yaeL5.mjs";
11
+ import { p as signJsonLd } from "../ld-BsTkRrwF.mjs";
12
+ import { d as verifyRequest, f as verifyRequestDetailed, l as signRequest } from "../http-Bd6rZlJX.mjs";
13
+ import { a as rsaPrivateKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
14
+ import { f as handleInbox, n as FederationImpl, o as createFederation } from "../middleware-Coqgp-K0.mjs";
15
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-D3GoetXS.mjs";
14
16
  import { t as ActivityListenerSet } from "../activity-listener-C-BSbKI7.mjs";
15
- import { t as KvKeyCache } from "../keycache-BInaECGj.mjs";
17
+ import { t as KvKeyCache } from "../keycache-PiOM9pM0.mjs";
16
18
  import { Create, CryptographicKey, Person } from "@fedify/vocab";
17
19
  import { mockDocumentLoader, test } from "@fedify/fixture";
18
20
  import { FetchError, encodeMultibase, exportDidKey, parseIri } from "@fedify/vocab-runtime";
@@ -508,5 +510,177 @@ test("handleInbox() checks the DIDs of compatible activity IDs", async () => {
508
510
  dispatched: 0
509
511
  });
510
512
  });
513
+ function countingLoader(responses) {
514
+ const inner = createLoader(responses);
515
+ let count = 0;
516
+ return {
517
+ documentLoader(url, options) {
518
+ if (url.replace(/#.*$/, "") === compatibleActorId(gateway)) count++;
519
+ return inner(url, options);
520
+ },
521
+ fetched: () => count
522
+ };
523
+ }
524
+ async function signedRequest(keyId = gatewayKeyId, privateKey = rsaPrivateKey2, spec) {
525
+ return await signRequest(new Request("https://local.example/notes/1", { headers: { Accept: "application/activity+json" } }), privateKey, keyId, spec == null ? {} : { spec });
526
+ }
527
+ test("handleInbox() fetches the actor of a gateway key once", async () => {
528
+ for (const [keyId, actor] of [[gatewayKeyId, await actorDocument([gateway])], [apKeyId, await apActorDocument()]]) {
529
+ const { documentLoader, fetched } = countingLoader({ [compatibleActorId(gateway)]: actor });
530
+ const kv = new MemoryKvStore();
531
+ for (let i = 0; i < 2; i++) {
532
+ assertEquals(await deliver(await createJson(`once-${i}`), [gateway], {
533
+ kv,
534
+ documentLoader,
535
+ keyId
536
+ }), {
537
+ status: 401,
538
+ dispatched: 0
539
+ });
540
+ assertEquals(fetched(), 1);
541
+ }
542
+ }
543
+ });
544
+ test("RequestContext.getSignedKeyOwner() does not fetch the actor of a gateway key again", async () => {
545
+ for (const [keyId, actor, gateways] of [[
546
+ gatewayKeyId,
547
+ await actorDocument([gateway, otherGateway]),
548
+ [`${gateway}/`, `${otherGateway}/`]
549
+ ], [
550
+ apKeyId,
551
+ await apActorDocument(),
552
+ [`${gateway}/`]
553
+ ]]) {
554
+ const { documentLoader, fetched } = countingLoader({ [compatibleActorId(gateway)]: actor });
555
+ const ctx = new FederationImpl({
556
+ kv: new MemoryKvStore(),
557
+ contextLoaderFactory: () => mockDocumentLoader,
558
+ documentLoaderFactory: () => documentLoader
559
+ }).createContext(await signedRequest(keyId), void 0);
560
+ assertEquals((await ctx.getSignedKey())?.id?.href, keyId.href);
561
+ assertEquals(fetched(), 1);
562
+ const owner = await ctx.getSignedKeyOwner();
563
+ assertEquals(owner?.id?.href, actorId.href);
564
+ assertEquals(owner?.gateways.map((g) => g.href), [...gateways]);
565
+ assertEquals(fetched(), 1);
566
+ }
567
+ });
568
+ test("getKeyOwner() reuses the actor of a cached gateway key", async () => {
569
+ for (const spec of [void 0, "rfc9421"]) {
570
+ const { documentLoader, fetched } = countingLoader({ [compatibleActorId(gateway)]: await actorDocument([gateway]) });
571
+ const options = {
572
+ documentLoader,
573
+ contextLoader: mockDocumentLoader,
574
+ keyCache: new KvKeyCache(new MemoryKvStore(), ["pk"])
575
+ };
576
+ const fresh = await verifyRequest(await signedRequest(gatewayKeyId, rsaPrivateKey2, spec), options);
577
+ const cached = await verifyRequest(await signedRequest(gatewayKeyId, rsaPrivateKey2, spec), options);
578
+ assertEquals(fetched(), 1);
579
+ for (const key of [fresh, cached]) assertEquals((await getKeyOwner(key, options))?.id?.href, actorId.href);
580
+ assertEquals(fetched(), 1);
581
+ }
582
+ });
583
+ test("doesActorOwnKey() checks the actor of a verified gateway key without fetching", async () => {
584
+ const { documentLoader, fetched } = countingLoader({ [compatibleActorId(gateway)]: await actorDocument([gateway]) });
585
+ const options = {
586
+ documentLoader,
587
+ contextLoader: mockDocumentLoader
588
+ };
589
+ const key = await verifyRequest(await signedRequest(), options);
590
+ assertEquals(fetched(), 1);
591
+ assertEquals(await doesActorOwnKey(portableCreate(), key, options), true);
592
+ assertEquals(await doesActorOwnKey(new Create({
593
+ id: parseIri(`ap+ef61://${otherDid}/activities/1`),
594
+ actor: parseIri(`ap+ef61://${otherDid}/actors/alice`)
595
+ }), key, options), false);
596
+ assertEquals(fetched(), 1);
597
+ });
598
+ test("doesActorOwnKey() and getKeyOwner() fully check other gateway keys", async () => {
599
+ const { documentLoader, fetched } = countingLoader({ [compatibleActorId(gateway)]: await actorDocument([gateway]) });
600
+ const options = {
601
+ documentLoader,
602
+ contextLoader: mockDocumentLoader
603
+ };
604
+ const verified = await verifyRequest(await signedRequest(), options);
605
+ assertEquals(fetched(), 1);
606
+ const others = [new CryptographicKey({
607
+ id: gatewayKeyId,
608
+ owner: actorId,
609
+ publicKey: rsaPublicKey2.publicKey
610
+ }), verified.clone({})];
611
+ let expected = 1;
612
+ for (const key of others) {
613
+ assertEquals(await doesActorOwnKey(portableCreate(), key, options), true);
614
+ assertEquals(fetched(), ++expected);
615
+ assertEquals((await getKeyOwner(key, options))?.id?.href, actorId.href);
616
+ assertEquals(fetched(), ++expected);
617
+ }
618
+ const mutated = await verifyRequest(await signedRequest(), options);
619
+ mutated.ownerId.href = parseIri(`ap+ef61://${otherDid}/actors/alice`).href;
620
+ assertEquals(getVerifiedKeyOwnerEvidence(mutated), void 0);
621
+ });
622
+ test("verifyRequest() does not vouch for the owners of keys that fail to verify signatures", async () => {
623
+ const documentLoader = createLoader({ [compatibleActorId(gateway)]: await actorDocument([gateway]) });
624
+ const cachedKeys = [];
625
+ const keyCache = new class extends KvKeyCache {
626
+ compatibleKeyScope(scope) {
627
+ const scoped = super.compatibleKeyScope(scope);
628
+ return {
629
+ ...scoped,
630
+ set(keyId, key, options) {
631
+ if (key instanceof CryptographicKey) cachedKeys.push(key);
632
+ return scoped.set(keyId, key, options);
633
+ }
634
+ };
635
+ }
636
+ }(new MemoryKvStore(), ["pk"]);
637
+ assertEquals((await verifyRequestDetailed(await signedRequest(gatewayKeyId, rsaPrivateKey3), {
638
+ documentLoader,
639
+ contextLoader: mockDocumentLoader,
640
+ keyCache
641
+ })).verified, false);
642
+ assertEquals(cachedKeys.length, 1);
643
+ assertEquals(getVerifiedKeyOwnerEvidence(cachedKeys[0]), void 0);
644
+ });
645
+ test("doesActorOwnKey() fully checks cached gateway keys cached without their actors", async () => {
646
+ const { documentLoader, fetched } = countingLoader({ [compatibleActorId(gateway)]: await actorDocument([gateway]) });
647
+ const kv = new MemoryKvStore();
648
+ const options = {
649
+ documentLoader,
650
+ contextLoader: mockDocumentLoader,
651
+ keyCache: new KvKeyCache(kv, ["pk"])
652
+ };
653
+ await verifyRequest(await signedRequest(), options);
654
+ assertEquals(fetched(), 1);
655
+ const entryKey = [
656
+ "pk",
657
+ "__compatible",
658
+ "httpSignature",
659
+ gatewayKeyId.href
660
+ ];
661
+ const { owner: _, ...entry } = await kv.get(entryKey) ?? {};
662
+ await kv.set(entryKey, entry);
663
+ const key = await verifyRequest(await signedRequest(), options);
664
+ assertEquals(fetched(), 1);
665
+ assertEquals(getVerifiedKeyOwnerEvidence(key), void 0);
666
+ assertEquals(await doesActorOwnKey(portableCreate(), key, options), true);
667
+ assertEquals(fetched(), 2);
668
+ });
669
+ test("Owners of verified gateway keys expire with their cache entries", async () => {
670
+ const documentLoader = createLoader({ [compatibleActorId(gateway)]: await actorDocument([gateway]) });
671
+ const now = Temporal.Now.instant();
672
+ const keyCache = new KvKeyCache(new MemoryKvStore(), ["pk"], {
673
+ keyTtl: Temporal.Duration.from({ minutes: 5 }),
674
+ now: () => now
675
+ });
676
+ const key = await verifyRequest(await signedRequest(), {
677
+ documentLoader,
678
+ contextLoader: mockDocumentLoader,
679
+ keyCache
680
+ });
681
+ const deadline = now.add({ minutes: 5 });
682
+ assertEquals(getVerifiedKeyOwnerEvidence(key, deadline.subtract({ seconds: 1 }))?.expires, deadline);
683
+ assertEquals(getVerifiedKeyOwnerEvidence(key, deadline), void 0);
684
+ });
511
685
  //#endregion
512
686
  export {};
@@ -8,11 +8,11 @@ import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
8
8
  import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
9
9
  import "../std__assert-DvMDRPes.mjs";
10
10
  import { t as assert } from "../assert-D1Eafmd_.mjs";
11
- import { p as signJsonLd } from "../ld-ya2C1Xip.mjs";
12
- import { a as signObject } from "../proof-BdO3BbLh.mjs";
13
- import { f as verifyRequestDetailed, l as signRequest } from "../http-DV_yW4dv.mjs";
11
+ import { p as signJsonLd } from "../ld-BsTkRrwF.mjs";
12
+ import { a as signObject } from "../proof-CQAYqWdj.mjs";
13
+ import { f as verifyRequestDetailed, l as signRequest } from "../http-Bd6rZlJX.mjs";
14
14
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
15
- import { _ as coversDelivery, o as createFederation, v as forwardPortableInboxActivity, y as resolvePortableInboxForwardingOptions } from "../middleware-Bdwd_Gg8.mjs";
15
+ import { _ as coversDelivery, o as createFederation, v as forwardPortableInboxActivity, y as resolvePortableInboxForwardingOptions } from "../middleware-Coqgp-K0.mjs";
16
16
  import { Create, CryptographicKey, Follow, Note, Person, Tombstone } from "@fedify/vocab";
17
17
  import { mockDocumentLoader, test } from "@fedify/fixture";
18
18
  import { exportDidKey, formatIri, parseIri } from "@fedify/vocab-runtime";
@@ -7,7 +7,7 @@ import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
7
7
  import "../std__assert-DvMDRPes.mjs";
8
8
  import { t as assert } from "../assert-D1Eafmd_.mjs";
9
9
  import { r as ed25519PublicKey } from "../keys-DIJNHW-Y.mjs";
10
- import { o as createFederation } from "../middleware-Bdwd_Gg8.mjs";
10
+ import { o as createFederation } from "../middleware-Coqgp-K0.mjs";
11
11
  import { Note, Object as Object$1, Person } from "@fedify/vocab";
12
12
  import { test } from "@fedify/fixture";
13
13
  import { exportDidKey, parseIri } from "@fedify/vocab-runtime";
@@ -8,10 +8,10 @@ import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
8
8
  import "../std__assert-DvMDRPes.mjs";
9
9
  import { t as assertStrictEquals } from "../assert_strict_equals-CYvBmkpC.mjs";
10
10
  import { t as assert } from "../assert-D1Eafmd_.mjs";
11
- import { a as signObject, c as verifyPortableObjectProof } from "../proof-BdO3BbLh.mjs";
12
- import { l as signRequest } from "../http-DV_yW4dv.mjs";
11
+ import { a as signObject, c as verifyPortableObjectProof } from "../proof-CQAYqWdj.mjs";
12
+ import { l as signRequest } from "../http-Bd6rZlJX.mjs";
13
13
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
14
- import { b as PORTABLE_OBJECT_CONTENT_TYPE, o as createFederation } from "../middleware-Bdwd_Gg8.mjs";
14
+ import { b as PORTABLE_OBJECT_CONTENT_TYPE, o as createFederation } from "../middleware-Coqgp-K0.mjs";
15
15
  import { configure, reset } from "@logtape/logtape";
16
16
  import { Collection, Create, Note, Object as Object$1, Person, Tombstone, lookupObject } from "@fedify/vocab";
17
17
  import { mockDocumentLoader, test } from "@fedify/fixture";
@@ -10,10 +10,10 @@ import { t as assertNotEquals } from "../assert_not_equals-CpPK2t89.mjs";
10
10
  import "../std__assert-DvMDRPes.mjs";
11
11
  import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
12
12
  import { t as assert } from "../assert-D1Eafmd_.mjs";
13
- import { d as verifyRequest } from "../http-DV_yW4dv.mjs";
13
+ import { d as verifyRequest } from "../http-Bd6rZlJX.mjs";
14
14
  import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
15
- import { t as doesActorOwnKey } from "../owner-C6Nv5yyw.mjs";
16
- import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-BwANxryy.mjs";
15
+ import { t as doesActorOwnKey } from "../owner-D3GoetXS.mjs";
16
+ import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-DjkQrxt5.mjs";
17
17
  import { Activity, Application, Endpoints, Group, Person, Service } from "@fedify/vocab";
18
18
  import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
19
19
  import { FetchError, UrlError } from "@fedify/vocab-runtime";
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
4
4
  import { t as MemoryKvStore } from "../../kv-DCHkaJ9-.mjs";
5
5
  import { a as numberSchema, i as makeSchema, n as baseOptions, o as stringSchema, t as MockQueue } from "../../tasks-IG3pHfvZ.mjs";
6
6
  import "../../testing-C1itIjqW.mjs";
7
- import { o as createFederation } from "../../middleware-Bdwd_Gg8.mjs";
7
+ import { o as createFederation } from "../../middleware-Coqgp-K0.mjs";
8
8
  import { n as ParallelMessageQueue } from "../../mq-Dm1Wmtm-.mjs";
9
9
  import { configure, reset } from "@logtape/logtape";
10
10
  import { delay } from "es-toolkit";
@@ -4,8 +4,8 @@ globalThis.addEventListener = () => {};
4
4
  import { t as MemoryKvStore } from "../../kv-DCHkaJ9-.mjs";
5
5
  import { a as numberSchema, i as makeSchema, n as baseOptions, o as stringSchema, t as MockQueue } from "../../tasks-IG3pHfvZ.mjs";
6
6
  import "../../testing-C1itIjqW.mjs";
7
- import { o as createFederation } from "../../middleware-Bdwd_Gg8.mjs";
8
- import { r as createFederationBuilder } from "../../builder-D89oOfHC.mjs";
7
+ import { o as createFederation } from "../../middleware-Coqgp-K0.mjs";
8
+ import { r as createFederationBuilder } from "../../builder-B2d_Pt0j.mjs";
9
9
  import { t as TaskCodec } from "../../codec-C6rTrpIp.mjs";
10
10
  import { t as InProcessMessageQueue } from "../../mq-Dm1Wmtm-.mjs";
11
11
  import { W3CTraceContextPropagator } from "@opentelemetry/core";
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
4
4
  import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
5
5
  import "../std__assert-DvMDRPes.mjs";
6
6
  import { t as assert } from "../assert-D1Eafmd_.mjs";
7
- import { t as hasMalformedKnownTemporalLiteral } from "../temporal-CbPfRGZq.mjs";
7
+ import { t as hasMalformedKnownTemporalLiteral } from "../temporal-oRKP803M.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 () => {
@@ -6,7 +6,7 @@ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
6
6
  import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
7
7
  import { t as assertNotEquals } from "../assert_not_equals-CpPK2t89.mjs";
8
8
  import "../std__assert-DvMDRPes.mjs";
9
- import { o as createFederation, s as handleWebFinger } from "../middleware-Bdwd_Gg8.mjs";
9
+ import { o as createFederation, s as handleWebFinger } from "../middleware-Coqgp-K0.mjs";
10
10
  import { Image, Link, Person, Tombstone } from "@fedify/vocab";
11
11
  import { createTestMeterProvider, test } from "@fedify/fixture";
12
12
  import { parseIri } from "@fedify/vocab-runtime";
@@ -1,10 +1,10 @@
1
1
  const { URLPattern } = require("urlpattern-polyfill");
2
2
  const require_rolldown_runtime = require("./rolldown-runtime-Dmm3t92W.cjs");
3
3
  const require_transformers = require("./transformers-BalCrSsr.cjs");
4
- const require_http = require("./http-wdsia0-O.cjs");
4
+ const require_http = require("./http-5CJBdU8n.cjs");
5
5
  const require_types = require("./types-poIao40f.cjs");
6
- const require_portable_collection = require("./portable-collection-C65SwL2l.cjs");
7
- const require_kv_cache = require("./kv-cache-BHNtQi9e.cjs");
6
+ const require_portable_collection = require("./portable-collection-CnlCamup.cjs");
7
+ const require_kv_cache = require("./kv-cache-YRi_g8GB.cjs");
8
8
  let _logtape_logtape = require("@logtape/logtape");
9
9
  let _fedify_uri_template = require("@fedify/uri-template");
10
10
  let _fedify_vocab = require("@fedify/vocab");
@@ -2497,10 +2497,13 @@ async function routeActivity({ context: ctx, json, originalJson, normalizedActiv
2497
2497
  const Temporal$9 = require_http.Temporal;
2498
2498
  const KEY_CACHE_GENERATION = "2";
2499
2499
  const COMPATIBLE_KEY_SEGMENT = "__compatible";
2500
- const MAX_COMPATIBLE_KEY_TTL = Temporal$9.Duration.from({ hours: 1 });
2500
+ const MAX_OWNER_BYTES = 32 * 1024;
2501
2501
  function isCompatibleKeyEntry(value) {
2502
2502
  return value != null && typeof value === "object" && "key" in value && "expires" in value && typeof value.expires === "number";
2503
2503
  }
2504
+ function isJsonObject(value) {
2505
+ return value != null && typeof value === "object" && !Array.isArray(value);
2506
+ }
2504
2507
  var KvKeyCache = class {
2505
2508
  kv;
2506
2509
  prefix;
@@ -2582,30 +2585,48 @@ var KvKeyCache = class {
2582
2585
  keyId.href
2583
2586
  ];
2584
2587
  const isExpired = (entry) => entry.expires <= now().epochMilliseconds;
2585
- const keyTtl = Math.min(this.keyTtl.total("millisecond"), MAX_COMPATIBLE_KEY_TTL.total("millisecond"));
2588
+ const keyTtl = Math.min(this.keyTtl.total("millisecond"), require_http.MAX_PORTABLE_KEY_TTL.total("millisecond"));
2586
2589
  const unavailableKeyTtl = this.unavailableKeyTtl.total("millisecond");
2587
- return {
2588
- get: async (keyId) => {
2589
- const entry = await this.kv.get(entryKey(keyId));
2590
- if (entry === void 0) return void 0;
2591
- if (!isCompatibleKeyEntry(entry) || isExpired(entry)) {
2592
- await this.kv.delete(entryKey(keyId));
2593
- return;
2594
- }
2595
- if (entry.key === null) return null;
2596
- let key;
2590
+ const getEntry = async (keyId) => {
2591
+ const entry = await this.kv.get(entryKey(keyId));
2592
+ if (entry === void 0) return void 0;
2593
+ if (!isCompatibleKeyEntry(entry) || isExpired(entry)) {
2594
+ await this.kv.delete(entryKey(keyId));
2595
+ return;
2596
+ }
2597
+ if (entry.key === null) return null;
2598
+ let expires;
2599
+ try {
2600
+ expires = Temporal$9.Instant.fromEpochMilliseconds(entry.expires);
2601
+ } catch (error) {
2602
+ if (!(error instanceof RangeError)) throw error;
2603
+ await this.kv.delete(entryKey(keyId));
2604
+ return;
2605
+ }
2606
+ let key;
2607
+ try {
2608
+ key = await _fedify_vocab.CryptographicKey.fromJsonLd(entry.key, this.options);
2609
+ } catch {
2597
2610
  try {
2598
- key = await _fedify_vocab.CryptographicKey.fromJsonLd(entry.key, this.options);
2611
+ key = await _fedify_vocab.Multikey.fromJsonLd(entry.key, this.options);
2599
2612
  } catch {
2600
- try {
2601
- key = await _fedify_vocab.Multikey.fromJsonLd(entry.key, this.options);
2602
- } catch {
2603
- await this.kv.delete(entryKey(keyId));
2604
- return;
2605
- }
2613
+ await this.kv.delete(entryKey(keyId));
2614
+ return;
2606
2615
  }
2607
- return isExpired(entry) ? void 0 : key;
2616
+ }
2617
+ if (isExpired(entry)) return void 0;
2618
+ return {
2619
+ key,
2620
+ ...isJsonObject(entry.owner) ? { owner: entry.owner } : {},
2621
+ expires
2622
+ };
2623
+ };
2624
+ return {
2625
+ get: async (keyId) => {
2626
+ const entry = await getEntry(keyId);
2627
+ return entry == null ? entry : entry.key;
2608
2628
  },
2629
+ getEntry,
2609
2630
  set: async (keyId, key, options) => {
2610
2631
  const serialized = key == null ? null : await key.toJsonLd(this.options);
2611
2632
  const current = now();
@@ -2616,10 +2637,13 @@ var KvKeyCache = class {
2616
2637
  await this.kv.delete(entryKey(keyId));
2617
2638
  return;
2618
2639
  }
2640
+ const owner = key == null || options?.owner == null || new TextEncoder().encode(JSON.stringify(options.owner)).length > MAX_OWNER_BYTES ? void 0 : options.owner;
2619
2641
  await this.kv.set(entryKey(keyId), {
2620
2642
  key: serialized,
2621
- expires
2643
+ expires,
2644
+ ...owner == null ? {} : { owner }
2622
2645
  }, { ttl: Temporal$9.Duration.from({ milliseconds: ttl }) });
2646
+ return key == null ? void 0 : Temporal$9.Instant.fromEpochMilliseconds(expires);
2623
2647
  },
2624
2648
  delete: async (keyId) => {
2625
2649
  await this.kv.delete(entryKey(keyId));