@fedify/fedify 2.4.0-dev.2084 → 2.4.0-dev.2093

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 (75) hide show
  1. package/dist/{builder-BGlpUocK.mjs → builder-Ld4Y9ymR.mjs} +34 -3
  2. package/dist/compat/transformers.test.mjs +1 -1
  3. package/dist/{compound-proof-B6Aj2kGY.mjs → compound-proof-CTx_lewQ.mjs} +191 -13
  4. package/dist/{deno-Dn-py9Zy.mjs → deno-8t8k_6Yv.mjs} +1 -1
  5. package/dist/{docloader-BUq5bYJr.mjs → docloader-DJKcsAiF.mjs} +2 -2
  6. package/dist/federation/builder.test.mjs +1 -1
  7. package/dist/federation/compound-fanout.test.mjs +3 -3
  8. package/dist/federation/handler-compound-proof.test.mjs +3 -3
  9. package/dist/federation/handler.test.mjs +5 -5
  10. package/dist/federation/hashlink-media.test.mjs +2 -2
  11. package/dist/federation/idempotency.test.mjs +2 -2
  12. package/dist/federation/metrics.test.mjs +1 -1
  13. package/dist/federation/middleware.test.mjs +7 -7
  14. package/dist/federation/mod.cjs +1 -1
  15. package/dist/federation/mod.js +1 -1
  16. package/dist/federation/outgoing-proof.test.mjs +254 -5
  17. package/dist/federation/portable-gateway-keys.test.mjs +72 -11
  18. package/dist/federation/portable-inbox.test.mjs +116 -4
  19. package/dist/federation/portable.test.mjs +182 -4
  20. package/dist/federation/send.test.mjs +3 -3
  21. package/dist/federation/tasks/enqueue.test.mjs +1 -1
  22. package/dist/federation/tasks/tasks.test.mjs +2 -2
  23. package/dist/federation/temporal.test.mjs +1 -1
  24. package/dist/federation/webfinger.test.mjs +89 -1
  25. package/dist/{federation-BLGx8JUH.cjs → federation-aSHO04ob.cjs} +360 -65
  26. package/dist/{http-B0VRNipE.mjs → http-B2ftY0Ha.mjs} +4 -4
  27. package/dist/{http-B5q1CHtL.cjs → http-DSaSAN7X.cjs} +1609 -1457
  28. package/dist/{http-4PCCvhsU.js → http-DyT7DP1Y.js} +1518 -1390
  29. package/dist/{key-BJrp524f.mjs → key-Dwm4VswT.mjs} +39 -99
  30. package/dist/{kv-cache-Dhhhrryv.cjs → kv-cache-BSJAlP4C.cjs} +1 -1
  31. package/dist/{kv-cache-C4C3LyYW.mjs → kv-cache-D0yYukqk.mjs} +1 -1
  32. package/dist/{kv-cache-1KUmAPH7.js → kv-cache-DmroAz3M.js} +1 -1
  33. package/dist/{ld-BmFz5NLA.mjs → ld-BYZOoDzZ.mjs} +3 -3
  34. package/dist/{metrics-Beod6tzO.mjs → metrics-B7YwKTFr.mjs} +1 -1
  35. package/dist/{middleware-B7CNsyqt.mjs → middleware-BNeqKSsL.mjs} +1 -1
  36. package/dist/{middleware-D_9pNYe9.js → middleware-Blq0882d.js} +368 -73
  37. package/dist/{middleware-BKeQYPm0.mjs → middleware-E_0IH72m.mjs} +166 -71
  38. package/dist/{mod-HDSvS-ww.d.cts → mod-C8LieBzF.d.cts} +16 -3
  39. package/dist/{mod-C9WSpZWm.d.ts → mod-Coacostr.d.ts} +16 -3
  40. package/dist/mod.cjs +5 -5
  41. package/dist/mod.d.cts +1 -1
  42. package/dist/mod.d.ts +1 -1
  43. package/dist/mod.js +5 -5
  44. package/dist/nodeinfo/handler.test.mjs +1 -1
  45. package/dist/{owner-CsKVgMzk.mjs → owner-Cgx2Dc7I.mjs} +5 -4
  46. package/dist/{owner-_pbbgLJK.js → owner-DAGSC5gX.js} +2 -2
  47. package/dist/{owner-BQFZtFV4.cjs → owner-szIZl4qI.cjs} +2 -2
  48. package/dist/{portable-key-B4R-CiIV.mjs → portable-key-Cn1WJSN1.mjs} +60 -41
  49. package/dist/portable-key-id-Bva5iT3W.mjs +136 -0
  50. package/dist/{proof-ozG4HfcQ.mjs → proof-DVXC6nYz.mjs} +59 -18
  51. package/dist/{send-ClPt8nYu.mjs → send-D-hOvYKy.mjs} +3 -3
  52. package/dist/sig/compound-proof-discovery.test.mjs +1 -1
  53. package/dist/sig/compound-proof-producer.test.mjs +1 -1
  54. package/dist/sig/compound-proof-verification.test.mjs +160 -3
  55. package/dist/sig/compound-proof.test.mjs +2 -2
  56. package/dist/sig/http.test.mjs +2 -2
  57. package/dist/sig/key.test.mjs +1 -1
  58. package/dist/sig/ld.test.mjs +2 -2
  59. package/dist/sig/mod.cjs +3 -3
  60. package/dist/sig/mod.d.cts +1 -1
  61. package/dist/sig/mod.d.ts +1 -1
  62. package/dist/sig/mod.js +3 -3
  63. package/dist/sig/owner.test.mjs +1 -1
  64. package/dist/sig/portable-collection.test.mjs +69 -5
  65. package/dist/sig/portable-key.test.mjs +176 -10
  66. package/dist/sig/proof.test.mjs +107 -4
  67. package/dist/{sig-DhdomAN0.js → sig-B5Ell7pO.js} +19 -3
  68. package/dist/{sig-k3C8sF7g.cjs → sig-CXOKN4Br.cjs} +19 -3
  69. package/dist/{temporal-Ba0EAZAI.mjs → temporal-CqpKGEPk.mjs} +1 -1
  70. package/dist/testing/kv.test.mjs +1 -1
  71. package/dist/utils/docloader.test.mjs +2 -2
  72. package/dist/utils/kv-cache.test.mjs +1 -1
  73. package/dist/utils/mod.cjs +1 -1
  74. package/dist/utils/mod.js +1 -1
  75. package/package.json +7 -7
@@ -4,12 +4,14 @@ globalThis.addEventListener = () => {};
4
4
  import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
5
5
  import "../std__assert-DvMDRPes.mjs";
6
6
  import { t as assert } from "../assert-D1Eafmd_.mjs";
7
- import { i as verifyMapLocalProof, s as verifyPortableObjectProofPolicy } from "../proof-ozG4HfcQ.mjs";
8
- import { a as verifyCompoundPortableObjectProofs, o as verifyCompoundProofDocuments } from "../compound-proof-B6Aj2kGY.mjs";
7
+ import { a as verifyMapLocalProof, c as verifyPortableObjectProofPolicy } from "../proof-DVXC6nYz.mjs";
8
+ import { n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
9
+ import { a as verifyCompoundPortableObjectProofs, i as inspectCompoundPortableObjectApplicability, o as verifyCompoundProofDocuments, t as containsCompoundPortableObject } from "../compound-proof-CTx_lewQ.mjs";
9
10
  import { t as map_local_create_note_default } from "../map-local-create-note-B0SeXJms.mjs";
10
11
  import { t as map_local_context_conflict_default } from "../map-local-context-conflict-DOYEEJ3u.mjs";
12
+ import { CryptographicKey, Multikey, Person } from "@fedify/vocab";
11
13
  import { mockDocumentLoader, test } from "@fedify/fixture";
12
- import { encodeMultibase } from "@fedify/vocab-runtime";
14
+ import { encodeMultibase, exportDidKey, parseIri } from "@fedify/vocab-runtime";
13
15
  import serialize from "json-canon";
14
16
  //#region src/sig/compound-proof-verification.test.ts
15
17
  const limits = {
@@ -461,5 +463,160 @@ test("verifyCompoundPortableObjectProofs() reports the policy-validated ID", asy
461
463
  assertEquals(result.portableObjects.length, 1);
462
464
  assertEquals(result.portableObjects[0].id, map_local_create_note_default.documents.innerUnsecuredDocument.id);
463
465
  });
466
+ const compatibleDid = await exportDidKey(ed25519PublicKey.publicKey);
467
+ const compatibleVerificationMethod = `${compatibleDid}#${compatibleDid.slice(8)}`;
468
+ const compatibleActorId = `https://gw.example/.well-known/apgateway/${compatibleDid}/actor`;
469
+ const compatibleContext = ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/data-integrity/v1"];
470
+ async function signCompatible(document) {
471
+ return await secureRawDocument(document, await crypto.subtle.exportKey("jwk", ed25519PrivateKey), compatibleVerificationMethod);
472
+ }
473
+ async function compatibleActor(id = compatibleActorId, keyBase = compatibleActorId) {
474
+ const actorId = parseIri(id);
475
+ return await new Person({
476
+ id: actorId,
477
+ inbox: new URL(`${keyBase}/inbox`),
478
+ outbox: new URL(`${keyBase}/outbox`),
479
+ gateways: [new URL("https://gw.example")],
480
+ publicKey: new CryptographicKey({
481
+ id: new URL(`${keyBase}#main-key`),
482
+ owner: actorId,
483
+ publicKey: rsaPublicKey2.publicKey
484
+ }),
485
+ assertionMethods: [new Multikey({
486
+ id: new URL(`${keyBase}#ed25519-key`),
487
+ controller: actorId,
488
+ publicKey: ed25519PublicKey.publicKey
489
+ })]
490
+ }).toJsonLd({
491
+ format: "compact",
492
+ contextLoader: mockDocumentLoader
493
+ });
494
+ }
495
+ test("verifyCompoundPortableObjectProofs() treats compatible-ID maps as portable", async () => {
496
+ const note = {
497
+ "@context": [...compatibleContext],
498
+ id: `${compatibleActorId}/notes/1`,
499
+ type: "Note",
500
+ attributedTo: compatibleActorId,
501
+ content: "Hello"
502
+ };
503
+ const ordinary = {
504
+ "@context": [...compatibleContext],
505
+ id: "https://social.example/activities/1",
506
+ type: "Announce",
507
+ actor: "https://social.example/users/bob",
508
+ object: note
509
+ };
510
+ assertEquals(inspectCompoundPortableObjectApplicability(ordinary, limits), "present");
511
+ assert(containsCompoundPortableObject(ordinary));
512
+ const result = await verifyCompoundPortableObjectProofs(ordinary, limits, options);
513
+ assert(result.status === "ok");
514
+ assertEquals(result.verified, false);
515
+ assertEquals(result.portableObjects.map((o) => [o.path, o.verified]), [["/object", false]]);
516
+ const signed = await verifyCompoundPortableObjectProofs({
517
+ ...ordinary,
518
+ object: await signCompatible(note)
519
+ }, limits, options);
520
+ assert(signed.status === "ok");
521
+ assert(signed.verified);
522
+ });
523
+ test("verifyCompoundPortableObjectProofs() checks compatible activity IDs", async () => {
524
+ const create = (did) => ({
525
+ "@context": [...compatibleContext],
526
+ id: `https://gw.example/.well-known/apgateway/${did}/activities/1`,
527
+ type: "Create",
528
+ actor: compatibleActorId,
529
+ object: "https://social.example/notes/1"
530
+ });
531
+ const own = await verifyCompoundPortableObjectProofs(await signCompatible(create(compatibleDid)), limits, options);
532
+ assert(own.status === "ok");
533
+ assert(own.verified);
534
+ const forged = await verifyCompoundPortableObjectProofs(await signCompatible(create("did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK")), limits, options);
535
+ assert(forged.status === "ok");
536
+ assertEquals(forged.verified, false);
537
+ const [object] = forged.portableObjects;
538
+ assert(!object.verified);
539
+ assertEquals(object.reason.type, "verificationMethodMismatch");
540
+ });
541
+ test("verifyCompoundPortableObjectProofs() exempts keys embedded in portable actors", async () => {
542
+ let result = await verifyCompoundPortableObjectProofs(await signCompatible(await compatibleActor()), limits, options);
543
+ assert(result.status === "ok");
544
+ assert(result.verified);
545
+ assertEquals(result.portableObjects.map((o) => o.path), [""]);
546
+ result = await verifyCompoundPortableObjectProofs(await signCompatible(await compatibleActor(`ap://${compatibleDid}/actor`)), limits, options);
547
+ assert(result.status === "ok");
548
+ assert(result.verified);
549
+ result = await verifyCompoundPortableObjectProofs({
550
+ "@context": [...compatibleContext],
551
+ id: "https://social.example/activities/2",
552
+ type: "Update",
553
+ actor: "https://social.example/users/bob",
554
+ object: await signCompatible(await compatibleActor())
555
+ }, limits, options);
556
+ assert(result.status === "ok");
557
+ assert(result.verified);
558
+ });
559
+ test("verifyCompoundPortableObjectProofs() exempts only keys of the parent itself", async () => {
560
+ const actor = await compatibleActor();
561
+ const otherActorId = "https://gw.example/.well-known/apgateway/did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK/actor";
562
+ const publicKey = actor.publicKey;
563
+ const cases = {
564
+ "a key of another actor": {
565
+ ...actor,
566
+ publicKey: {
567
+ ...publicKey,
568
+ id: `${otherActorId}#main-key`,
569
+ owner: otherActorId
570
+ }
571
+ },
572
+ "a key owned by another actor": {
573
+ ...actor,
574
+ publicKey: {
575
+ ...publicKey,
576
+ owner: otherActorId
577
+ }
578
+ },
579
+ "a non-key object": {
580
+ ...actor,
581
+ publicKey: {
582
+ id: `${compatibleActorId}#note`,
583
+ type: "Note",
584
+ content: "Not a key"
585
+ }
586
+ },
587
+ "a key with extra content": {
588
+ ...actor,
589
+ publicKey: {
590
+ ...publicKey,
591
+ name: "Extra"
592
+ }
593
+ },
594
+ "a key under another property": {
595
+ ...actor,
596
+ attachment: structuredClone(publicKey)
597
+ },
598
+ "a parent context with a keyword alias": {
599
+ ...actor,
600
+ "@context": [...actor["@context"], { kind: "@type" }]
601
+ },
602
+ "a key with a scoped context": {
603
+ ...actor,
604
+ publicKey: {
605
+ ...publicKey,
606
+ "@context": { CryptographicKey: {
607
+ "@id": "https://w3id.org/security#Key",
608
+ "@context": {}
609
+ } }
610
+ }
611
+ }
612
+ };
613
+ for (const [name, document] of Object.entries(cases)) {
614
+ const result = await verifyCompoundPortableObjectProofs(await signCompatible(document), limits, options);
615
+ assert(result.status === "ok", name);
616
+ assertEquals(result.verified, false, name);
617
+ assert(result.portableObjects.find((o) => o.path === "")?.verified, name);
618
+ assert(result.portableObjects.some((o) => o.path !== "" && !o.verified), name);
619
+ }
620
+ });
464
621
  //#endregion
465
622
  export {};
@@ -6,9 +6,9 @@ import "../std__assert-DvMDRPes.mjs";
6
6
  import { t as assert } from "../assert-D1Eafmd_.mjs";
7
7
  import { n as preloadedOnlyDocumentLoader } from "../public-audience--klBIOk1.mjs";
8
8
  import { r as normalizeOutgoingActivityJsonLd } from "../outgoing-jsonld-4IJqPYos.mjs";
9
- import { l as verifyProof, r as signObject } from "../proof-ozG4HfcQ.mjs";
9
+ import { i as signObject, u as verifyProof } from "../proof-DVXC6nYz.mjs";
10
10
  import { n as ed25519PrivateKey, r as ed25519PublicKey } from "../keys-DIJNHW-Y.mjs";
11
- import { o as verifyCompoundProofDocuments } from "../compound-proof-B6Aj2kGY.mjs";
11
+ import { o as verifyCompoundProofDocuments } from "../compound-proof-CTx_lewQ.mjs";
12
12
  import { t as map_local_create_note_default } from "../map-local-create-note-B0SeXJms.mjs";
13
13
  import { t as map_local_context_conflict_default } from "../map-local-context-conflict-DOYEEJ3u.mjs";
14
14
  import { Create, DataIntegrityProof, Note, Question } from "@fedify/vocab";
@@ -11,8 +11,8 @@ import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
11
11
  import "../std__assert-DvMDRPes.mjs";
12
12
  import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
13
13
  import { t as assert } from "../assert-D1Eafmd_.mjs";
14
- import { t as exportJwk } from "../key-BJrp524f.mjs";
15
- 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-B0VRNipE.mjs";
14
+ import { t as exportJwk } from "../key-Dwm4VswT.mjs";
15
+ 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-B2ftY0Ha.mjs";
16
16
  import { i as rsaPrivateKey2, l as rsaPublicKey5, o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
17
17
  import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
18
18
  import { FetchError, exportSpki } from "@fedify/vocab-runtime";
@@ -6,7 +6,7 @@ import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
6
6
  import "../std__assert-DvMDRPes.mjs";
7
7
  import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
8
8
  import { t as assert } from "../assert-D1Eafmd_.mjs";
9
- import { a as generateCryptoKeyPair, i as fetchKeyDetailed, o as importJwk, r as fetchKey, s as validateCryptoKey, t as exportJwk } from "../key-BJrp524f.mjs";
9
+ import { a as generateCryptoKeyPair, i as fetchKeyDetailed, o as importJwk, r as fetchKey, s as validateCryptoKey, t as exportJwk } from "../key-Dwm4VswT.mjs";
10
10
  import { c as rsaPublicKey3, i as rsaPrivateKey2, o as rsaPublicKey1, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
11
11
  import { CryptographicKey, Multikey } from "@fedify/vocab";
12
12
  import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
@@ -8,8 +8,8 @@ import { t as assertInstanceOf } from "../assert_instance_of-mrXWWNY-.mjs";
8
8
  import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
9
9
  import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
10
10
  import { t as assert } from "../assert-D1Eafmd_.mjs";
11
- import { a as generateCryptoKeyPair } from "../key-BJrp524f.mjs";
12
- import { a as compactJsonLd, f as isInvalidUrlTypeError, g as verifySignature, h as verifyJsonLd, i as attachSignature, n as UnsafeJsonLdError, o as createSignature, p as signJsonLd, s as detachSignature, u as hasSignatureLike } from "../ld-BmFz5NLA.mjs";
11
+ import { a as generateCryptoKeyPair } from "../key-Dwm4VswT.mjs";
12
+ import { a as compactJsonLd, f as isInvalidUrlTypeError, g as verifySignature, h as verifyJsonLd, i as attachSignature, n as UnsafeJsonLdError, o as createSignature, p as signJsonLd, s as detachSignature, u as hasSignatureLike } from "../ld-BYZOoDzZ.mjs";
13
13
  import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
14
14
  import { CryptographicKey } from "@fedify/vocab";
15
15
  import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
package/dist/sig/mod.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  const { URLPattern } = require("urlpattern-polyfill");
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_http = require("../http-B5q1CHtL.cjs");
4
- const require_owner = require("../owner-BQFZtFV4.cjs");
5
- const require_sig = require("../sig-k3C8sF7g.cjs");
3
+ const require_http = require("../http-DSaSAN7X.cjs");
4
+ const require_owner = require("../owner-szIZl4qI.cjs");
5
+ const require_sig = require("../sig-CXOKN4Br.cjs");
6
6
  exports.attachSignature = require_http.attachSignature;
7
7
  exports.createProof = require_http.createProof;
8
8
  exports.createSignature = require_http.createSignature;
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
2
  import { C as exportJwk, D as importJwk, E as generateCryptoKeyPair, S as KeyCache, T as fetchKeyDetailed, _ as validateAcceptSignature, a as VerifyRequestDetailedResult, b as FetchKeyOptions, c as signRequest, d as AcceptSignatureMember, f as AcceptSignatureParameters, g as parseAcceptSignature, h as fulfillAcceptSignature, i as SignRequestOptions, l as verifyRequest, m as formatAcceptSignature, n as HttpMessageSignaturesSpecDeterminer, o as VerifyRequestFailureReason, p as FulfillAcceptSignatureResult, r as Rfc9421SignRequestOptions, s as VerifyRequestOptions, t as HttpMessageSignaturesSpec, u as verifyRequestDetailed, v as FetchKeyDetailedResult, w as fetchKey, x as FetchKeyResult, y as FetchKeyErrorResult } from "../http-xlG-jRdB.cjs";
3
3
  import { i as getKeyOwner, n as GetKeyOwnerOptions, r as doesActorOwnKey, t as DoesActorOwnKeyOptions } from "../owner-BF0L9cMt.cjs";
4
- import { C as createSignature, D as verifyJsonLd, E as signJsonLd, O as verifySignature, S as attachSignature, T as hasSignatureLike, _ as verifyProof, a as CreateProofOptions, b as VerifyJsonLdOptions, c as VerifyPortableObjectProofFailureReason, d as VerifyProofOptions, f as createProof, g as verifyPortableObjectProof, h as verifyObject, i as verifyPortableObject, l as VerifyPortableObjectProofOptions, m as signObject, n as VerifyPortableObjectOptions, o as SignObjectOptions, p as hasProofLike, r as VerifyPortableObjectResult, s as VerifyObjectOptions, t as VerifyPortableObjectFailureReason, u as VerifyPortableObjectProofResult, v as CreateSignatureOptions, w as detachSignature, x as VerifySignatureOptions, y as SignJsonLdOptions } from "../mod-HDSvS-ww.cjs";
4
+ import { C as createSignature, D as verifyJsonLd, E as signJsonLd, O as verifySignature, S as attachSignature, T as hasSignatureLike, _ as verifyProof, a as CreateProofOptions, b as VerifyJsonLdOptions, c as VerifyPortableObjectProofFailureReason, d as VerifyProofOptions, f as createProof, g as verifyPortableObjectProof, h as verifyObject, i as verifyPortableObject, l as VerifyPortableObjectProofOptions, m as signObject, n as VerifyPortableObjectOptions, o as SignObjectOptions, p as hasProofLike, r as VerifyPortableObjectResult, s as VerifyObjectOptions, t as VerifyPortableObjectFailureReason, u as VerifyPortableObjectProofResult, v as CreateSignatureOptions, w as detachSignature, x as VerifySignatureOptions, y as SignJsonLdOptions } from "../mod-C8LieBzF.cjs";
5
5
  export { AcceptSignatureMember, AcceptSignatureParameters, CreateProofOptions, CreateSignatureOptions, DoesActorOwnKeyOptions, FetchKeyDetailedResult, FetchKeyErrorResult, FetchKeyOptions, FetchKeyResult, FulfillAcceptSignatureResult, GetKeyOwnerOptions, HttpMessageSignaturesSpec, HttpMessageSignaturesSpecDeterminer, KeyCache, Rfc9421SignRequestOptions, SignJsonLdOptions, SignObjectOptions, SignRequestOptions, VerifyJsonLdOptions, VerifyObjectOptions, VerifyPortableObjectFailureReason, VerifyPortableObjectOptions, VerifyPortableObjectProofFailureReason, VerifyPortableObjectProofOptions, VerifyPortableObjectProofResult, VerifyPortableObjectResult, VerifyProofOptions, VerifyRequestDetailedResult, VerifyRequestFailureReason, VerifyRequestOptions, VerifySignatureOptions, attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, fetchKeyDetailed, formatAcceptSignature, fulfillAcceptSignature, generateCryptoKeyPair, getKeyOwner, hasProofLike, hasSignatureLike, importJwk, parseAcceptSignature, signJsonLd, signObject, signRequest, validateAcceptSignature, verifyJsonLd, verifyObject, verifyPortableObject, verifyPortableObjectProof, verifyProof, verifyRequest, verifyRequestDetailed, verifySignature };
package/dist/sig/mod.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /// <reference lib="esnext.temporal" />
2
2
  import { C as exportJwk, D as importJwk, E as generateCryptoKeyPair, S as KeyCache, T as fetchKeyDetailed, _ as validateAcceptSignature, a as VerifyRequestDetailedResult, b as FetchKeyOptions, c as signRequest, d as AcceptSignatureMember, f as AcceptSignatureParameters, g as parseAcceptSignature, h as fulfillAcceptSignature, i as SignRequestOptions, l as verifyRequest, m as formatAcceptSignature, n as HttpMessageSignaturesSpecDeterminer, o as VerifyRequestFailureReason, p as FulfillAcceptSignatureResult, r as Rfc9421SignRequestOptions, s as VerifyRequestOptions, t as HttpMessageSignaturesSpec, u as verifyRequestDetailed, v as FetchKeyDetailedResult, w as fetchKey, x as FetchKeyResult, y as FetchKeyErrorResult } from "../http-n2v6DPxu.js";
3
3
  import { i as getKeyOwner, n as GetKeyOwnerOptions, r as doesActorOwnKey, t as DoesActorOwnKeyOptions } from "../owner-BSzr5-I8.js";
4
- import { C as createSignature, D as verifyJsonLd, E as signJsonLd, O as verifySignature, S as attachSignature, T as hasSignatureLike, _ as verifyProof, a as CreateProofOptions, b as VerifyJsonLdOptions, c as VerifyPortableObjectProofFailureReason, d as VerifyProofOptions, f as createProof, g as verifyPortableObjectProof, h as verifyObject, i as verifyPortableObject, l as VerifyPortableObjectProofOptions, m as signObject, n as VerifyPortableObjectOptions, o as SignObjectOptions, p as hasProofLike, r as VerifyPortableObjectResult, s as VerifyObjectOptions, t as VerifyPortableObjectFailureReason, u as VerifyPortableObjectProofResult, v as CreateSignatureOptions, w as detachSignature, x as VerifySignatureOptions, y as SignJsonLdOptions } from "../mod-C9WSpZWm.js";
4
+ import { C as createSignature, D as verifyJsonLd, E as signJsonLd, O as verifySignature, S as attachSignature, T as hasSignatureLike, _ as verifyProof, a as CreateProofOptions, b as VerifyJsonLdOptions, c as VerifyPortableObjectProofFailureReason, d as VerifyProofOptions, f as createProof, g as verifyPortableObjectProof, h as verifyObject, i as verifyPortableObject, l as VerifyPortableObjectProofOptions, m as signObject, n as VerifyPortableObjectOptions, o as SignObjectOptions, p as hasProofLike, r as VerifyPortableObjectResult, s as VerifyObjectOptions, t as VerifyPortableObjectFailureReason, u as VerifyPortableObjectProofResult, v as CreateSignatureOptions, w as detachSignature, x as VerifySignatureOptions, y as SignJsonLdOptions } from "../mod-Coacostr.js";
5
5
  export { AcceptSignatureMember, AcceptSignatureParameters, CreateProofOptions, CreateSignatureOptions, DoesActorOwnKeyOptions, FetchKeyDetailedResult, FetchKeyErrorResult, FetchKeyOptions, FetchKeyResult, FulfillAcceptSignatureResult, GetKeyOwnerOptions, HttpMessageSignaturesSpec, HttpMessageSignaturesSpecDeterminer, KeyCache, Rfc9421SignRequestOptions, SignJsonLdOptions, SignObjectOptions, SignRequestOptions, VerifyJsonLdOptions, VerifyObjectOptions, VerifyPortableObjectFailureReason, VerifyPortableObjectOptions, VerifyPortableObjectProofFailureReason, VerifyPortableObjectProofOptions, VerifyPortableObjectProofResult, VerifyPortableObjectResult, VerifyProofOptions, VerifyRequestDetailedResult, VerifyRequestFailureReason, VerifyRequestOptions, VerifySignatureOptions, attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, fetchKeyDetailed, formatAcceptSignature, fulfillAcceptSignature, generateCryptoKeyPair, getKeyOwner, hasProofLike, hasSignatureLike, importJwk, parseAcceptSignature, signJsonLd, signObject, signRequest, validateAcceptSignature, verifyJsonLd, verifyObject, verifyPortableObject, verifyPortableObjectProof, verifyProof, verifyRequest, verifyRequestDetailed, verifySignature };
package/dist/sig/mod.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { URLPattern } from "urlpattern-polyfill";
3
- import { A as verifySignature, D as signJsonLd, F as fetchKeyDetailed, I as generateCryptoKeyPair, L as importJwk, M as exportJwk, P as fetchKey, a as verifyRequestDetailed, b as createSignature, c as hasProofLike, d as verifyObject, dt as fulfillAcceptSignature, f as verifyPortableObjectProof, ft as parseAcceptSignature, h as verifyProof, i as verifyRequest, k as verifyJsonLd, l as signObject, pt as validateAcceptSignature, r as signRequest, s as createProof, ut as formatAcceptSignature, v as attachSignature, w as hasSignatureLike, x as detachSignature } from "../http-4PCCvhsU.js";
4
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-_pbbgLJK.js";
5
- import { t as verifyPortableObject } from "../sig-DhdomAN0.js";
3
+ import { C as detachSignature, E as hasSignatureLike, I as fetchKey, L as fetchKeyDetailed, M as verifySignature, P as exportJwk, R as generateCryptoKeyPair, S as createSignature, a as verifyRequestDetailed, b as attachSignature, c as createProof, ct as parseAcceptSignature, f as verifyObject, g as verifyProof, i as verifyRequest, j as verifyJsonLd, k as signJsonLd, l as hasProofLike, lt as validateAcceptSignature, ot as formatAcceptSignature, p as verifyPortableObjectProof, r as signRequest, st as fulfillAcceptSignature, u as signObject, z as importJwk } from "../http-DyT7DP1Y.js";
4
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-DAGSC5gX.js";
5
+ import { t as verifyPortableObject } from "../sig-B5Ell7pO.js";
6
6
  export { attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, fetchKeyDetailed, formatAcceptSignature, fulfillAcceptSignature, generateCryptoKeyPair, getKeyOwner, hasProofLike, hasSignatureLike, importJwk, parseAcceptSignature, signJsonLd, signObject, signRequest, validateAcceptSignature, verifyJsonLd, verifyObject, verifyPortableObject, verifyPortableObjectProof, verifyProof, verifyRequest, verifyRequestDetailed, verifySignature };
@@ -6,7 +6,7 @@ import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
6
6
  import "../std__assert-DvMDRPes.mjs";
7
7
  import { t as assert } from "../assert-D1Eafmd_.mjs";
8
8
  import { o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
9
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-CsKVgMzk.mjs";
9
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-Cgx2Dc7I.mjs";
10
10
  import { Create, CryptographicKey, lookupObject } from "@fedify/vocab";
11
11
  import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
12
12
  //#region src/sig/owner.test.ts
@@ -1,17 +1,17 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { n as version, t as name } from "../deno-Dn-py9Zy.mjs";
5
- import { c as verifyPortableObjectProofWithRoot, o as verifyPortableObjectProof } from "../proof-ozG4HfcQ.mjs";
4
+ import { n as version, t as name } from "../deno-8t8k_6Yv.mjs";
5
+ import { l as verifyPortableObjectProofWithRoot, s as verifyPortableObjectProof } from "../proof-DVXC6nYz.mjs";
6
6
  import { n as ed25519PrivateKey, r as ed25519PublicKey } from "../keys-DIJNHW-Y.mjs";
7
7
  import { getLogger } from "@logtape/logtape";
8
8
  import { Collection, CollectionPage, Note, Object as Object$1, OrderedCollection, Person, isActor, traverseCollection } from "@fedify/vocab";
9
9
  import { trace } from "@opentelemetry/api";
10
10
  import { test } from "@fedify/fixture";
11
11
  import { FetchError, canonicalizePortableUri, encodeMultibase, exportDidKey, formatIri, fromCompatibleEf61Id, getDocumentLoader, getFe34Origin, parseIri, preloadedContexts } from "@fedify/vocab-runtime";
12
+ import { dereferencePortableIri, getPortableGatewayCandidates } from "@fedify/vocab-runtime/internal/portable-dereference";
12
13
  import serialize from "json-canon";
13
14
  import { deepStrictEqual, ok, strictEqual } from "node:assert/strict";
14
- import { dereferencePortableIri, getPortableGatewayCandidates } from "@fedify/vocab-runtime/internal/portable-dereference";
15
15
  //#region src/sig/portable-collection.ts
16
16
  const logger = getLogger([
17
17
  "fedify",
@@ -54,6 +54,8 @@ function getContextState(context) {
54
54
  }
55
55
  function canonicalize(id) {
56
56
  try {
57
+ const portable = fromCompatibleEf61Id(id);
58
+ if (portable != null) return canonicalizePortableUri(formatIri(portable));
57
59
  return canonicalizePortableUri(typeof id === "string" ? id : formatIri(id));
58
60
  } catch (error) {
59
61
  if (error instanceof TypeError) return null;
@@ -234,7 +236,20 @@ async function fetchOwner(candidate, options) {
234
236
  const contextLoader = options.contextLoader ?? getDocumentLoader();
235
237
  const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
236
238
  const tracer = tracerProvider.getTracer(name, version);
237
- const gateways = options.gateways ?? (getPortableGatewayCandidates(candidate).length > 0 ? void 0 : options.gatewayHints);
239
+ let inferredGateways;
240
+ try {
241
+ const portable = fromCompatibleEf61Id(candidate);
242
+ if (portable != null) {
243
+ inferredGateways = [new URL(candidate.origin)];
244
+ candidate = portable;
245
+ }
246
+ } catch (error) {
247
+ if (!(error instanceof TypeError)) throw error;
248
+ logger.debug("The owner {owner} of a portable collection is a malformed compatible identifier.", { owner: candidate.href });
249
+ return null;
250
+ }
251
+ const gateways = options.gateways ?? (inferredGateways != null || getPortableGatewayCandidates(candidate).length > 0 ? void 0 : options.gatewayHints);
252
+ if (options.gateways != null) inferredGateways = void 0;
238
253
  const span = tracer.startSpan("activitypub.lookup_object");
239
254
  try {
240
255
  const object = await dereferencePortableIri(candidate, {
@@ -242,6 +257,7 @@ async function fetchOwner(candidate, options) {
242
257
  contextLoader,
243
258
  tracerProvider,
244
259
  gateways,
260
+ ...inferredGateways == null ? {} : { inferredGateways },
245
261
  verifyPortableObject: (document, verifierOptions) => verifyPortableObjectProof(document, {
246
262
  ...options,
247
263
  ...verifierOptions
@@ -569,13 +585,61 @@ test("verifyPortableObject() uses the actual fetch source", async () => {
569
585
  referrer,
570
586
  documentUrl: new URL(`https://user@gw1.example/.well-known/apgateway/${did}/actor/outbox`)
571
587
  }), "unknownCollectionSource");
572
- assertFailure(await verify(outbox({ id: gatewayUrl(evil, outboxId) }), {
588
+ const result = await verify(outbox({ id: gatewayUrl(evil, outboxId) }), {
589
+ documentLoader,
590
+ gateways,
591
+ referrer,
592
+ documentUrl: new URL(gatewayUrl(gw1, outboxId))
593
+ });
594
+ ok(result.verified);
595
+ strictEqual(result.method, "gateway");
596
+ if (result.method !== "gateway") return;
597
+ deepStrictEqual(result.gateway, new URL(gw1));
598
+ assertFailure(await verify(outbox({ id: `${evil}/outbox` }), {
573
599
  documentLoader,
574
600
  gateways,
575
601
  referrer,
576
602
  documentUrl: new URL(gatewayUrl(gw1, outboxId))
577
603
  }), "notPortableObject");
578
604
  });
605
+ test("verifyPortableObject() trusts unsecured collections of compatible-ID actors", async () => {
606
+ const compatibleActorId = gatewayUrl(gw1, actorId);
607
+ const compatibleOutboxId = gatewayUrl(gw1, outboxId);
608
+ const signed = await sign(actor({
609
+ id: compatibleActorId,
610
+ inbox: gatewayUrl(gw1, `ap://${did}/actor/inbox`),
611
+ outbox: compatibleOutboxId,
612
+ followers: gatewayUrl(gw1, `ap://${did}/actor/followers`)
613
+ }));
614
+ const collection = outbox({
615
+ id: compatibleOutboxId,
616
+ attributedTo: compatibleActorId
617
+ });
618
+ const documentLoader = createLoader({ [compatibleActorId]: signed });
619
+ const result = await verify(collection, {
620
+ documentLoader,
621
+ documentUrl: new URL(compatibleOutboxId)
622
+ });
623
+ ok(result.verified, JSON.stringify(result));
624
+ strictEqual(result.method, "gateway");
625
+ if (result.method !== "gateway") return;
626
+ deepStrictEqual(result.gateway, new URL(gw1));
627
+ deepStrictEqual(documentLoader.fetched, [compatibleActorId]);
628
+ const noGateways = createLoader({ [compatibleActorId]: signed });
629
+ assertFailure(await verify(collection, {
630
+ documentLoader: noGateways,
631
+ documentUrl: new URL(compatibleOutboxId),
632
+ gateways: []
633
+ }), "collectionOwnerUnavailable");
634
+ deepStrictEqual(noGateways.fetched.filter((url) => url === compatibleActorId), []);
635
+ assertFailure(await verify(collection, {
636
+ documentLoader: createLoader({ [compatibleActorId]: actor({
637
+ id: compatibleActorId,
638
+ outbox: compatibleOutboxId
639
+ }) }),
640
+ documentUrl: new URL(compatibleOutboxId)
641
+ }), "collectionOwnerUnavailable");
642
+ });
579
643
  test("verifyPortableObject() requires an unambiguous owner", async () => {
580
644
  const base = {
581
645
  documentLoader: createLoader({ [gatewayUrl(gw1, actorId)]: signedActor }),
@@ -1,13 +1,13 @@
1
1
  import "temporal-polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { r as fetchKey } from "../key-BJrp524f.mjs";
5
- import { l as verifyRequest, s as signRequest } from "../http-B0VRNipE.mjs";
4
+ import { r as fetchKey } from "../key-Dwm4VswT.mjs";
5
+ import { l as verifyRequest, s as signRequest } from "../http-B2ftY0Ha.mjs";
6
6
  import { c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
7
- import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-CsKVgMzk.mjs";
7
+ import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-Cgx2Dc7I.mjs";
8
8
  import { Create, CryptographicKey, Multikey, Person } from "@fedify/vocab";
9
9
  import { test } from "@fedify/fixture";
10
- import { FetchError, encodeMultibase, exportDidKey, parseIri, preloadedContexts } from "@fedify/vocab-runtime";
10
+ import { FetchError, encodeMultibase, exportDidKey, exportSpki, parseIri, preloadedContexts } from "@fedify/vocab-runtime";
11
11
  import serialize from "json-canon";
12
12
  import { deepStrictEqual, ok, strictEqual } from "node:assert/strict";
13
13
  //#region src/sig/portable-key.test.ts
@@ -129,7 +129,16 @@ test("verifyRequest() rejects gateway keys that portable actors do not vouch for
129
129
  "an unsigned actor document": unsigned,
130
130
  "an actor document signed by another DID": await sign(unsigned, otherKeyPair.privateKey, `${otherDid}#${otherDid.slice(8)}`),
131
131
  "an unlisted gateway": await sign(await actorJson({ gateways: [gw2] })),
132
- "a key missing from assertionMethod": await sign(await actorJson({ assertionMethod: false })),
132
+ "a key missing from both assertionMethod and publicKey": await sign(await actorJson({
133
+ assertionMethod: false,
134
+ publicKey: null
135
+ })),
136
+ "a key referred to by URL in assertionMethod, embedded in publicKey": await sign({
137
+ ...await actorJson({ assertionMethod: false }),
138
+ assertionMethod: [keyId.href]
139
+ }),
140
+ "a key only in publicKey without an owner": await sign(withoutPublicKeyOwner(await actorJson({ assertionMethod: false }))),
141
+ "two keys with the same ID in publicKey": await sign(await duplicatePublicKey(await actorJson({ assertionMethod: false }))),
133
142
  "a key referred to by URL": await sign({
134
143
  ...await actorJson({
135
144
  publicKey: null,
@@ -154,18 +163,175 @@ test("verifyRequest() rejects gateway keys that portable actors do not vouch for
154
163
  contextLoader
155
164
  }), null);
156
165
  });
157
- test("verifyRequest() keeps web-origin trust for compatible-ID actors", async () => {
158
- const id = compatibleId(gw1);
159
- const documentLoader = createLoader({ [id]: await actorJson({
160
- id,
161
- gateways: [gw1]
166
+ function withoutPublicKeyOwner(json) {
167
+ const { owner: _, ...publicKey } = json.publicKey;
168
+ return {
169
+ ...json,
170
+ publicKey
171
+ };
172
+ }
173
+ async function duplicatePublicKey(json) {
174
+ const publicKey = json.publicKey;
175
+ return {
176
+ ...json,
177
+ publicKey: [publicKey, {
178
+ ...publicKey,
179
+ publicKeyPem: await exportSpki(rsaPublicKey3.publicKey)
180
+ }]
181
+ };
182
+ }
183
+ test("verifyRequest() accepts gateway keys referred to by URL in publicKey", async () => {
184
+ const documentLoader = createLoader({ [compatibleId(gw1)]: await sign({
185
+ ...await actorJson({ publicKey: null }),
186
+ publicKey: keyId.href
162
187
  }) });
188
+ strictEqual((await verifyRequest(await signedRequest(), {
189
+ documentLoader,
190
+ contextLoader
191
+ }))?.id?.href, keyId.href);
192
+ });
193
+ test("verifyRequest() accepts gateway keys only in publicKey", async () => {
194
+ const documentLoader = createLoader({ [compatibleId(gw1)]: await sign(await actorJson({ assertionMethod: false })) });
163
195
  const key = await verifyRequest(await signedRequest(), {
164
196
  documentLoader,
165
197
  contextLoader
166
198
  });
167
199
  strictEqual(key?.id?.href, keyId.href);
200
+ strictEqual(key?.ownerId?.href, parseIri(actorId).href);
201
+ });
202
+ test("verifyRequest() resolves gateway keys of compatible-ID actors", async () => {
203
+ const id = compatibleId(gw1);
204
+ const signed = await sign(await actorJson({
205
+ id,
206
+ gateways: [gw1]
207
+ }));
208
+ let key = await verifyRequest(await signedRequest(), {
209
+ documentLoader: createLoader({ [id]: signed }),
210
+ contextLoader
211
+ });
212
+ strictEqual(key?.id?.href, keyId.href);
168
213
  strictEqual(key?.ownerId?.href, id);
214
+ key = await verifyRequest(await signedRequest(), {
215
+ documentLoader: createLoader({ [id]: await sign(await actorJson({
216
+ id,
217
+ gateways: [gw1],
218
+ assertionMethod: false
219
+ })) }),
220
+ contextLoader
221
+ });
222
+ strictEqual(key?.id?.href, keyId.href);
223
+ const evil = "https://evil.example";
224
+ const evilId = compatibleId(evil);
225
+ const evilKeyId = new URL(`${evilId}#main-key`);
226
+ const unsigned = await actorJson({
227
+ id: evilId,
228
+ gateways: [evil],
229
+ key: evilKeyId
230
+ });
231
+ const documentLoader = createLoader({ [evilId]: unsigned });
232
+ strictEqual(await verifyRequest(await signedRequest(void 0, evilKeyId), {
233
+ documentLoader,
234
+ contextLoader
235
+ }), null);
236
+ strictEqual(await getKeyOwner(evilKeyId, {
237
+ documentLoader,
238
+ contextLoader
239
+ }), null);
240
+ strictEqual(await verifyRequest(await signedRequest(), {
241
+ documentLoader: createLoader({ [id]: await sign(await actorJson({
242
+ id,
243
+ gateways: [gw1]
244
+ }), otherKeyPair.privateKey, `${otherDid}#${otherDid.slice(8)}`) }),
245
+ contextLoader
246
+ }), null);
247
+ });
248
+ test("keys at ordinary URLs cannot belong to portable actors", async () => {
249
+ const evil = "https://evil.example";
250
+ const evilActorId = compatibleId(evil);
251
+ const evilKeyId = new URL(`${evil}/keys/1`);
252
+ const options = {
253
+ documentLoader: createLoader({
254
+ [evilKeyId.href]: {
255
+ "@context": "https://w3id.org/security/v1",
256
+ id: evilKeyId.href,
257
+ type: "Key",
258
+ owner: evilActorId,
259
+ publicKeyPem: await exportSpki(gatewayPublicKey)
260
+ },
261
+ [evilActorId]: await actorJson({
262
+ id: evilActorId,
263
+ gateways: [evil],
264
+ key: evilKeyId,
265
+ assertionMethod: false
266
+ })
267
+ }),
268
+ contextLoader
269
+ };
270
+ strictEqual(await verifyRequest(await signedRequest(void 0, evilKeyId), options), null);
271
+ strictEqual((await fetchKey(evilKeyId, CryptographicKey, options)).key, null);
272
+ strictEqual(await getKeyOwner(evilKeyId, options), null);
273
+ const key = new CryptographicKey({
274
+ id: evilKeyId,
275
+ owner: new URL(evilActorId),
276
+ publicKey: gatewayPublicKey
277
+ });
278
+ strictEqual(await getKeyOwner(key, options), null);
279
+ ok(!await doesActorOwnKey(new Create({
280
+ id: new URL(`${evil}/activities/1`),
281
+ actor: new URL(evilActorId)
282
+ }), key, options));
283
+ const actorKeyId = new URL(`${evil}/users/alice#main-key`);
284
+ for (const document of [await actorJson({
285
+ id: evilActorId,
286
+ gateways: [evil],
287
+ key: actorKeyId
288
+ }), withoutPublicKeyOwner(await actorJson({
289
+ id: evilActorId,
290
+ gateways: [evil],
291
+ key: actorKeyId,
292
+ assertionMethod: false
293
+ }))]) {
294
+ const actorOptions = {
295
+ documentLoader: createLoader({ [`${evil}/users/alice`]: document }),
296
+ contextLoader
297
+ };
298
+ strictEqual(await verifyRequest(await signedRequest(void 0, actorKeyId), actorOptions), null);
299
+ strictEqual((await fetchKey(actorKeyId, CryptographicKey, actorOptions)).key, null);
300
+ strictEqual(await getKeyOwner(actorKeyId, actorOptions), null);
301
+ }
302
+ const ownerKeyId = new URL(`${evil}/keys/2`);
303
+ const ownerOptions = {
304
+ documentLoader: createLoader({
305
+ [ownerKeyId.href]: {
306
+ "@context": "https://w3id.org/security/v1",
307
+ id: ownerKeyId.href,
308
+ type: "Key",
309
+ owner: `${evil}/users/bob`,
310
+ publicKeyPem: await exportSpki(gatewayPublicKey)
311
+ },
312
+ [`${evil}/users/bob`]: await actorJson({
313
+ id: evilActorId,
314
+ gateways: [evil],
315
+ key: ownerKeyId,
316
+ assertionMethod: false
317
+ })
318
+ }),
319
+ contextLoader
320
+ };
321
+ strictEqual(await getKeyOwner(ownerKeyId, ownerOptions), null);
322
+ strictEqual(await getKeyOwner(new CryptographicKey({
323
+ id: ownerKeyId,
324
+ owner: new URL(`${evil}/users/bob`),
325
+ publicKey: gatewayPublicKey
326
+ }), ownerOptions), null);
327
+ const keyCache = {
328
+ get: () => Promise.resolve(key),
329
+ set: () => Promise.resolve()
330
+ };
331
+ strictEqual((await fetchKey(evilKeyId, CryptographicKey, {
332
+ ...options,
333
+ keyCache
334
+ })).key, null);
169
335
  });
170
336
  test("gateway keys are neither cached nor accepted outside HTTP Signatures", async () => {
171
337
  const calls = [];