@fedify/fedify 2.4.5-dev.2462 → 2.4.5
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/README.md +3 -0
- package/dist/{builder-BBUGd9wr.mjs → builder-CUAVOHg6.mjs} +2 -2
- package/dist/{client-D-XP_Ccb.d.cts → client-3InDZbba.d.cts} +0 -1
- package/dist/{client-D-XP_Ccb.d.ts → client-3InDZbba.d.ts} +0 -1
- package/dist/{client-CEnNz8O7.mjs → client-5SIFzW3q.mjs} +113 -64
- 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/{compound-proof-CariICma.mjs → compound-proof-BNjXclzO.mjs} +2 -2
- package/dist/{context-7NyiqIcg.d.ts → context-CVOOd9pD.d.ts} +28 -2
- package/dist/{context-tsYPJ2Ew.d.cts → context-D0gFIgev.d.cts} +28 -2
- package/dist/{deno-BO7-a3hz.mjs → deno-DcJISdwu.mjs} +1 -1
- package/dist/docloader-CP1UxMLL.mjs +136 -0
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/compound-fanout.test.mjs +6 -3
- package/dist/federation/handler-compound-proof.test.mjs +3 -3
- package/dist/federation/handler.test.mjs +4 -4
- package/dist/federation/hashlink-media.test.mjs +2 -2
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/inbox-report.test.mjs +5 -5
- package/dist/federation/inbox.test.mjs +1 -1
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +465 -32
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +3 -3
- package/dist/federation/mod.d.ts +3 -3
- package/dist/federation/mod.js +1 -1
- package/dist/federation/outgoing-proof.test.mjs +9 -6
- package/dist/federation/portable-actor.test.mjs +3 -3
- package/dist/federation/portable-chain.test.mjs +3 -3
- package/dist/federation/portable-collection.test.mjs +4 -4
- package/dist/federation/portable-delivery.test.mjs +2 -2
- package/dist/federation/portable-gateway-keys.test.mjs +11 -5
- package/dist/federation/portable-inbox.test.mjs +4 -4
- package/dist/federation/portable-parse-uri.test.mjs +1 -1
- package/dist/federation/portable-route-activity.test.mjs +2 -2
- package/dist/federation/portable.test.mjs +3 -3
- package/dist/federation/send.test.mjs +498 -88
- 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 +1 -1
- package/dist/{federation-Dd9IwOEi.cjs → federation-Bkfq2YpS.cjs} +240 -102
- package/dist/{http-DLf8QYD6.cjs → http-DHVH0DqC.cjs} +179 -110
- package/dist/{http-D7L2pqLT.mjs → http-DuGmr8J8.mjs} +204 -106
- package/dist/{http-BVrOR6MG.js → http-R0ty0Udi.js} +178 -109
- package/dist/{inbox-DtEKOr3W.mjs → inbox-Bl1Y0s_A.mjs} +2 -2
- package/dist/{key-DYxuyd-s.d.cts → key-CyCcut3h.d.ts} +1 -2
- package/dist/{key-C1nv7_jD.d.ts → key-VEL1QqHF.d.cts} +1 -2
- package/dist/{kv-cache-Dkzuqs8B.cjs → kv-cache-BtBSBZi9.cjs} +72 -27
- package/dist/{kv-cache-m3RIr811.mjs → kv-cache-DAV2_U44.mjs} +1 -1
- package/dist/{kv-cache-DoZoRS9p.js → kv-cache-FnLtmATH.js} +73 -28
- package/dist/{ld-PJLGA2MJ.mjs → ld-Cy5GqbvS.mjs} +2 -2
- package/dist/{metrics-CGR9cI-Y.mjs → metrics-CW8LoN7n.mjs} +1 -1
- package/dist/{middleware-DPI-Jp9w.mjs → middleware-CdP-lz8Q.mjs} +1 -1
- package/dist/{middleware-ByanhTvb.mjs → middleware-D2fk45uN.mjs} +82 -42
- package/dist/{middleware-BxhBd7pw.js → middleware-D4rQARvq.js} +241 -103
- package/dist/{mod-DEZXwV6J.d.ts → mod-B1Qt5cQQ.d.ts} +2 -9
- package/dist/{mod-Xj5P4s4d.d.ts → mod-B5COx5Wd.d.ts} +1 -1
- package/dist/{mod-CavhAgLw.d.cts → mod-BTxJG7ZH.d.cts} +1 -1
- package/dist/{mod-CtpF2BU5.d.ts → mod-CpyjFA9s.d.ts} +1 -1
- package/dist/{mod-BojP2Bw3.d.cts → mod-makPMVMg.d.cts} +1 -1
- package/dist/{mod-Dw-nPxQh.d.cts → mod-ss0wBUH1.d.cts} +2 -9
- 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-B5c276hH.mjs → owner-CbQZqFim.mjs} +3 -3
- package/dist/{portable-collection-BMZY9qT-.js → portable-collection-B5Aryi8I.js} +1 -1
- package/dist/{portable-collection-CR5uwjws.cjs → portable-collection-C_Kmvl3q.cjs} +1 -1
- package/dist/{portable-collection-C88tBiy0.mjs → portable-collection-D2JYDadi.mjs} +2 -2
- package/dist/{portable-key-DxTXUpCK.mjs → portable-key-Cc-ctNU2.mjs} +1 -1
- package/dist/{proof-DNu-qP0i.mjs → proof-UN4CW55z.mjs} +3 -3
- package/dist/{send-CdCifQs4.mjs → send-BzbX2e6v.mjs} +174 -76
- 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 +2 -2
- package/dist/sig/compound-proof.test.mjs +2 -2
- package/dist/sig/http.test.mjs +553 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +1 -1
- package/dist/sig/mitra-receive-interop.test.mjs +4 -4
- package/dist/sig/mitra-send-interop.test.mjs +3 -3
- 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 +1 -1
- package/dist/sig/portable-collection.test.mjs +1 -1
- package/dist/sig/portable-interop.test.mjs +3 -3
- package/dist/sig/portable-key.test.mjs +5 -5
- package/dist/sig/proof.test.mjs +4 -4
- package/dist/sig/tootik-request-interop.test.mjs +4 -4
- package/dist/sig/tootik-send-interop.test.mjs +3 -3
- package/dist/sig/verification.test.mjs +3 -3
- package/dist/{temporal-BuMu2bgP.mjs → temporal-B7Wvxrjs.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- package/dist/testing/mod.d.mts +26 -0
- package/dist/{types-_S2_MeLF.js → types-DUjZb4i6.js} +112 -63
- package/dist/{types-poIao40f.cjs → types-hKCCjii0.cjs} +111 -62
- package/dist/utils/docloader.test.mjs +344 -36
- package/dist/utils/kv-cache.test.mjs +1 -1
- 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 +7 -7
- package/dist/docloader-DQNRDYDb.mjs +0 -91
package/dist/sig/mod.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { D as createSignature, H as fetchKeyDetailed, I as verifyJsonLd, L as verifySignature, O as detachSignature, P as signJsonLd, T as attachSignature, U as generateCryptoKeyPair, V as fetchKey, W as importJwk, _ as verifyObject, _t as validateAcceptSignature, a as signRequest, c as verifyRequestDetailed, gt as parseAcceptSignature, h as signObject, ht as fulfillAcceptSignature, j as hasSignatureLike, m as hasProofLike, mt as formatAcceptSignature, p as createProof, s as verifyRequest, v as verifyPortableObjectProof, x as verifyProof, z as exportJwk } from "../http-
|
|
4
|
-
import { n as doesActorOwnKey, r as getKeyOwner, t as verifyPortableObject } from "../portable-collection-
|
|
3
|
+
import { D as createSignature, H as fetchKeyDetailed, I as verifyJsonLd, L as verifySignature, O as detachSignature, P as signJsonLd, T as attachSignature, U as generateCryptoKeyPair, V as fetchKey, W as importJwk, _ as verifyObject, _t as validateAcceptSignature, a as signRequest, c as verifyRequestDetailed, gt as parseAcceptSignature, h as signObject, ht as fulfillAcceptSignature, j as hasSignatureLike, m as hasProofLike, mt as formatAcceptSignature, p as createProof, s as verifyRequest, v as verifyPortableObjectProof, x as verifyProof, z as exportJwk } from "../http-R0ty0Udi.js";
|
|
4
|
+
import { n as doesActorOwnKey, r as getKeyOwner, t as verifyPortableObject } from "../portable-collection-B5Aryi8I.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, 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-CbQZqFim.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
|
|
@@ -2,7 +2,7 @@ import "temporal-polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { n as ed25519PrivateKey, r as ed25519PublicKey } from "../keys-DIJNHW-Y.mjs";
|
|
5
|
-
import { t as verifyPortableObject } from "../portable-collection-
|
|
5
|
+
import { t as verifyPortableObject } from "../portable-collection-D2JYDadi.mjs";
|
|
6
6
|
import { Collection, CollectionPage, Note, OrderedCollection, Person, traverseCollection } from "@fedify/vocab";
|
|
7
7
|
import { FetchError, encodeMultibase, exportDidKey, preloadedContexts } from "@fedify/vocab-runtime";
|
|
8
8
|
import { test } from "@fedify/fixture";
|
|
@@ -4,9 +4,9 @@ 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 { c as verifyPortableObjectProof, d as verifyProof } from "../proof-
|
|
8
|
-
import { n as getKeyOwner } from "../owner-
|
|
9
|
-
import { t as verifyPortableObject } from "../portable-collection-
|
|
7
|
+
import { c as verifyPortableObjectProof, d as verifyProof } from "../proof-UN4CW55z.mjs";
|
|
8
|
+
import { n as getKeyOwner } from "../owner-CbQZqFim.mjs";
|
|
9
|
+
import { t as verifyPortableObject } from "../portable-collection-D2JYDadi.mjs";
|
|
10
10
|
import { Application, DataIntegrityProof, lookupObject } from "@fedify/vocab";
|
|
11
11
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
12
12
|
//#region test-vectors/fep-ef61/tootik-v0.25.4/actor.json
|
|
@@ -2,12 +2,12 @@ import { Temporal } from "temporal-polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
5
|
-
import { S as fetchKeyDetailed, h as verifyJsonLd, p as signJsonLd, x as fetchKey } from "../ld-
|
|
6
|
-
import { d as verifyProof, r as createProof } from "../proof-
|
|
7
|
-
import { n as resolvePortableActorKey } from "../portable-key-
|
|
8
|
-
import {
|
|
5
|
+
import { S as fetchKeyDetailed, h as verifyJsonLd, p as signJsonLd, x as fetchKey } from "../ld-Cy5GqbvS.mjs";
|
|
6
|
+
import { d as verifyProof, r as createProof } from "../proof-UN4CW55z.mjs";
|
|
7
|
+
import { n as resolvePortableActorKey } from "../portable-key-Cc-ctNU2.mjs";
|
|
8
|
+
import { m as verifyRequestDetailed, p as verifyRequest, u as signRequest } from "../http-DuGmr8J8.mjs";
|
|
9
9
|
import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
|
|
10
|
-
import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-
|
|
10
|
+
import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-CbQZqFim.mjs";
|
|
11
11
|
import { t as KvKeyCache } from "../keycache-N2opu4-3.mjs";
|
|
12
12
|
import { Create, CryptographicKey, Multikey, Note, Person } from "@fedify/vocab";
|
|
13
13
|
import { FetchError, encodeMultibase, exportDidKey, exportSpki, parseIri, preloadedContexts } from "@fedify/vocab-runtime";
|
package/dist/sig/proof.test.mjs
CHANGED
|
@@ -11,10 +11,10 @@ import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
|
|
|
11
11
|
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
12
12
|
import { a as verificationObservation } from "../verification-Dpfcw8ml.mjs";
|
|
13
13
|
import { r as normalizeOutgoingActivityJsonLd } from "../outgoing-jsonld-4IJqPYos.mjs";
|
|
14
|
-
import { a as signObject, c as verifyPortableObjectProof, d as verifyProof, i as hasProofLike, o as verifyMapLocalProof, r as createProof, s as verifyObject } from "../proof-
|
|
15
|
-
import {
|
|
14
|
+
import { a as signObject, c as verifyPortableObjectProof, d as verifyProof, i as hasProofLike, o as verifyMapLocalProof, r as createProof, s as verifyObject } from "../proof-UN4CW55z.mjs";
|
|
15
|
+
import { p as verifyRequest } from "../http-DuGmr8J8.mjs";
|
|
16
16
|
import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
|
|
17
|
-
import {
|
|
17
|
+
import { n as getAuthenticatedDocumentLoader } from "../docloader-CP1UxMLL.mjs";
|
|
18
18
|
import { Create, DataIntegrityProof, Document, Multikey, Note, PUBLIC_COLLECTION, Place, Translation } from "@fedify/vocab";
|
|
19
19
|
import { decodeMultibase, encodeMultibase, exportDidKey, exportMultibaseKey, formatIri, importMultibaseKey, parseIri } from "@fedify/vocab-runtime";
|
|
20
20
|
import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
@@ -2451,7 +2451,7 @@ test("getAuthenticatedDocumentLoader() signs portable object requests to gateway
|
|
|
2451
2451
|
documentLoader: getAuthenticatedDocumentLoader({
|
|
2452
2452
|
keyId: new URL("https://example.com/key2"),
|
|
2453
2453
|
privateKey: rsaPrivateKey2
|
|
2454
|
-
}),
|
|
2454
|
+
}, { allowPrivateAddress: true }),
|
|
2455
2455
|
contextLoader: mockDocumentLoader,
|
|
2456
2456
|
gateways: ["https://example.com"],
|
|
2457
2457
|
verifyPortableObject: verifyPortableObjectProof
|
|
@@ -5,10 +5,10 @@ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
6
6
|
import "../std__assert-DvMDRPes.mjs";
|
|
7
7
|
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
8
|
-
import { c as verifyPortableObjectProof } from "../proof-
|
|
9
|
-
import {
|
|
10
|
-
import { o as createFederation } from "../middleware-
|
|
11
|
-
import { t as doesActorOwnKey } from "../owner-
|
|
8
|
+
import { c as verifyPortableObjectProof } from "../proof-UN4CW55z.mjs";
|
|
9
|
+
import { m as verifyRequestDetailed } from "../http-DuGmr8J8.mjs";
|
|
10
|
+
import { o as createFederation } from "../middleware-D2fk45uN.mjs";
|
|
11
|
+
import { t as doesActorOwnKey } from "../owner-CbQZqFim.mjs";
|
|
12
12
|
import { Follow, Person } from "@fedify/vocab";
|
|
13
13
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
14
14
|
import { encodeHex } from "byte-encodings/hex";
|
|
@@ -4,9 +4,9 @@ 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 { c as verifyPortableObjectProof } from "../proof-
|
|
8
|
-
import {
|
|
9
|
-
import { t as doesActorOwnKey } from "../owner-
|
|
7
|
+
import { c as verifyPortableObjectProof } from "../proof-UN4CW55z.mjs";
|
|
8
|
+
import { m as verifyRequestDetailed } from "../http-DuGmr8J8.mjs";
|
|
9
|
+
import { t as doesActorOwnKey } from "../owner-CbQZqFim.mjs";
|
|
10
10
|
import { Create } from "@fedify/vocab";
|
|
11
11
|
import { decodeMultibase, importDidKey } from "@fedify/vocab-runtime";
|
|
12
12
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
@@ -2,9 +2,9 @@ import "temporal-polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { a as verificationObservation } from "../verification-Dpfcw8ml.mjs";
|
|
5
|
-
import { h as verifyJsonLd, p as signJsonLd } from "../ld-
|
|
6
|
-
import { a as signObject, s as verifyObject } from "../proof-
|
|
7
|
-
import {
|
|
5
|
+
import { h as verifyJsonLd, p as signJsonLd } from "../ld-Cy5GqbvS.mjs";
|
|
6
|
+
import { a as signObject, s as verifyObject } from "../proof-UN4CW55z.mjs";
|
|
7
|
+
import { m as verifyRequestDetailed, u as signRequest } from "../http-DuGmr8J8.mjs";
|
|
8
8
|
import { i as rsaPrivateKey2, n as ed25519PrivateKey, o as rsaPublicKey1, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
|
|
9
9
|
import { Activity, Create, CryptographicKey, Multikey } from "@fedify/vocab";
|
|
10
10
|
import { FetchError } from "@fedify/vocab-runtime";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "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-Cy5GqbvS.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/kv.test.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
|
6
6
|
import { t as ManualClockKvStore } from "../kv-DBRWVx3Q.mjs";
|
|
7
7
|
import { n as baseOptions, o as stringSchema, t as MockQueue } from "../tasks-IG3pHfvZ.mjs";
|
|
8
8
|
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
9
|
-
import { o as createFederation } from "../middleware-
|
|
9
|
+
import { o as createFederation } from "../middleware-D2fk45uN.mjs";
|
|
10
10
|
//#region src/testing/kv.test.ts
|
|
11
11
|
test("ManualClockKvStore keeps an entry at its exact expiration instant", async () => {
|
|
12
12
|
const kv = new ManualClockKvStore();
|
package/dist/testing/mod.d.mts
CHANGED
|
@@ -4429,6 +4429,11 @@ interface RequestContext<TContextData> extends Context<TContextData> {
|
|
|
4429
4429
|
* Gets the public key of the sender, if any exists and it is verified.
|
|
4430
4430
|
* Otherwise, `null` is returned.
|
|
4431
4431
|
*
|
|
4432
|
+
* Successful results are reused for this request regardless of the options.
|
|
4433
|
+
* Pending checks and `null` results are reused for the same effective
|
|
4434
|
+
* document and context loaders, including failed lookups. Rejected checks
|
|
4435
|
+
* can be retried. Shared work uses the first caller's tracer provider.
|
|
4436
|
+
*
|
|
4432
4437
|
* This can be used for implementing [authorized fetch] (also known as
|
|
4433
4438
|
* secure mode) in ActivityPub.
|
|
4434
4439
|
*
|
|
@@ -4442,6 +4447,11 @@ interface RequestContext<TContextData> extends Context<TContextData> {
|
|
|
4442
4447
|
* Gets the public key of the sender, if any exists and it is verified.
|
|
4443
4448
|
* Otherwise, `null` is returned.
|
|
4444
4449
|
*
|
|
4450
|
+
* Successful results are reused for this request regardless of the options.
|
|
4451
|
+
* Pending checks and `null` results are reused for the same effective
|
|
4452
|
+
* document and context loaders, including failed lookups. Rejected checks
|
|
4453
|
+
* can be retried. Shared work uses the first caller's tracer provider.
|
|
4454
|
+
*
|
|
4445
4455
|
* This can be used for implementing [authorized fetch] (also known as
|
|
4446
4456
|
* secure mode) in ActivityPub.
|
|
4447
4457
|
*
|
|
@@ -4461,6 +4471,14 @@ interface RequestContext<TContextData> extends Context<TContextData> {
|
|
|
4461
4471
|
* Gets the owner of the signed key, if any exists and it is verified.
|
|
4462
4472
|
* Otherwise, `null` is returned.
|
|
4463
4473
|
*
|
|
4474
|
+
* Verified keys and owners are reused for this request regardless of the
|
|
4475
|
+
* options. Pending checks are shared for the same effective document and
|
|
4476
|
+
* context loaders. A `null` result from an owner lookup after key
|
|
4477
|
+
* verification is retained for those loaders. A `null` result caused by
|
|
4478
|
+
* an unverified key is not retained, allowing an owner lookup after another
|
|
4479
|
+
* loader verifies the key. Rejected checks can be retried. Shared work
|
|
4480
|
+
* uses the first caller's tracer provider.
|
|
4481
|
+
*
|
|
4464
4482
|
* This can be used for implementing [authorized fetch] (also known as
|
|
4465
4483
|
* secure mode) in ActivityPub.
|
|
4466
4484
|
*
|
|
@@ -4475,6 +4493,14 @@ interface RequestContext<TContextData> extends Context<TContextData> {
|
|
|
4475
4493
|
* Gets the owner of the signed key, if any exists and it is verified.
|
|
4476
4494
|
* Otherwise, `null` is returned.
|
|
4477
4495
|
*
|
|
4496
|
+
* Verified keys and owners are reused for this request regardless of the
|
|
4497
|
+
* options. Pending checks are shared for the same effective document and
|
|
4498
|
+
* context loaders. A `null` result from an owner lookup after key
|
|
4499
|
+
* verification is retained for those loaders. A `null` result caused by
|
|
4500
|
+
* an unverified key is not retained, allowing an owner lookup after another
|
|
4501
|
+
* loader verifies the key. Rejected checks can be retried. Shared work
|
|
4502
|
+
* uses the first caller's tracer provider.
|
|
4503
|
+
*
|
|
4478
4504
|
* This can be used for implementing [authorized fetch] (also known as
|
|
4479
4505
|
* secure mode) in ActivityPub.
|
|
4480
4506
|
*
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
import { getLogger } from "@logtape/logtape";
|
|
4
|
-
import { FetchError, UrlError, getUserAgent
|
|
4
|
+
import { FetchError, UrlError, getUserAgent } from "@fedify/vocab-runtime";
|
|
5
|
+
import { openPublicFetch } from "@fedify/vocab-runtime/internal";
|
|
5
6
|
//#region src/utils/body.ts
|
|
6
7
|
/** Decoded JSON body limit: 16 MiB. @internal */
|
|
7
8
|
const MAX_BODY_SIZE = 16 * 1024 * 1024;
|
|
@@ -84,23 +85,34 @@ const logger = getLogger([
|
|
|
84
85
|
]);
|
|
85
86
|
const DEFAULT_MAX_REDIRECTION = 5;
|
|
86
87
|
/**
|
|
87
|
-
* Fetches a URL while guarding against SSRF.
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* bounce the request to an internal
|
|
88
|
+
* Fetches a URL while guarding against SSRF. Every request—including each
|
|
89
|
+
* redirect hop—is made in its own session opened with `openPublicFetch()`,
|
|
90
|
+
* which rejects loopback, link-local, and private addresses, as well as
|
|
91
|
+
* non-HTTP(S) schemes such as `data:`, and connects only to the validated
|
|
92
|
+
* addresses where the runtime supports it. Redirects are followed manually
|
|
93
|
+
* with a cap, so that a public URL cannot bounce the request to an internal
|
|
94
|
+
* address.
|
|
95
|
+
*
|
|
96
|
+
* The final response is passed to `consume`, which must consume or cancel its
|
|
97
|
+
* body; the session is closed after `consume` settles. The cancellation of
|
|
98
|
+
* redirect response bodies is started before their sessions are closed.
|
|
93
99
|
* @param url The URL to fetch.
|
|
94
100
|
* @param headers The request headers.
|
|
95
|
-
* @
|
|
96
|
-
*
|
|
101
|
+
* @param consume The function to consume the final response with.
|
|
102
|
+
* @param deps The dependencies.
|
|
103
|
+
* @returns The value returned by `consume`, or `null` if the URL is
|
|
104
|
+
* disallowed, its hostname cannot be resolved, or there are too many
|
|
105
|
+
* redirects.
|
|
106
|
+
* @internal
|
|
97
107
|
*/
|
|
98
|
-
async function fetchPublicUrl(url, headers) {
|
|
108
|
+
async function fetchPublicUrl(url, headers, consume, deps = {}) {
|
|
109
|
+
const openHop = deps.openHop ?? ((hopUrl) => openPublicFetch(hopUrl));
|
|
99
110
|
let current = url instanceof URL ? url : new URL(url);
|
|
100
111
|
let redirected = 0;
|
|
101
112
|
while (true) {
|
|
113
|
+
let session;
|
|
102
114
|
try {
|
|
103
|
-
await
|
|
115
|
+
session = await openHop(current.href);
|
|
104
116
|
} catch (e) {
|
|
105
117
|
if (e instanceof UrlError) {
|
|
106
118
|
if (e.reason === "dns") logger.error("DNS lookup failed for {url}: {error}", {
|
|
@@ -115,52 +127,89 @@ async function fetchPublicUrl(url, headers) {
|
|
|
115
127
|
}
|
|
116
128
|
throw e;
|
|
117
129
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
130
|
+
let location;
|
|
131
|
+
try {
|
|
132
|
+
const response = await session.fetch(current, {
|
|
133
|
+
headers,
|
|
134
|
+
redirect: "manual"
|
|
135
|
+
});
|
|
136
|
+
if (response.status < 300 || response.status >= 400 || !response.headers.has("Location")) return await consume(response);
|
|
137
|
+
location = response.headers.get("Location");
|
|
138
|
+
cancelBody(response, current);
|
|
139
|
+
} finally {
|
|
140
|
+
await session.close();
|
|
141
|
+
}
|
|
142
|
+
redirected++;
|
|
143
|
+
if (redirected >= DEFAULT_MAX_REDIRECTION) {
|
|
144
|
+
logger.error("Too many redirections ({redirections}) while fetching {url}.", {
|
|
145
|
+
redirections: redirected,
|
|
146
|
+
url: current.href
|
|
147
|
+
});
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
const next = new URL(location, current);
|
|
151
|
+
if (next.protocol !== current.protocol) {
|
|
152
|
+
logger.error("Refused a redirect to a different protocol ({protocol} to {redirectedProtocol}) while fetching NodeInfo.", {
|
|
153
|
+
protocol: current.protocol,
|
|
154
|
+
redirectedProtocol: next.protocol
|
|
155
|
+
});
|
|
156
|
+
return null;
|
|
141
157
|
}
|
|
142
|
-
|
|
158
|
+
current = next;
|
|
143
159
|
}
|
|
144
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* Starts cancelling a response body that is not read, without waiting for it
|
|
163
|
+
* to settle. The cancellation of a branch of a tee (e.g., a body cloned by
|
|
164
|
+
* a fetch mock) settles only after the other branch is cancelled too, per
|
|
165
|
+
* the Streams standard, so awaiting it could block forever. A failure is
|
|
166
|
+
* only logged.
|
|
167
|
+
*/
|
|
168
|
+
function cancelBody(response, url) {
|
|
169
|
+
response.body?.cancel().catch((error) => {
|
|
170
|
+
logger.debug("Failed to cancel the response body from {url}: {error}", {
|
|
171
|
+
url: url.toString(),
|
|
172
|
+
error
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}
|
|
145
176
|
async function getNodeInfo(url, options = {}) {
|
|
177
|
+
return await getNodeInfoInternal(url, options);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The implementation of {@link getNodeInfo}, which is not exported from any
|
|
181
|
+
* entry point.
|
|
182
|
+
* @param url The base URL of the server, or the URL of the NodeInfo document
|
|
183
|
+
* if `options.direct` is turned on.
|
|
184
|
+
* @param options Options for fetching the NodeInfo document.
|
|
185
|
+
* @param deps The dependencies.
|
|
186
|
+
* @returns The NodeInfo document if it could be fetched successfully.
|
|
187
|
+
* Otherwise, `undefined` is returned.
|
|
188
|
+
* @internal
|
|
189
|
+
*/
|
|
190
|
+
async function getNodeInfoInternal(url, options = {}, deps = {}) {
|
|
146
191
|
try {
|
|
192
|
+
const headers = {
|
|
193
|
+
Accept: "application/json",
|
|
194
|
+
"User-Agent": typeof options.userAgent === "string" ? options.userAgent : getUserAgent(options.userAgent)
|
|
195
|
+
};
|
|
147
196
|
let nodeInfoUrl = url;
|
|
148
197
|
if (!options.direct) {
|
|
149
198
|
const wellKnownUrl = new URL("/.well-known/nodeinfo", url);
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const wellKnownRd =
|
|
199
|
+
const wellKnown = await fetchPublicUrl(wellKnownUrl, headers, async (response) => {
|
|
200
|
+
if (!response.ok) {
|
|
201
|
+
logger.error("Failed to fetch {url}: {status} {statusText}", {
|
|
202
|
+
url: wellKnownUrl.href,
|
|
203
|
+
status: response.status,
|
|
204
|
+
statusText: response.statusText
|
|
205
|
+
});
|
|
206
|
+
cancelBody(response, wellKnownUrl);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
return { rd: JSON.parse(await readBoundedText(response, MAX_BODY_SIZE, wellKnownUrl)) };
|
|
210
|
+
}, deps);
|
|
211
|
+
if (wellKnown == null) return void 0;
|
|
212
|
+
const wellKnownRd = wellKnown.rd;
|
|
164
213
|
const link = wellKnownRd?.links?.find((link) => link != null && "rel" in link && (link.rel === "http://nodeinfo.diaspora.software/ns/schema/2.0" || link.rel === "http://nodeinfo.diaspora.software/ns/schema/2.1") && "href" in link && link.href != null);
|
|
165
214
|
if (link == null || link.href == null) {
|
|
166
215
|
logger.error("Failed to find a NodeInfo document link from {url}: {resourceDescriptor}", {
|
|
@@ -171,20 +220,20 @@ async function getNodeInfo(url, options = {}) {
|
|
|
171
220
|
}
|
|
172
221
|
nodeInfoUrl = link.href;
|
|
173
222
|
}
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const data =
|
|
223
|
+
const document = await fetchPublicUrl(nodeInfoUrl, headers, async (response) => {
|
|
224
|
+
if (!response.ok) {
|
|
225
|
+
logger.error("Failed to fetch NodeInfo document from {url}: {status} {statusText}", {
|
|
226
|
+
url: nodeInfoUrl.toString(),
|
|
227
|
+
status: response.status,
|
|
228
|
+
statusText: response.statusText
|
|
229
|
+
});
|
|
230
|
+
cancelBody(response, nodeInfoUrl);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
return { data: JSON.parse(await readBoundedText(response, MAX_BODY_SIZE, nodeInfoUrl)) };
|
|
234
|
+
}, deps);
|
|
235
|
+
if (document == null) return void 0;
|
|
236
|
+
const { data } = document;
|
|
188
237
|
if (options.parse === "none") return data;
|
|
189
238
|
return parseNodeInfo(data, { tryBestEffort: options.parse === "best-effort" }) ?? void 0;
|
|
190
239
|
} catch (error) {
|