@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.
- package/dist/{builder-BGlpUocK.mjs → builder-Ld4Y9ymR.mjs} +34 -3
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{compound-proof-B6Aj2kGY.mjs → compound-proof-CTx_lewQ.mjs} +191 -13
- package/dist/{deno-Dn-py9Zy.mjs → deno-8t8k_6Yv.mjs} +1 -1
- package/dist/{docloader-BUq5bYJr.mjs → docloader-DJKcsAiF.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/compound-fanout.test.mjs +3 -3
- package/dist/federation/handler-compound-proof.test.mjs +3 -3
- package/dist/federation/handler.test.mjs +5 -5
- package/dist/federation/hashlink-media.test.mjs +2 -2
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +7 -7
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.js +1 -1
- package/dist/federation/outgoing-proof.test.mjs +254 -5
- package/dist/federation/portable-gateway-keys.test.mjs +72 -11
- package/dist/federation/portable-inbox.test.mjs +116 -4
- package/dist/federation/portable.test.mjs +182 -4
- package/dist/federation/send.test.mjs +3 -3
- package/dist/federation/tasks/enqueue.test.mjs +1 -1
- package/dist/federation/tasks/tasks.test.mjs +2 -2
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +89 -1
- package/dist/{federation-BLGx8JUH.cjs → federation-aSHO04ob.cjs} +360 -65
- package/dist/{http-B0VRNipE.mjs → http-B2ftY0Ha.mjs} +4 -4
- package/dist/{http-B5q1CHtL.cjs → http-DSaSAN7X.cjs} +1609 -1457
- package/dist/{http-4PCCvhsU.js → http-DyT7DP1Y.js} +1518 -1390
- package/dist/{key-BJrp524f.mjs → key-Dwm4VswT.mjs} +39 -99
- package/dist/{kv-cache-Dhhhrryv.cjs → kv-cache-BSJAlP4C.cjs} +1 -1
- package/dist/{kv-cache-C4C3LyYW.mjs → kv-cache-D0yYukqk.mjs} +1 -1
- package/dist/{kv-cache-1KUmAPH7.js → kv-cache-DmroAz3M.js} +1 -1
- package/dist/{ld-BmFz5NLA.mjs → ld-BYZOoDzZ.mjs} +3 -3
- package/dist/{metrics-Beod6tzO.mjs → metrics-B7YwKTFr.mjs} +1 -1
- package/dist/{middleware-B7CNsyqt.mjs → middleware-BNeqKSsL.mjs} +1 -1
- package/dist/{middleware-D_9pNYe9.js → middleware-Blq0882d.js} +368 -73
- package/dist/{middleware-BKeQYPm0.mjs → middleware-E_0IH72m.mjs} +166 -71
- package/dist/{mod-HDSvS-ww.d.cts → mod-C8LieBzF.d.cts} +16 -3
- package/dist/{mod-C9WSpZWm.d.ts → mod-Coacostr.d.ts} +16 -3
- package/dist/mod.cjs +5 -5
- package/dist/mod.d.cts +1 -1
- package/dist/mod.d.ts +1 -1
- package/dist/mod.js +5 -5
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/{owner-CsKVgMzk.mjs → owner-Cgx2Dc7I.mjs} +5 -4
- package/dist/{owner-_pbbgLJK.js → owner-DAGSC5gX.js} +2 -2
- package/dist/{owner-BQFZtFV4.cjs → owner-szIZl4qI.cjs} +2 -2
- package/dist/{portable-key-B4R-CiIV.mjs → portable-key-Cn1WJSN1.mjs} +60 -41
- package/dist/portable-key-id-Bva5iT3W.mjs +136 -0
- package/dist/{proof-ozG4HfcQ.mjs → proof-DVXC6nYz.mjs} +59 -18
- package/dist/{send-ClPt8nYu.mjs → send-D-hOvYKy.mjs} +3 -3
- package/dist/sig/compound-proof-discovery.test.mjs +1 -1
- package/dist/sig/compound-proof-producer.test.mjs +1 -1
- package/dist/sig/compound-proof-verification.test.mjs +160 -3
- package/dist/sig/compound-proof.test.mjs +2 -2
- package/dist/sig/http.test.mjs +2 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +2 -2
- package/dist/sig/mod.cjs +3 -3
- package/dist/sig/mod.d.cts +1 -1
- package/dist/sig/mod.d.ts +1 -1
- package/dist/sig/mod.js +3 -3
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/portable-collection.test.mjs +69 -5
- package/dist/sig/portable-key.test.mjs +176 -10
- package/dist/sig/proof.test.mjs +107 -4
- package/dist/{sig-DhdomAN0.js → sig-B5Ell7pO.js} +19 -3
- package/dist/{sig-k3C8sF7g.cjs → sig-CXOKN4Br.cjs} +19 -3
- package/dist/{temporal-Ba0EAZAI.mjs → temporal-CqpKGEPk.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- package/dist/utils/docloader.test.mjs +2 -2
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.js +1 -1
- 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 {
|
|
8
|
-
import {
|
|
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 {
|
|
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-
|
|
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";
|
package/dist/sig/http.test.mjs
CHANGED
|
@@ -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-
|
|
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-
|
|
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";
|
package/dist/sig/key.test.mjs
CHANGED
|
@@ -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-
|
|
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";
|
package/dist/sig/ld.test.mjs
CHANGED
|
@@ -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-
|
|
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-
|
|
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-
|
|
4
|
-
const require_owner = require("../owner-
|
|
5
|
-
const require_sig = require("../sig-
|
|
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;
|
package/dist/sig/mod.d.cts
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-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-
|
|
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-
|
|
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 {
|
|
4
|
-
import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-
|
|
5
|
-
import { t as verifyPortableObject } from "../sig-
|
|
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 };
|
package/dist/sig/owner.test.mjs
CHANGED
|
@@ -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-
|
|
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-
|
|
5
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
5
|
-
import { l as verifyRequest, s as signRequest } from "../http-
|
|
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-
|
|
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({
|
|
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
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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 = [];
|