@fedify/fedify 2.2.18 → 2.2.20
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-DAbQyxmb.mjs → builder-BolQ56ab.mjs} +2 -2
- package/dist/{client-CAM_bQXx.d.cts → client-BIBzqEIp.d.cts} +0 -1
- package/dist/{client-9F_u23dc.mjs → client-DhxaVgOv.mjs} +113 -64
- package/dist/{client-CSddvgWN.d.ts → client-jE7oGvRh.d.ts} +0 -1
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{context-tJbL_Hkw.d.cts → context-CFQGaq5x.d.cts} +28 -2
- package/dist/{context-OkwEpc3-.d.ts → context-DdbLVV_k.d.ts} +28 -2
- package/dist/{deno-JUTr6LYC.mjs → deno-BUj4roJc.mjs} +1 -1
- package/dist/docloader-CbtF_0cD.mjs +125 -0
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +5 -5
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/inbox.test.mjs +1 -1
- package/dist/federation/keycache.test.mjs +18 -7
- package/dist/federation/middleware.test.mjs +389 -28
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +2 -2
- package/dist/federation/mod.d.ts +2 -2
- package/dist/federation/mod.js +1 -1
- package/dist/federation/send.test.mjs +445 -70
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +1 -1
- package/dist/{http-Dl00HXr4.d.ts → http-9IFUxdkp.d.cts} +1 -2
- package/dist/{http-OSYYhKM8.js → http-C5g_VrA_.js} +188 -105
- package/dist/{http-lCmKCZBI.mjs → http-CQMVisM0.mjs} +195 -97
- package/dist/{http-DEH_eppX.cjs → http-D8I7LBfx.cjs} +189 -106
- package/dist/{http-DqZhyEso.d.cts → http-SbfezERn.d.ts} +1 -2
- package/dist/{inbox-DMATfdEI.mjs → inbox-CD8IDILN.mjs} +1 -1
- package/dist/{key-D0ahOVjf.mjs → key-C3o3DGap.mjs} +17 -3
- package/dist/{keycache-Dkc_sflV.mjs → keycache-BimEQucx.mjs} +1 -1
- package/dist/{kv-cache-B7X4p1y7.js → kv-cache-CSKXXleR.js} +60 -16
- package/dist/{kv-cache-CPEV_4nZ.cjs → kv-cache-DC9LcfoC.cjs} +59 -15
- package/dist/{ld-CJOXIehz.mjs → ld-ijSr-0AB.mjs} +2 -2
- package/dist/{middleware-CHoUjmJm.mjs → middleware-CYAaUTi5.mjs} +79 -39
- package/dist/{middleware-QcuVRA-q.cjs → middleware-DNueR0GD.cjs} +185 -60
- package/dist/{middleware-D3hx1aiI.cjs → middleware-DmcY2TWS.cjs} +1 -1
- package/dist/{middleware-aNUajYPY.js → middleware-sjhz30sm.js} +185 -60
- package/dist/{middleware-BgGJEcdp.mjs → middleware-yqqfI7oJ.mjs} +1 -1
- package/dist/{mod-B6LmugJ4.d.ts → mod-BRnwh2oy.d.ts} +2 -8
- package/dist/{mod-D2JyWtW3.d.cts → mod-BYWp77-z.d.cts} +1 -1
- package/dist/{mod-DQGjRJUG.d.ts → mod-BuRRdsfD.d.ts} +1 -1
- package/dist/{mod-ej_rLx8h.d.ts → mod-CM5_J_cx.d.ts} +1 -1
- package/dist/{mod-a6kmB8xD.d.cts → mod-CVSKw-5H.d.cts} +1 -1
- package/dist/{mod-V2vDnYNu.d.cts → mod-Co7LEK9X.d.cts} +2 -8
- package/dist/mod.cjs +5 -5
- package/dist/mod.d.cts +6 -6
- package/dist/mod.d.ts +6 -6
- package/dist/mod.js +5 -5
- package/dist/nodeinfo/client.test.mjs +337 -19
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/nodeinfo/mod.cjs +1 -1
- package/dist/nodeinfo/mod.d.cts +1 -1
- package/dist/nodeinfo/mod.d.ts +1 -1
- package/dist/nodeinfo/mod.js +1 -1
- package/dist/otel/exporter.test.mjs +292 -30
- package/dist/otel/mod.cjs +36 -30
- package/dist/otel/mod.d.cts +13 -0
- package/dist/otel/mod.d.ts +13 -0
- package/dist/otel/mod.js +36 -30
- package/dist/{owner-BUTMEkbn.mjs → owner-B8kXzD0q.mjs} +2 -2
- package/dist/{proof-DS1Zl6BX.mjs → proof-CBQOjOgA.mjs} +2 -2
- package/dist/{proof-Bm3xyn3D.js → proof-DKX6nASL.js} +1 -1
- package/dist/{proof-BeY7TsiS.cjs → proof-qiuGJCD7.cjs} +1 -1
- package/dist/{send-fnPrh9Zm.mjs → send-DRpisX_f.mjs} +117 -32
- package/dist/sig/http.test.mjs +529 -3
- package/dist/sig/key.test.mjs +197 -3
- package/dist/sig/ld.test.mjs +47 -2
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.d.cts +2 -2
- package/dist/sig/mod.d.ts +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +46 -1
- package/dist/sig/proof.test.mjs +52 -1
- package/dist/{temporal-Biz6zK6e.mjs → temporal-BQGEINad.mjs} +1 -1
- package/dist/testing/mod.d.mts +26 -1
- package/dist/{types-miAYfiGO.js → types-B1_pRFE_.js} +112 -63
- package/dist/{types-DRPjmHVV.cjs → types-DOvyymM4.cjs} +111 -62
- package/dist/utils/docloader.test.mjs +382 -34
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.d.cts +1 -1
- package/dist/utils/mod.d.ts +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +6 -6
- package/dist/docloader-BGjq1F5U.mjs +0 -81
package/dist/sig/key.test.mjs
CHANGED
|
@@ -3,13 +3,13 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
5
5
|
import "../std__assert-DNZ4Liil.mjs";
|
|
6
|
-
import { t as assertThrows } from "../assert_throws-D4DNWrux.mjs";
|
|
6
|
+
import { r as assertFalse, t as assertThrows } from "../assert_throws-D4DNWrux.mjs";
|
|
7
7
|
import { t as assert } from "../assert-BhQd8QHP.mjs";
|
|
8
8
|
import { t as assertRejects } from "../assert_rejects-WyYSTDDX.mjs";
|
|
9
9
|
import { t as assertStrictEquals } from "../assert_strict_equals-Dmjbg-bA.mjs";
|
|
10
|
-
import { a as generateCryptoKeyPair, i as fetchKeyDetailed, o as importJwk, r as fetchKey, s as validateCryptoKey, t as exportJwk } from "../key-
|
|
10
|
+
import { a as generateCryptoKeyPair, i as fetchKeyDetailed, o as importJwk, r as fetchKey, s as validateCryptoKey, t as exportJwk } from "../key-C3o3DGap.mjs";
|
|
11
11
|
import { c as rsaPublicKey3, i as rsaPrivateKey2, o as rsaPublicKey1, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.mjs";
|
|
12
|
-
import { _ as wrapContextLoaderForJsonLd } from "../ld-
|
|
12
|
+
import { _ as wrapContextLoaderForJsonLd } from "../ld-ijSr-0AB.mjs";
|
|
13
13
|
import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
14
14
|
import { CryptographicKey, Multikey, Person } from "@fedify/vocab";
|
|
15
15
|
import { FetchError, UrlError, getDocumentLoader } from "@fedify/vocab-runtime";
|
|
@@ -760,5 +760,199 @@ test("fetchKey() records the controller an actor document establishes", async ()
|
|
|
760
760
|
assertEquals(key?.controllerId, new URL(actorId));
|
|
761
761
|
assert(key?.publicKey != null);
|
|
762
762
|
});
|
|
763
|
+
test("fetchKey() rejects a key whose owner redirects to another actor", async () => {
|
|
764
|
+
const keyId = "https://evil.example/keys/1";
|
|
765
|
+
const victim = "https://victim.example/users/alice";
|
|
766
|
+
const mallory = "https://evil.example/users/mallory";
|
|
767
|
+
const { publicKeyPem } = await rsaPublicKey3.toJsonLd({ contextLoader: mockDocumentLoader });
|
|
768
|
+
const cache = {};
|
|
769
|
+
assertEquals(await fetchKey(keyId, CryptographicKey, {
|
|
770
|
+
documentLoader(resource) {
|
|
771
|
+
if (resource === keyId) return Promise.resolve({
|
|
772
|
+
contextUrl: null,
|
|
773
|
+
documentUrl: resource,
|
|
774
|
+
document: {
|
|
775
|
+
"@context": "https://w3id.org/security/v1",
|
|
776
|
+
id: keyId,
|
|
777
|
+
type: "CryptographicKey",
|
|
778
|
+
owner: victim,
|
|
779
|
+
publicKeyPem
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
if (resource === victim || resource === mallory) return Promise.resolve({
|
|
783
|
+
contextUrl: null,
|
|
784
|
+
documentUrl: mallory,
|
|
785
|
+
document: {
|
|
786
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
|
|
787
|
+
id: mallory,
|
|
788
|
+
type: "Person",
|
|
789
|
+
publicKey: keyId
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
return mockDocumentLoader(resource);
|
|
793
|
+
},
|
|
794
|
+
contextLoader: mockDocumentLoader,
|
|
795
|
+
keyCache: {
|
|
796
|
+
get(keyId) {
|
|
797
|
+
return Promise.resolve(cache[keyId.href]);
|
|
798
|
+
},
|
|
799
|
+
set(keyId, key) {
|
|
800
|
+
cache[keyId.href] = key;
|
|
801
|
+
return Promise.resolve();
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
}), {
|
|
805
|
+
key: null,
|
|
806
|
+
cached: false
|
|
807
|
+
});
|
|
808
|
+
assertEquals(cache, { [keyId]: null });
|
|
809
|
+
});
|
|
810
|
+
test("fetchKey() rejects a key whose owner resolves to another actor on the same origin", async () => {
|
|
811
|
+
const keyId = "https://victim.example/keys/bob";
|
|
812
|
+
const victim = "https://victim.example/users/alice";
|
|
813
|
+
const bob = "https://victim.example/users/bob";
|
|
814
|
+
const { publicKeyPem } = await rsaPublicKey3.toJsonLd({ contextLoader: mockDocumentLoader });
|
|
815
|
+
assertEquals(await fetchKey(keyId, CryptographicKey, {
|
|
816
|
+
documentLoader(resource) {
|
|
817
|
+
if (resource === keyId) return Promise.resolve({
|
|
818
|
+
contextUrl: null,
|
|
819
|
+
documentUrl: resource,
|
|
820
|
+
document: {
|
|
821
|
+
"@context": "https://w3id.org/security/v1",
|
|
822
|
+
id: keyId,
|
|
823
|
+
type: "CryptographicKey",
|
|
824
|
+
owner: victim,
|
|
825
|
+
publicKeyPem
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
if (resource === victim || resource === bob) return Promise.resolve({
|
|
829
|
+
contextUrl: null,
|
|
830
|
+
documentUrl: resource,
|
|
831
|
+
document: {
|
|
832
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
|
|
833
|
+
id: bob,
|
|
834
|
+
type: "Person",
|
|
835
|
+
publicKey: keyId
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
return mockDocumentLoader(resource);
|
|
839
|
+
},
|
|
840
|
+
contextLoader: mockDocumentLoader
|
|
841
|
+
}), {
|
|
842
|
+
key: null,
|
|
843
|
+
cached: false
|
|
844
|
+
});
|
|
845
|
+
});
|
|
846
|
+
test("fetchKey() rejects a Multikey whose controller redirects to another actor", async () => {
|
|
847
|
+
const keyId = "https://evil.example/keys/ed25519";
|
|
848
|
+
const victim = "https://victim.example/users/alice";
|
|
849
|
+
const mallory = "https://evil.example/users/mallory";
|
|
850
|
+
const multikeyDocument = await ed25519Multikey.toJsonLd({ contextLoader: mockDocumentLoader });
|
|
851
|
+
assertEquals(await fetchKey(keyId, Multikey, {
|
|
852
|
+
documentLoader(resource) {
|
|
853
|
+
if (resource === keyId) return Promise.resolve({
|
|
854
|
+
contextUrl: null,
|
|
855
|
+
documentUrl: resource,
|
|
856
|
+
document: {
|
|
857
|
+
...multikeyDocument,
|
|
858
|
+
id: keyId,
|
|
859
|
+
controller: victim
|
|
860
|
+
}
|
|
861
|
+
});
|
|
862
|
+
if (resource === victim || resource === mallory) return Promise.resolve({
|
|
863
|
+
contextUrl: null,
|
|
864
|
+
documentUrl: mallory,
|
|
865
|
+
document: {
|
|
866
|
+
"@context": [
|
|
867
|
+
"https://www.w3.org/ns/activitystreams",
|
|
868
|
+
"https://w3id.org/security/v1",
|
|
869
|
+
"https://w3id.org/security/multikey/v1",
|
|
870
|
+
"https://w3id.org/security/data-integrity/v1",
|
|
871
|
+
"https://www.w3.org/ns/did/v1"
|
|
872
|
+
],
|
|
873
|
+
id: mallory,
|
|
874
|
+
type: "Person",
|
|
875
|
+
assertionMethod: [keyId]
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
return mockDocumentLoader(resource);
|
|
879
|
+
},
|
|
880
|
+
contextLoader: mockDocumentLoader
|
|
881
|
+
}), {
|
|
882
|
+
key: null,
|
|
883
|
+
cached: false
|
|
884
|
+
});
|
|
885
|
+
});
|
|
886
|
+
test("fetchKey() accepts an owner whose document URL differs from its id", async () => {
|
|
887
|
+
const keyId = "https://victim.example/keys/alice";
|
|
888
|
+
const alice = "https://victim.example/users/alice";
|
|
889
|
+
const { publicKeyPem } = await rsaPublicKey3.toJsonLd({ contextLoader: mockDocumentLoader });
|
|
890
|
+
const { key, cached } = await fetchKey(keyId, CryptographicKey, {
|
|
891
|
+
documentLoader(resource) {
|
|
892
|
+
if (resource === keyId) return Promise.resolve({
|
|
893
|
+
contextUrl: null,
|
|
894
|
+
documentUrl: resource,
|
|
895
|
+
document: {
|
|
896
|
+
"@context": "https://w3id.org/security/v1",
|
|
897
|
+
id: keyId,
|
|
898
|
+
type: "CryptographicKey",
|
|
899
|
+
owner: alice,
|
|
900
|
+
publicKeyPem
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
if (resource === alice) return Promise.resolve({
|
|
904
|
+
contextUrl: null,
|
|
905
|
+
documentUrl: `${alice}.json`,
|
|
906
|
+
document: {
|
|
907
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
|
|
908
|
+
id: alice,
|
|
909
|
+
type: "Person",
|
|
910
|
+
publicKey: keyId
|
|
911
|
+
}
|
|
912
|
+
});
|
|
913
|
+
return mockDocumentLoader(resource);
|
|
914
|
+
},
|
|
915
|
+
contextLoader: mockDocumentLoader
|
|
916
|
+
});
|
|
917
|
+
assertFalse(cached);
|
|
918
|
+
assertEquals(key?.id, new URL(keyId));
|
|
919
|
+
assertEquals(key?.ownerId, new URL(alice));
|
|
920
|
+
});
|
|
921
|
+
test("fetchKey() rejects an owner reached through a normalization redirect", async () => {
|
|
922
|
+
const keyId = "https://victim.example/keys/alice";
|
|
923
|
+
const canonical = "https://victim.example/users/alice";
|
|
924
|
+
const nonCanonical = "https://victim.example/users/Alice";
|
|
925
|
+
const { publicKeyPem } = await rsaPublicKey3.toJsonLd({ contextLoader: mockDocumentLoader });
|
|
926
|
+
assertEquals(await fetchKey(keyId, CryptographicKey, {
|
|
927
|
+
documentLoader(resource) {
|
|
928
|
+
if (resource === keyId) return Promise.resolve({
|
|
929
|
+
contextUrl: null,
|
|
930
|
+
documentUrl: resource,
|
|
931
|
+
document: {
|
|
932
|
+
"@context": "https://w3id.org/security/v1",
|
|
933
|
+
id: keyId,
|
|
934
|
+
type: "CryptographicKey",
|
|
935
|
+
owner: nonCanonical,
|
|
936
|
+
publicKeyPem
|
|
937
|
+
}
|
|
938
|
+
});
|
|
939
|
+
if (resource === canonical || resource === nonCanonical) return Promise.resolve({
|
|
940
|
+
contextUrl: null,
|
|
941
|
+
documentUrl: canonical,
|
|
942
|
+
document: {
|
|
943
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
|
|
944
|
+
id: canonical,
|
|
945
|
+
type: "Person",
|
|
946
|
+
publicKey: keyId
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
return mockDocumentLoader(resource);
|
|
950
|
+
},
|
|
951
|
+
contextLoader: mockDocumentLoader
|
|
952
|
+
}), {
|
|
953
|
+
key: null,
|
|
954
|
+
cached: false
|
|
955
|
+
});
|
|
956
|
+
});
|
|
763
957
|
//#endregion
|
|
764
958
|
export {};
|
package/dist/sig/ld.test.mjs
CHANGED
|
@@ -5,9 +5,9 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
|
5
5
|
import { r as assertFalse, t as assertThrows } from "../assert_throws-D4DNWrux.mjs";
|
|
6
6
|
import { n as assertInstanceOf, t as assert } from "../assert-BhQd8QHP.mjs";
|
|
7
7
|
import { t as assertRejects } from "../assert_rejects-WyYSTDDX.mjs";
|
|
8
|
-
import { a as generateCryptoKeyPair } from "../key-
|
|
8
|
+
import { a as generateCryptoKeyPair } from "../key-C3o3DGap.mjs";
|
|
9
9
|
import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.mjs";
|
|
10
|
-
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-
|
|
10
|
+
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-ijSr-0AB.mjs";
|
|
11
11
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
12
12
|
import { CryptographicKey } from "@fedify/vocab";
|
|
13
13
|
import { encodeBase64 } from "byte-encodings/base64";
|
|
@@ -860,5 +860,50 @@ test("verifyJsonLd() rejects a key that claims a forged owner", async () => {
|
|
|
860
860
|
contextLoader: mockDocumentLoader
|
|
861
861
|
}));
|
|
862
862
|
});
|
|
863
|
+
test("verifyJsonLd() rejects a key whose owner redirects to another actor", async () => {
|
|
864
|
+
const keyId = new URL("https://evil.example/keys/1");
|
|
865
|
+
const victim = "https://victim.example/users/alice";
|
|
866
|
+
const mallory = "https://evil.example/users/mallory";
|
|
867
|
+
const { publicKeyPem } = await rsaPublicKey3.toJsonLd({ contextLoader: mockDocumentLoader });
|
|
868
|
+
const signed = await signJsonLd({
|
|
869
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
870
|
+
id: "https://victim.example/activities/forged",
|
|
871
|
+
type: "Create",
|
|
872
|
+
actor: victim,
|
|
873
|
+
object: {
|
|
874
|
+
type: "Note",
|
|
875
|
+
content: "forged"
|
|
876
|
+
}
|
|
877
|
+
}, rsaPrivateKey3, keyId, { contextLoader: mockDocumentLoader });
|
|
878
|
+
const options = {
|
|
879
|
+
documentLoader(resource) {
|
|
880
|
+
if (resource === keyId.href) return Promise.resolve({
|
|
881
|
+
contextUrl: null,
|
|
882
|
+
documentUrl: resource,
|
|
883
|
+
document: {
|
|
884
|
+
"@context": "https://w3id.org/security/v1",
|
|
885
|
+
id: keyId.href,
|
|
886
|
+
type: "CryptographicKey",
|
|
887
|
+
owner: victim,
|
|
888
|
+
publicKeyPem
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
if (resource === victim || resource === mallory) return Promise.resolve({
|
|
892
|
+
contextUrl: null,
|
|
893
|
+
documentUrl: mallory,
|
|
894
|
+
document: {
|
|
895
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
|
|
896
|
+
id: mallory,
|
|
897
|
+
type: "Person",
|
|
898
|
+
publicKey: keyId.href
|
|
899
|
+
}
|
|
900
|
+
});
|
|
901
|
+
return mockDocumentLoader(resource);
|
|
902
|
+
},
|
|
903
|
+
contextLoader: mockDocumentLoader
|
|
904
|
+
};
|
|
905
|
+
assertEquals(await verifySignature(signed, options), null);
|
|
906
|
+
assertFalse(await verifyJsonLd(signed, options));
|
|
907
|
+
});
|
|
863
908
|
//#endregion
|
|
864
909
|
export {};
|
package/dist/sig/mod.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const { Temporal } = require("@js-temporal/polyfill");
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
|
-
const require_http = require("../http-
|
|
5
|
-
const require_proof = require("../proof-
|
|
4
|
+
const require_http = require("../http-D8I7LBfx.cjs");
|
|
5
|
+
const require_proof = require("../proof-qiuGJCD7.cjs");
|
|
6
6
|
exports.attachSignature = require_proof.attachSignature;
|
|
7
7
|
exports.createProof = require_proof.createProof;
|
|
8
8
|
exports.createSignature = require_proof.createSignature;
|
package/dist/sig/mod.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
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-
|
|
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-9IFUxdkp.cjs";
|
|
3
3
|
import { i as getKeyOwner, n as GetKeyOwnerOptions, r as doesActorOwnKey, t as DoesActorOwnKeyOptions } from "../owner-B3hNQCG8.cjs";
|
|
4
|
-
import { _ as hasSignatureLike, a as createProof, b as verifySignature, c as verifyObject, d as SignJsonLdOptions, f as VerifyJsonLdOptions, g as detachSignature, h as createSignature, i as VerifyProofOptions, l as verifyProof, m as attachSignature, n as SignObjectOptions, o as hasProofLike, p as VerifySignatureOptions, r as VerifyObjectOptions, s as signObject, t as CreateProofOptions, u as CreateSignatureOptions, v as signJsonLd, y as verifyJsonLd } from "../mod-
|
|
4
|
+
import { _ as hasSignatureLike, a as createProof, b as verifySignature, c as verifyObject, d as SignJsonLdOptions, f as VerifyJsonLdOptions, g as detachSignature, h as createSignature, i as VerifyProofOptions, l as verifyProof, m as attachSignature, n as SignObjectOptions, o as hasProofLike, p as VerifySignatureOptions, r as VerifyObjectOptions, s as signObject, t as CreateProofOptions, u as CreateSignatureOptions, v as signJsonLd, y as verifyJsonLd } from "../mod-BYWp77-z.cjs";
|
|
5
5
|
export { AcceptSignatureMember, AcceptSignatureParameters, CreateProofOptions, CreateSignatureOptions, DoesActorOwnKeyOptions, FetchKeyDetailedResult, FetchKeyErrorResult, FetchKeyOptions, FetchKeyResult, FulfillAcceptSignatureResult, GetKeyOwnerOptions, HttpMessageSignaturesSpec, HttpMessageSignaturesSpecDeterminer, KeyCache, Rfc9421SignRequestOptions, SignJsonLdOptions, SignObjectOptions, SignRequestOptions, VerifyJsonLdOptions, VerifyObjectOptions, 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, verifyProof, verifyRequest, verifyRequestDetailed, verifySignature };
|
package/dist/sig/mod.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
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-
|
|
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-SbfezERn.js";
|
|
3
3
|
import { i as getKeyOwner, n as GetKeyOwnerOptions, r as doesActorOwnKey, t as DoesActorOwnKeyOptions } from "../owner-CiBPcC6F.js";
|
|
4
|
-
import { _ as hasSignatureLike, a as createProof, b as verifySignature, c as verifyObject, d as SignJsonLdOptions, f as VerifyJsonLdOptions, g as detachSignature, h as createSignature, i as VerifyProofOptions, l as verifyProof, m as attachSignature, n as SignObjectOptions, o as hasProofLike, p as VerifySignatureOptions, r as VerifyObjectOptions, s as signObject, t as CreateProofOptions, u as CreateSignatureOptions, v as signJsonLd, y as verifyJsonLd } from "../mod-
|
|
4
|
+
import { _ as hasSignatureLike, a as createProof, b as verifySignature, c as verifyObject, d as SignJsonLdOptions, f as VerifyJsonLdOptions, g as detachSignature, h as createSignature, i as VerifyProofOptions, l as verifyProof, m as attachSignature, n as SignObjectOptions, o as hasProofLike, p as VerifySignatureOptions, r as VerifyObjectOptions, s as signObject, t as CreateProofOptions, u as CreateSignatureOptions, v as signJsonLd, y as verifyJsonLd } from "../mod-CM5_J_cx.js";
|
|
5
5
|
export { AcceptSignatureMember, AcceptSignatureParameters, CreateProofOptions, CreateSignatureOptions, DoesActorOwnKeyOptions, FetchKeyDetailedResult, FetchKeyErrorResult, FetchKeyOptions, FetchKeyResult, FulfillAcceptSignatureResult, GetKeyOwnerOptions, HttpMessageSignaturesSpec, HttpMessageSignaturesSpecDeterminer, KeyCache, Rfc9421SignRequestOptions, SignJsonLdOptions, SignObjectOptions, SignRequestOptions, VerifyJsonLdOptions, VerifyObjectOptions, 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, verifyProof, verifyRequest, verifyRequestDetailed, verifySignature };
|
package/dist/sig/mod.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { _ as validateAcceptSignature, a as verifyRequestDetailed, c as fetchKey, d as importJwk, g as parseAcceptSignature, h as fulfillAcceptSignature, i as verifyRequest, l as fetchKeyDetailed, m as formatAcceptSignature, o as exportJwk, r as signRequest, u as generateCryptoKeyPair } from "../http-
|
|
4
|
-
import { C as verifySignature, S as verifyJsonLd, _ as hasSignatureLike, a as verifyProof, b as signJsonLd, c as getKeyOwner, d as attachSignature, i as verifyObject, m as detachSignature, n as hasProofLike, p as createSignature, r as signObject, s as doesActorOwnKey, t as createProof } from "../proof-
|
|
3
|
+
import { _ as validateAcceptSignature, a as verifyRequestDetailed, c as fetchKey, d as importJwk, g as parseAcceptSignature, h as fulfillAcceptSignature, i as verifyRequest, l as fetchKeyDetailed, m as formatAcceptSignature, o as exportJwk, r as signRequest, u as generateCryptoKeyPair } from "../http-C5g_VrA_.js";
|
|
4
|
+
import { C as verifySignature, S as verifyJsonLd, _ as hasSignatureLike, a as verifyProof, b as signJsonLd, c as getKeyOwner, d as attachSignature, i as verifyObject, m as detachSignature, n as hasProofLike, p as createSignature, r as signObject, s as doesActorOwnKey, t as createProof } from "../proof-DKX6nASL.js";
|
|
5
5
|
export { attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, fetchKeyDetailed, formatAcceptSignature, fulfillAcceptSignature, generateCryptoKeyPair, getKeyOwner, hasProofLike, hasSignatureLike, importJwk, parseAcceptSignature, signJsonLd, signObject, signRequest, validateAcceptSignature, verifyJsonLd, verifyObject, verifyProof, verifyRequest, verifyRequestDetailed, verifySignature };
|
package/dist/sig/owner.test.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import "../std__assert-DNZ4Liil.mjs";
|
|
|
6
6
|
import { r as assertFalse } from "../assert_throws-D4DNWrux.mjs";
|
|
7
7
|
import { t as assert } from "../assert-BhQd8QHP.mjs";
|
|
8
8
|
import { o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-BAK-tUlf.mjs";
|
|
9
|
-
import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-
|
|
9
|
+
import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-B8kXzD0q.mjs";
|
|
10
10
|
import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
11
11
|
import { Create, CryptographicKey, lookupObject } from "@fedify/vocab";
|
|
12
12
|
//#region src/sig/owner.test.ts
|
|
@@ -153,5 +153,50 @@ test("doesActorOwnKey() matches a key that leaves its id implicit", async () =>
|
|
|
153
153
|
publicKey: rsaPublicKey2.publicKey
|
|
154
154
|
}), options));
|
|
155
155
|
});
|
|
156
|
+
test("doesActorOwnKey() rejects an actor ID that redirects to the key's owner", async () => {
|
|
157
|
+
const keyId = "https://evil.example/keys/1";
|
|
158
|
+
const victim = "https://victim.example/users/alice";
|
|
159
|
+
const mallory = "https://evil.example/users/mallory";
|
|
160
|
+
const { publicKeyPem } = await rsaPublicKey1.toJsonLd({ contextLoader: mockDocumentLoader });
|
|
161
|
+
const serveKeyOwnedBy = (owner) => ({
|
|
162
|
+
documentLoader(resource) {
|
|
163
|
+
if (resource === keyId) return Promise.resolve({
|
|
164
|
+
contextUrl: null,
|
|
165
|
+
documentUrl: resource,
|
|
166
|
+
document: {
|
|
167
|
+
"@context": "https://w3id.org/security/v1",
|
|
168
|
+
id: keyId,
|
|
169
|
+
type: "CryptographicKey",
|
|
170
|
+
owner,
|
|
171
|
+
publicKeyPem
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
if (resource === victim || resource === mallory) return Promise.resolve({
|
|
175
|
+
contextUrl: null,
|
|
176
|
+
documentUrl: mallory,
|
|
177
|
+
document: {
|
|
178
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
|
|
179
|
+
id: mallory,
|
|
180
|
+
type: "Person",
|
|
181
|
+
publicKey: keyId
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
return mockDocumentLoader(resource);
|
|
185
|
+
},
|
|
186
|
+
contextLoader: mockDocumentLoader
|
|
187
|
+
});
|
|
188
|
+
const activity = new Create({ actor: new URL(victim) });
|
|
189
|
+
assertFalse(await doesActorOwnKey(activity, new CryptographicKey({
|
|
190
|
+
id: new URL(keyId),
|
|
191
|
+
owner: new URL(mallory),
|
|
192
|
+
publicKey: rsaPublicKey1.publicKey
|
|
193
|
+
}), serveKeyOwnedBy(mallory)));
|
|
194
|
+
assertFalse(await doesActorOwnKey(activity, new CryptographicKey({
|
|
195
|
+
id: new URL(keyId),
|
|
196
|
+
owner: new URL(victim),
|
|
197
|
+
publicKey: rsaPublicKey1.publicKey
|
|
198
|
+
}), serveKeyOwnedBy(victim)));
|
|
199
|
+
assertEquals(await getKeyOwner(new URL(keyId), serveKeyOwnedBy(victim)), null);
|
|
200
|
+
});
|
|
156
201
|
//#endregion
|
|
157
202
|
export {};
|
package/dist/sig/proof.test.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { n as assertInstanceOf, t as assert } from "../assert-BhQd8QHP.mjs";
|
|
|
8
8
|
import { t as assertRejects } from "../assert_rejects-WyYSTDDX.mjs";
|
|
9
9
|
import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.mjs";
|
|
10
10
|
import { r as normalizeOutgoingActivityJsonLd } from "../outgoing-jsonld-amccRMrV.mjs";
|
|
11
|
-
import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-
|
|
11
|
+
import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-CBQOjOgA.mjs";
|
|
12
12
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
13
13
|
import { Create, DataIntegrityProof, Document, Multikey, Note, PUBLIC_COLLECTION, Place } from "@fedify/vocab";
|
|
14
14
|
import { decodeMultibase, importMultibaseKey } from "@fedify/vocab-runtime";
|
|
@@ -438,5 +438,56 @@ test("verifyObject() rejects a key that claims a forged controller", async () =>
|
|
|
438
438
|
contextLoader: mockDocumentLoader
|
|
439
439
|
}), null);
|
|
440
440
|
});
|
|
441
|
+
test("verifyObject() rejects a key whose controller redirects to another actor", async () => {
|
|
442
|
+
const keyId = new URL("https://evil.example/keys/ed25519");
|
|
443
|
+
const victim = "https://victim.example/users/alice";
|
|
444
|
+
const mallory = "https://evil.example/users/mallory";
|
|
445
|
+
const multikeyDocument = await ed25519Multikey.toJsonLd({ contextLoader: mockDocumentLoader });
|
|
446
|
+
const signOptions = {
|
|
447
|
+
format: "compact",
|
|
448
|
+
contextLoader: mockDocumentLoader,
|
|
449
|
+
documentLoader: mockDocumentLoader,
|
|
450
|
+
context: ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/data-integrity/v1"]
|
|
451
|
+
};
|
|
452
|
+
assertEquals(await verifyObject(Create, await (await signObject(new Create({
|
|
453
|
+
id: new URL("https://victim.example/activities/forged"),
|
|
454
|
+
actor: new URL(victim),
|
|
455
|
+
object: new Note({
|
|
456
|
+
id: new URL("https://victim.example/notes/forged"),
|
|
457
|
+
attribution: new URL(victim),
|
|
458
|
+
content: "forged"
|
|
459
|
+
})
|
|
460
|
+
}), ed25519PrivateKey, keyId, signOptions)).toJsonLd(signOptions), {
|
|
461
|
+
documentLoader(resource) {
|
|
462
|
+
if (resource === keyId.href) return Promise.resolve({
|
|
463
|
+
contextUrl: null,
|
|
464
|
+
documentUrl: resource,
|
|
465
|
+
document: {
|
|
466
|
+
...multikeyDocument,
|
|
467
|
+
id: keyId.href,
|
|
468
|
+
controller: victim
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
if (resource === victim || resource === mallory) return Promise.resolve({
|
|
472
|
+
contextUrl: null,
|
|
473
|
+
documentUrl: mallory,
|
|
474
|
+
document: {
|
|
475
|
+
"@context": [
|
|
476
|
+
"https://www.w3.org/ns/activitystreams",
|
|
477
|
+
"https://w3id.org/security/v1",
|
|
478
|
+
"https://w3id.org/security/multikey/v1",
|
|
479
|
+
"https://w3id.org/security/data-integrity/v1",
|
|
480
|
+
"https://www.w3.org/ns/did/v1"
|
|
481
|
+
],
|
|
482
|
+
id: mallory,
|
|
483
|
+
type: "Person",
|
|
484
|
+
assertionMethod: [keyId.href]
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
return mockDocumentLoader(resource);
|
|
488
|
+
},
|
|
489
|
+
contextLoader: mockDocumentLoader
|
|
490
|
+
}), null);
|
|
491
|
+
});
|
|
441
492
|
//#endregion
|
|
442
493
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { c as getNormalizationContextLoader } from "./ld-
|
|
4
|
+
import { c as getNormalizationContextLoader } from "./ld-ijSr-0AB.mjs";
|
|
5
5
|
import jsonld from "@fedify/vocab-runtime/jsonld";
|
|
6
6
|
//#region src/federation/temporal.ts
|
|
7
7
|
function isPlainObject(value) {
|
package/dist/testing/mod.d.mts
CHANGED
|
@@ -5,7 +5,6 @@ import { Activity, Actor, Collection, CryptographicKey, Hashtag, Link, LookupObj
|
|
|
5
5
|
import { Link as Link$1, LookupWebFingerOptions, ResourceDescriptor } from "@fedify/webfinger";
|
|
6
6
|
import { TracerProvider } from "@opentelemetry/api";
|
|
7
7
|
import { DocumentLoader, GetUserAgentOptions } from "@fedify/vocab-runtime";
|
|
8
|
-
|
|
9
8
|
//#region src/nodeinfo/types.d.ts
|
|
10
9
|
/**
|
|
11
10
|
* The type of the result of parsing JSON.
|
|
@@ -1942,6 +1941,11 @@ interface RequestContext<TContextData> extends Context<TContextData> {
|
|
|
1942
1941
|
* Gets the public key of the sender, if any exists and it is verified.
|
|
1943
1942
|
* Otherwise, `null` is returned.
|
|
1944
1943
|
*
|
|
1944
|
+
* Successful results are reused for this request regardless of the options.
|
|
1945
|
+
* Pending checks and `null` results are reused for the same effective
|
|
1946
|
+
* document and context loaders, including failed lookups. Rejected checks
|
|
1947
|
+
* can be retried. Shared work uses the first caller's tracer provider.
|
|
1948
|
+
*
|
|
1945
1949
|
* This can be used for implementing [authorized fetch] (also known as
|
|
1946
1950
|
* secure mode) in ActivityPub.
|
|
1947
1951
|
*
|
|
@@ -1955,6 +1959,11 @@ interface RequestContext<TContextData> extends Context<TContextData> {
|
|
|
1955
1959
|
* Gets the public key of the sender, if any exists and it is verified.
|
|
1956
1960
|
* Otherwise, `null` is returned.
|
|
1957
1961
|
*
|
|
1962
|
+
* Successful results are reused for this request regardless of the options.
|
|
1963
|
+
* Pending checks and `null` results are reused for the same effective
|
|
1964
|
+
* document and context loaders, including failed lookups. Rejected checks
|
|
1965
|
+
* can be retried. Shared work uses the first caller's tracer provider.
|
|
1966
|
+
*
|
|
1958
1967
|
* This can be used for implementing [authorized fetch] (also known as
|
|
1959
1968
|
* secure mode) in ActivityPub.
|
|
1960
1969
|
*
|
|
@@ -1974,6 +1983,14 @@ interface RequestContext<TContextData> extends Context<TContextData> {
|
|
|
1974
1983
|
* Gets the owner of the signed key, if any exists and it is verified.
|
|
1975
1984
|
* Otherwise, `null` is returned.
|
|
1976
1985
|
*
|
|
1986
|
+
* Verified keys and owners are reused for this request regardless of the
|
|
1987
|
+
* options. Pending checks are shared for the same effective document and
|
|
1988
|
+
* context loaders. A `null` result from an owner lookup after key
|
|
1989
|
+
* verification is retained for those loaders. A `null` result caused by
|
|
1990
|
+
* an unverified key is not retained, allowing an owner lookup after another
|
|
1991
|
+
* loader verifies the key. Rejected checks can be retried. Shared work
|
|
1992
|
+
* uses the first caller's tracer provider.
|
|
1993
|
+
*
|
|
1977
1994
|
* This can be used for implementing [authorized fetch] (also known as
|
|
1978
1995
|
* secure mode) in ActivityPub.
|
|
1979
1996
|
*
|
|
@@ -1988,6 +2005,14 @@ interface RequestContext<TContextData> extends Context<TContextData> {
|
|
|
1988
2005
|
* Gets the owner of the signed key, if any exists and it is verified.
|
|
1989
2006
|
* Otherwise, `null` is returned.
|
|
1990
2007
|
*
|
|
2008
|
+
* Verified keys and owners are reused for this request regardless of the
|
|
2009
|
+
* options. Pending checks are shared for the same effective document and
|
|
2010
|
+
* context loaders. A `null` result from an owner lookup after key
|
|
2011
|
+
* verification is retained for those loaders. A `null` result caused by
|
|
2012
|
+
* an unverified key is not retained, allowing an owner lookup after another
|
|
2013
|
+
* loader verifies the key. Rejected checks can be retried. Shared work
|
|
2014
|
+
* uses the first caller's tracer provider.
|
|
2015
|
+
*
|
|
1991
2016
|
* This can be used for implementing [authorized fetch] (also known as
|
|
1992
2017
|
* secure mode) in ActivityPub.
|
|
1993
2018
|
*
|