@fedify/fedify 2.2.19 → 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-UmydCxtK.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-CD-8UlUi.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/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-DJK2udgX.js → http-C5g_VrA_.js} +172 -103
- package/dist/{http-BBBUbwKh.mjs → http-CQMVisM0.mjs} +195 -97
- package/dist/{http-DrUG4fPS.cjs → http-D8I7LBfx.cjs} +173 -104
- package/dist/{http-DqZhyEso.d.cts → http-SbfezERn.d.ts} +1 -2
- package/dist/{inbox-Dca_0fwc.mjs → inbox-CD8IDILN.mjs} +1 -1
- package/dist/{key-DolXUaLH.mjs → key-C3o3DGap.mjs} +1 -1
- package/dist/{kv-cache-DDm80t1K.js → kv-cache-CSKXXleR.js} +60 -18
- package/dist/{kv-cache-Bk3V1Tiu.cjs → kv-cache-DC9LcfoC.cjs} +59 -17
- package/dist/{ld-rTdIfZ63.mjs → ld-ijSr-0AB.mjs} +2 -2
- package/dist/{middleware-CpXoRHs3.mjs → middleware-CYAaUTi5.mjs} +78 -38
- package/dist/{middleware-BWOwEGpy.cjs → middleware-DNueR0GD.cjs} +184 -59
- package/dist/{middleware-B4-Rzdi3.cjs → middleware-DmcY2TWS.cjs} +1 -1
- package/dist/{middleware-BimXKBcP.js → middleware-sjhz30sm.js} +184 -59
- package/dist/{middleware-DYK_res8.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-CVfzyM5V.mjs → owner-B8kXzD0q.mjs} +2 -2
- package/dist/{proof-gOGM-sJS.mjs → proof-CBQOjOgA.mjs} +2 -2
- package/dist/{proof-CaQ4KG6y.js → proof-DKX6nASL.js} +1 -1
- package/dist/{proof-DhaTTn-P.cjs → proof-qiuGJCD7.cjs} +1 -1
- package/dist/{send-D35Va72B.mjs → send-DRpisX_f.mjs} +117 -32
- package/dist/sig/http.test.mjs +528 -2
- package/dist/sig/key.test.mjs +2 -2
- package/dist/sig/ld.test.mjs +2 -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 +1 -1
- package/dist/sig/proof.test.mjs +1 -1
- package/dist/{temporal-CA4Y9hBJ.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 +318 -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-D1ghurDJ.mjs +0 -83
|
@@ -2,26 +2,26 @@ import { Temporal } from "@js-temporal/polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { n as RouterError } from "./router-CrMLXoOr.mjs";
|
|
5
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
+
import { n as version, t as name } from "./deno-BUj4roJc.mjs";
|
|
6
6
|
import { t as formatAcceptSignature } from "./accept-Dd__NiUL.mjs";
|
|
7
|
-
import { o as importJwk, s as validateCryptoKey, t as exportJwk } from "./key-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { o as importJwk, s as validateCryptoKey, t as exportJwk } from "./key-C3o3DGap.mjs";
|
|
8
|
+
import { d as verifyRequestDetailed, s as parseRfc9421SignatureInput, u as verifyRequest } from "./http-CQMVisM0.mjs";
|
|
9
|
+
import { n as getAuthenticatedDocumentLoader } from "./docloader-CbtF_0cD.mjs";
|
|
10
10
|
import { n as kvCache } from "./kv-cache-FsT1ljhs.mjs";
|
|
11
11
|
import { t as KvKeyCache } from "./keycache-BimEQucx.mjs";
|
|
12
|
-
import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-
|
|
13
|
-
import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-
|
|
12
|
+
import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-ijSr-0AB.mjs";
|
|
13
|
+
import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-B8kXzD0q.mjs";
|
|
14
14
|
import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-amccRMrV.mjs";
|
|
15
|
-
import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-
|
|
16
|
-
import { d as
|
|
15
|
+
import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-CBQOjOgA.mjs";
|
|
16
|
+
import { d as MAX_BODY_SIZE, f as readBoundedText, t as getNodeInfo, u as BodyTooLargeError } from "./client-DhxaVgOv.mjs";
|
|
17
17
|
import { t as nodeInfoToJson } from "./types-J53Kw7so.mjs";
|
|
18
|
-
import { t as FederationBuilderImpl } from "./builder-
|
|
18
|
+
import { t as FederationBuilderImpl } from "./builder-BolQ56ab.mjs";
|
|
19
19
|
import { t as buildCollectionSynchronizationHeader } from "./collection-D-HqUuA2.mjs";
|
|
20
|
-
import { n as routeActivity, t as actorsHaveSameOrigin } from "./inbox-
|
|
20
|
+
import { n as routeActivity, t as actorsHaveSameOrigin } from "./inbox-CD8IDILN.mjs";
|
|
21
21
|
import { t as acceptsJsonLd } from "./negotiation-SQvQgUqe.mjs";
|
|
22
|
-
import { t as hasMalformedKnownTemporalLiteral } from "./temporal-
|
|
22
|
+
import { t as hasMalformedKnownTemporalLiteral } from "./temporal-BQGEINad.mjs";
|
|
23
23
|
import { t as createExponentialBackoffPolicy } from "./retry-v_sGLH1d.mjs";
|
|
24
|
-
import {
|
|
24
|
+
import { i as sendActivity, n as extractInboxes, t as SendActivityError } from "./send-DRpisX_f.mjs";
|
|
25
25
|
import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, Tombstone, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
|
|
26
26
|
import { lookupWebFinger } from "@fedify/webfinger";
|
|
27
27
|
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
@@ -3539,43 +3539,83 @@ var RequestContextImpl = class RequestContextImpl extends ContextImpl {
|
|
|
3539
3539
|
}
|
|
3540
3540
|
}), values);
|
|
3541
3541
|
}
|
|
3542
|
-
#signedKey =
|
|
3542
|
+
#signedKey = null;
|
|
3543
|
+
#signedKeyOwner = null;
|
|
3544
|
+
#signatureChecks = /* @__PURE__ */ new WeakMap();
|
|
3545
|
+
#getSignatureCheck(documentLoader, contextLoader) {
|
|
3546
|
+
let checks = this.#signatureChecks.get(documentLoader);
|
|
3547
|
+
if (checks == null) {
|
|
3548
|
+
checks = /* @__PURE__ */ new WeakMap();
|
|
3549
|
+
this.#signatureChecks.set(documentLoader, checks);
|
|
3550
|
+
}
|
|
3551
|
+
let check = checks.get(contextLoader);
|
|
3552
|
+
if (check == null) {
|
|
3553
|
+
check = {};
|
|
3554
|
+
checks.set(contextLoader, check);
|
|
3555
|
+
}
|
|
3556
|
+
return check;
|
|
3557
|
+
}
|
|
3543
3558
|
async getSignedKey(options = {}) {
|
|
3544
3559
|
if (this.#signedKey != null) return this.#signedKey;
|
|
3545
|
-
|
|
3560
|
+
const documentLoader = options.documentLoader ?? this.documentLoader;
|
|
3561
|
+
const contextLoader = options.contextLoader ?? this.contextLoader;
|
|
3562
|
+
const check = this.#getSignatureCheck(documentLoader, contextLoader);
|
|
3563
|
+
if (check.key != null) return check.key;
|
|
3564
|
+
const promise = verifyRequest(this.request, {
|
|
3546
3565
|
...this,
|
|
3547
|
-
contextLoader
|
|
3548
|
-
documentLoader
|
|
3566
|
+
contextLoader,
|
|
3567
|
+
documentLoader,
|
|
3549
3568
|
timeWindow: this.federation.signatureTimeWindow,
|
|
3550
3569
|
tracerProvider: options.tracerProvider ?? this.tracerProvider
|
|
3570
|
+
}).then((key) => {
|
|
3571
|
+
if (key != null) this.#signedKey ??= key;
|
|
3572
|
+
return key;
|
|
3573
|
+
}).catch((error) => {
|
|
3574
|
+
if (check.key === promise) check.key = void 0;
|
|
3575
|
+
throw error;
|
|
3551
3576
|
});
|
|
3577
|
+
check.key = promise;
|
|
3578
|
+
return await promise;
|
|
3552
3579
|
}
|
|
3553
|
-
#signedKeyOwner = void 0;
|
|
3554
3580
|
async getSignedKeyOwner(options = {}) {
|
|
3555
3581
|
if (this.#signedKeyOwner != null) return this.#signedKeyOwner;
|
|
3556
|
-
const
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
"fedify",
|
|
3568
|
-
"federation",
|
|
3569
|
-
"actor"
|
|
3570
|
-
]).warn("Failed to fetch the key owner {keyOwner} of {keyId} while verifying the request signature; treating the request as unauthenticated: {error}", {
|
|
3571
|
-
keyId: key.id?.href,
|
|
3572
|
-
keyOwner: error.url.href,
|
|
3573
|
-
error
|
|
3574
|
-
});
|
|
3575
|
-
return this.#signedKeyOwner = null;
|
|
3582
|
+
const normalizedOptions = {
|
|
3583
|
+
documentLoader: options.documentLoader ?? this.documentLoader,
|
|
3584
|
+
contextLoader: options.contextLoader ?? this.contextLoader,
|
|
3585
|
+
tracerProvider: options.tracerProvider ?? this.tracerProvider
|
|
3586
|
+
};
|
|
3587
|
+
const check = this.#getSignatureCheck(normalizedOptions.documentLoader, normalizedOptions.contextLoader);
|
|
3588
|
+
if (check.owner != null) return check.owner;
|
|
3589
|
+
const promise = this.getSignedKey(normalizedOptions).then(async (key) => {
|
|
3590
|
+
if (key == null) {
|
|
3591
|
+
if (check.owner === promise) check.owner = void 0;
|
|
3592
|
+
return null;
|
|
3576
3593
|
}
|
|
3594
|
+
try {
|
|
3595
|
+
const owner = await getKeyOwner(key, normalizedOptions);
|
|
3596
|
+
if (owner != null) this.#signedKeyOwner ??= owner;
|
|
3597
|
+
return owner;
|
|
3598
|
+
} catch (error) {
|
|
3599
|
+
if (error instanceof FetchError) {
|
|
3600
|
+
getLogger([
|
|
3601
|
+
"fedify",
|
|
3602
|
+
"federation",
|
|
3603
|
+
"actor"
|
|
3604
|
+
]).warn("Failed to fetch the key owner {keyOwner} of {keyId} while verifying the request signature; treating the request as unauthenticated: {error}", {
|
|
3605
|
+
keyId: key.id?.href,
|
|
3606
|
+
keyOwner: error.url.href,
|
|
3607
|
+
error
|
|
3608
|
+
});
|
|
3609
|
+
return null;
|
|
3610
|
+
}
|
|
3611
|
+
throw error;
|
|
3612
|
+
}
|
|
3613
|
+
}).catch((error) => {
|
|
3614
|
+
if (check.owner === promise) check.owner = void 0;
|
|
3577
3615
|
throw error;
|
|
3578
|
-
}
|
|
3616
|
+
});
|
|
3617
|
+
check.owner = promise;
|
|
3618
|
+
return await promise;
|
|
3579
3619
|
}
|
|
3580
3620
|
};
|
|
3581
3621
|
function forwardActivity(ctx, loggerCategory, forwarder, recipients, options) {
|
|
@@ -2,10 +2,10 @@ const { Temporal } = require("@js-temporal/polyfill");
|
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
3
|
const require_chunk = require("./chunk-DDcVe30Y.cjs");
|
|
4
4
|
const require_transformers = require("./transformers-NeAONrAq.cjs");
|
|
5
|
-
const require_http = require("./http-
|
|
6
|
-
const require_types = require("./types-
|
|
7
|
-
const require_proof = require("./proof-
|
|
8
|
-
const require_kv_cache = require("./kv-cache-
|
|
5
|
+
const require_http = require("./http-D8I7LBfx.cjs");
|
|
6
|
+
const require_types = require("./types-DOvyymM4.cjs");
|
|
7
|
+
const require_proof = require("./proof-qiuGJCD7.cjs");
|
|
8
|
+
const require_kv_cache = require("./kv-cache-DC9LcfoC.cjs");
|
|
9
9
|
let _logtape_logtape = require("@logtape/logtape");
|
|
10
10
|
let _fedify_vocab = require("@fedify/vocab");
|
|
11
11
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
@@ -18,6 +18,7 @@ let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conve
|
|
|
18
18
|
let _fedify_vocab_runtime_jsonld = require("@fedify/vocab-runtime/jsonld");
|
|
19
19
|
_fedify_vocab_runtime_jsonld = require_chunk.__toESM(_fedify_vocab_runtime_jsonld);
|
|
20
20
|
let _fedify_webfinger = require("@fedify/webfinger");
|
|
21
|
+
let _fedify_vocab_runtime_internal = require("@fedify/vocab-runtime/internal");
|
|
21
22
|
let node_url = require("node:url");
|
|
22
23
|
//#region src/federation/activity-listener.ts
|
|
23
24
|
var ActivityListenerSet = class {
|
|
@@ -213,7 +214,7 @@ var FederationBuilderImpl = class {
|
|
|
213
214
|
this.collectionTypeIds = {};
|
|
214
215
|
}
|
|
215
216
|
async build(options) {
|
|
216
|
-
const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-
|
|
217
|
+
const { FederationImpl } = await Promise.resolve().then(() => require("./middleware-DmcY2TWS.cjs"));
|
|
217
218
|
const f = new FederationImpl(options);
|
|
218
219
|
const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
|
|
219
220
|
f.router = this.router.clone();
|
|
@@ -2738,9 +2739,10 @@ function extractInboxes({ recipients, preferSharedInbox, excludeBaseUris }) {
|
|
|
2738
2739
|
*
|
|
2739
2740
|
* @param parameters The parameters for sending the activity.
|
|
2740
2741
|
* See also {@link SendActivityParameters}.
|
|
2742
|
+
* @param deps The dependencies, for tests.
|
|
2741
2743
|
* @throws {Error} If the activity fails to send.
|
|
2742
2744
|
*/
|
|
2743
|
-
function sendActivity(options) {
|
|
2745
|
+
function sendActivity(options, deps = {}) {
|
|
2744
2746
|
const tracerProvider = options.tracerProvider ?? _opentelemetry_api.trace.getTracerProvider();
|
|
2745
2747
|
return tracerProvider.getTracer(require_http.name, require_http.version).startActiveSpan("activitypub.send_activity", {
|
|
2746
2748
|
kind: _opentelemetry_api.SpanKind.CLIENT,
|
|
@@ -2752,7 +2754,7 @@ function sendActivity(options) {
|
|
|
2752
2754
|
await sendActivityInternal({
|
|
2753
2755
|
...options,
|
|
2754
2756
|
tracerProvider
|
|
2755
|
-
}, span);
|
|
2757
|
+
}, span, deps);
|
|
2756
2758
|
} catch (e) {
|
|
2757
2759
|
span.setStatus({
|
|
2758
2760
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
@@ -2786,21 +2788,25 @@ async function readLimitedResponseBody(response, maxBytes) {
|
|
|
2786
2788
|
totalBytes += value.length;
|
|
2787
2789
|
}
|
|
2788
2790
|
} finally {
|
|
2791
|
+
if (truncated) reader.cancel().catch(() => {});
|
|
2789
2792
|
reader.releaseLock();
|
|
2790
2793
|
}
|
|
2791
2794
|
let result = chunks.join("");
|
|
2792
2795
|
if (truncated) result += "… (truncated)";
|
|
2793
2796
|
return result;
|
|
2794
2797
|
}
|
|
2795
|
-
async function sendActivityInternal({ activity, activityId, keys, inbox, allowPrivateAddress, headers, specDeterminer, tracerProvider }, span) {
|
|
2798
|
+
async function sendActivityInternal({ activity, activityId, keys, inbox, allowPrivateAddress, headers, specDeterminer, tracerProvider }, span, deps) {
|
|
2796
2799
|
const logger = (0, _logtape_logtape.getLogger)([
|
|
2797
2800
|
"fedify",
|
|
2798
2801
|
"federation",
|
|
2799
2802
|
"outbox"
|
|
2800
2803
|
]);
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
+
const openUnvalidatedHop = deps.openHop ?? (allowPrivateAddress ? _fedify_vocab_runtime_internal.openDirectFetch : (url) => (0, _fedify_vocab_runtime_internal.openPublicFetch)(url));
|
|
2805
|
+
let opened = false;
|
|
2806
|
+
async function openHop(url) {
|
|
2807
|
+
let session;
|
|
2808
|
+
try {
|
|
2809
|
+
session = await openUnvalidatedHop(url);
|
|
2804
2810
|
} catch (error) {
|
|
2805
2811
|
if (error instanceof _fedify_vocab_runtime.UrlError && error.reason === "dns") {
|
|
2806
2812
|
logger.error("DNS resolution failed for URL: {url}", {
|
|
@@ -2817,8 +2823,9 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, allowPr
|
|
|
2817
2823
|
});
|
|
2818
2824
|
throw error;
|
|
2819
2825
|
}
|
|
2826
|
+
opened = true;
|
|
2827
|
+
return session;
|
|
2820
2828
|
}
|
|
2821
|
-
await validateUrl(inbox.href);
|
|
2822
2829
|
headers = new Headers(headers);
|
|
2823
2830
|
headers.set("Content-Type", "application/activity+json");
|
|
2824
2831
|
const request = new Request(inbox, {
|
|
@@ -2839,36 +2846,30 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, allowPr
|
|
|
2839
2846
|
privateKey: pair.privateKey
|
|
2840
2847
|
}))
|
|
2841
2848
|
});
|
|
2842
|
-
let
|
|
2849
|
+
let outcome;
|
|
2843
2850
|
try {
|
|
2844
|
-
|
|
2851
|
+
outcome = rsaKey == null ? await fetchWithValidatedRedirects(request, openHop, (response) => consumeSendActivityResponse(response, inbox)) : await require_http.doubleKnockScoped(request, rsaKey, {
|
|
2845
2852
|
tracerProvider,
|
|
2846
|
-
specDeterminer
|
|
2847
|
-
|
|
2848
|
-
});
|
|
2853
|
+
specDeterminer
|
|
2854
|
+
}, openHop, (response) => consumeSendActivityResponse(response, inbox));
|
|
2849
2855
|
} catch (error) {
|
|
2850
|
-
logger.error("Failed to send activity {activityId} to {inbox}:\n{error}", {
|
|
2856
|
+
if (opened) logger.error("Failed to send activity {activityId} to {inbox}:\n{error}", {
|
|
2851
2857
|
activityId,
|
|
2852
2858
|
inbox: inbox.href,
|
|
2853
2859
|
error
|
|
2854
2860
|
});
|
|
2855
2861
|
throw error;
|
|
2856
2862
|
}
|
|
2857
|
-
if (!
|
|
2858
|
-
|
|
2859
|
-
try {
|
|
2860
|
-
error = await readLimitedResponseBody(response, MAX_ERROR_RESPONSE_BODY_BYTES);
|
|
2861
|
-
} catch (_) {
|
|
2862
|
-
error = "";
|
|
2863
|
-
}
|
|
2863
|
+
if (!outcome.ok) {
|
|
2864
|
+
const { status, statusText, error } = outcome;
|
|
2864
2865
|
logger.error("Failed to send activity {activityId} to {inbox} ({status} {statusText}):\n{error}", {
|
|
2865
2866
|
activityId,
|
|
2866
2867
|
inbox: inbox.href,
|
|
2867
|
-
status
|
|
2868
|
-
statusText
|
|
2868
|
+
status,
|
|
2869
|
+
statusText,
|
|
2869
2870
|
error
|
|
2870
2871
|
});
|
|
2871
|
-
throw new SendActivityError(inbox,
|
|
2872
|
+
throw new SendActivityError(inbox, status, `Failed to send activity ${activityId} to ${inbox.href} (${status} ${statusText}):\n${error}`, error);
|
|
2872
2873
|
}
|
|
2873
2874
|
span.addEvent("activitypub.activity.sent", {
|
|
2874
2875
|
"activitypub.activity.json": JSON.stringify(activity),
|
|
@@ -2876,10 +2877,74 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, allowPr
|
|
|
2876
2877
|
"activitypub.activity.id": activityId ?? ""
|
|
2877
2878
|
});
|
|
2878
2879
|
}
|
|
2879
|
-
|
|
2880
|
+
/**
|
|
2881
|
+
* Starts cancelling the body of a response without waiting for it to settle.
|
|
2882
|
+
* The cancellation of a branch of a tee (e.g., a body cloned by a fetch mock)
|
|
2883
|
+
* settles only after the other branch is cancelled too, per the Streams
|
|
2884
|
+
* standard, so awaiting it could block forever. Failures are only logged.
|
|
2885
|
+
*/
|
|
2886
|
+
function cancelResponseBody(response, url) {
|
|
2887
|
+
response.body?.cancel().catch((error) => {
|
|
2888
|
+
(0, _logtape_logtape.getLogger)([
|
|
2889
|
+
"fedify",
|
|
2890
|
+
"federation",
|
|
2891
|
+
"outbox"
|
|
2892
|
+
]).debug("Failed to cancel the response body from {url}: {error}", {
|
|
2893
|
+
url,
|
|
2894
|
+
error
|
|
2895
|
+
});
|
|
2896
|
+
});
|
|
2897
|
+
}
|
|
2898
|
+
/**
|
|
2899
|
+
* Reads what is needed from the final response of a delivery while its
|
|
2900
|
+
* session is open: the body of a successful response is cancelled, and at
|
|
2901
|
+
* most 1 KiB of an error response body is read.
|
|
2902
|
+
*/
|
|
2903
|
+
async function consumeSendActivityResponse(response, inbox) {
|
|
2904
|
+
if (response.ok) {
|
|
2905
|
+
cancelResponseBody(response, response.url || inbox.href);
|
|
2906
|
+
return { ok: true };
|
|
2907
|
+
}
|
|
2908
|
+
let error;
|
|
2909
|
+
try {
|
|
2910
|
+
error = await readLimitedResponseBody(response, MAX_ERROR_RESPONSE_BODY_BYTES);
|
|
2911
|
+
} catch (_) {
|
|
2912
|
+
error = "";
|
|
2913
|
+
}
|
|
2914
|
+
return {
|
|
2915
|
+
ok: false,
|
|
2916
|
+
status: response.status,
|
|
2917
|
+
statusText: response.statusText,
|
|
2918
|
+
error
|
|
2919
|
+
};
|
|
2920
|
+
}
|
|
2921
|
+
/**
|
|
2922
|
+
* Sends a request without signing it, following redirects manually like the
|
|
2923
|
+
* Fetch standard does. Every hop is opened with `openHop()`, which validates
|
|
2924
|
+
* the destination, after the previous hop is closed. The final response is
|
|
2925
|
+
* passed to `consume()`, and its session is closed after that.
|
|
2926
|
+
* This is exported only for tests; it is not exported from any entry point.
|
|
2927
|
+
* @param request The request to send.
|
|
2928
|
+
* @param openHop The function to open a session for each hop.
|
|
2929
|
+
* @param consume The function to consume the final response.
|
|
2930
|
+
* @returns The value returned by `consume`.
|
|
2931
|
+
*/
|
|
2932
|
+
async function fetchWithValidatedRedirects(request, openHop, consume) {
|
|
2933
|
+
const logger = (0, _logtape_logtape.getLogger)([
|
|
2934
|
+
"fedify",
|
|
2935
|
+
"federation",
|
|
2936
|
+
"outbox"
|
|
2937
|
+
]);
|
|
2880
2938
|
let body = await request.clone().text();
|
|
2881
2939
|
for (let redirects = 0;; redirects++) {
|
|
2882
|
-
const
|
|
2940
|
+
const session = await openHop(request.url);
|
|
2941
|
+
let response;
|
|
2942
|
+
try {
|
|
2943
|
+
response = await session.fetch(request, { redirect: "manual" });
|
|
2944
|
+
} catch (error) {
|
|
2945
|
+
await closeAfterError(session, logger);
|
|
2946
|
+
throw error;
|
|
2947
|
+
}
|
|
2883
2948
|
const location = response.headers.get("Location");
|
|
2884
2949
|
if (![
|
|
2885
2950
|
301,
|
|
@@ -2887,11 +2952,21 @@ async function fetchWithValidatedRedirects(request, validateUrl) {
|
|
|
2887
2952
|
303,
|
|
2888
2953
|
307,
|
|
2889
2954
|
308
|
|
2890
|
-
].includes(response.status) || location == null)
|
|
2891
|
-
|
|
2955
|
+
].includes(response.status) || location == null) try {
|
|
2956
|
+
return await consume(response);
|
|
2957
|
+
} catch (error) {
|
|
2958
|
+
logger.debug("Failed to consume the response from {url}; closing the session: {error}", {
|
|
2959
|
+
url: request.url,
|
|
2960
|
+
error
|
|
2961
|
+
});
|
|
2962
|
+
throw error;
|
|
2963
|
+
} finally {
|
|
2964
|
+
await session.close();
|
|
2965
|
+
}
|
|
2966
|
+
cancelResponseBody(response, request.url);
|
|
2967
|
+
await session.close();
|
|
2892
2968
|
if (redirects >= 20) throw new TypeError("Too many redirects");
|
|
2893
2969
|
const url = new URL(location, request.url);
|
|
2894
|
-
await validateUrl(url.href);
|
|
2895
2970
|
const headers = new Headers(request.headers);
|
|
2896
2971
|
if (url.origin !== new URL(request.url).origin) {
|
|
2897
2972
|
headers.delete("Authorization");
|
|
@@ -2919,6 +2994,16 @@ async function fetchWithValidatedRedirects(request, validateUrl) {
|
|
|
2919
2994
|
});
|
|
2920
2995
|
}
|
|
2921
2996
|
}
|
|
2997
|
+
async function closeAfterError(session, logger) {
|
|
2998
|
+
try {
|
|
2999
|
+
await session.close();
|
|
3000
|
+
} catch (error) {
|
|
3001
|
+
logger.debug("Failed to close the session for {url}: {error}", {
|
|
3002
|
+
url: session.url.href,
|
|
3003
|
+
error
|
|
3004
|
+
});
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
2922
3007
|
/**
|
|
2923
3008
|
* An error that is thrown when an activity fails to send to a remote inbox.
|
|
2924
3009
|
* It contains structured information about the failure, including the HTTP
|
|
@@ -4907,43 +4992,83 @@ var RequestContextImpl = class RequestContextImpl extends ContextImpl {
|
|
|
4907
4992
|
}
|
|
4908
4993
|
}), values);
|
|
4909
4994
|
}
|
|
4910
|
-
#signedKey =
|
|
4995
|
+
#signedKey = null;
|
|
4996
|
+
#signedKeyOwner = null;
|
|
4997
|
+
#signatureChecks = /* @__PURE__ */ new WeakMap();
|
|
4998
|
+
#getSignatureCheck(documentLoader, contextLoader) {
|
|
4999
|
+
let checks = this.#signatureChecks.get(documentLoader);
|
|
5000
|
+
if (checks == null) {
|
|
5001
|
+
checks = /* @__PURE__ */ new WeakMap();
|
|
5002
|
+
this.#signatureChecks.set(documentLoader, checks);
|
|
5003
|
+
}
|
|
5004
|
+
let check = checks.get(contextLoader);
|
|
5005
|
+
if (check == null) {
|
|
5006
|
+
check = {};
|
|
5007
|
+
checks.set(contextLoader, check);
|
|
5008
|
+
}
|
|
5009
|
+
return check;
|
|
5010
|
+
}
|
|
4911
5011
|
async getSignedKey(options = {}) {
|
|
4912
5012
|
if (this.#signedKey != null) return this.#signedKey;
|
|
4913
|
-
|
|
5013
|
+
const documentLoader = options.documentLoader ?? this.documentLoader;
|
|
5014
|
+
const contextLoader = options.contextLoader ?? this.contextLoader;
|
|
5015
|
+
const check = this.#getSignatureCheck(documentLoader, contextLoader);
|
|
5016
|
+
if (check.key != null) return check.key;
|
|
5017
|
+
const promise = require_http.verifyRequest(this.request, {
|
|
4914
5018
|
...this,
|
|
4915
|
-
contextLoader
|
|
4916
|
-
documentLoader
|
|
5019
|
+
contextLoader,
|
|
5020
|
+
documentLoader,
|
|
4917
5021
|
timeWindow: this.federation.signatureTimeWindow,
|
|
4918
5022
|
tracerProvider: options.tracerProvider ?? this.tracerProvider
|
|
5023
|
+
}).then((key) => {
|
|
5024
|
+
if (key != null) this.#signedKey ??= key;
|
|
5025
|
+
return key;
|
|
5026
|
+
}).catch((error) => {
|
|
5027
|
+
if (check.key === promise) check.key = void 0;
|
|
5028
|
+
throw error;
|
|
4919
5029
|
});
|
|
5030
|
+
check.key = promise;
|
|
5031
|
+
return await promise;
|
|
4920
5032
|
}
|
|
4921
|
-
#signedKeyOwner = void 0;
|
|
4922
5033
|
async getSignedKeyOwner(options = {}) {
|
|
4923
5034
|
if (this.#signedKeyOwner != null) return this.#signedKeyOwner;
|
|
4924
|
-
const
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
"fedify",
|
|
4936
|
-
"federation",
|
|
4937
|
-
"actor"
|
|
4938
|
-
]).warn("Failed to fetch the key owner {keyOwner} of {keyId} while verifying the request signature; treating the request as unauthenticated: {error}", {
|
|
4939
|
-
keyId: key.id?.href,
|
|
4940
|
-
keyOwner: error.url.href,
|
|
4941
|
-
error
|
|
4942
|
-
});
|
|
4943
|
-
return this.#signedKeyOwner = null;
|
|
5035
|
+
const normalizedOptions = {
|
|
5036
|
+
documentLoader: options.documentLoader ?? this.documentLoader,
|
|
5037
|
+
contextLoader: options.contextLoader ?? this.contextLoader,
|
|
5038
|
+
tracerProvider: options.tracerProvider ?? this.tracerProvider
|
|
5039
|
+
};
|
|
5040
|
+
const check = this.#getSignatureCheck(normalizedOptions.documentLoader, normalizedOptions.contextLoader);
|
|
5041
|
+
if (check.owner != null) return check.owner;
|
|
5042
|
+
const promise = this.getSignedKey(normalizedOptions).then(async (key) => {
|
|
5043
|
+
if (key == null) {
|
|
5044
|
+
if (check.owner === promise) check.owner = void 0;
|
|
5045
|
+
return null;
|
|
4944
5046
|
}
|
|
5047
|
+
try {
|
|
5048
|
+
const owner = await require_proof.getKeyOwner(key, normalizedOptions);
|
|
5049
|
+
if (owner != null) this.#signedKeyOwner ??= owner;
|
|
5050
|
+
return owner;
|
|
5051
|
+
} catch (error) {
|
|
5052
|
+
if (error instanceof _fedify_vocab_runtime.FetchError) {
|
|
5053
|
+
(0, _logtape_logtape.getLogger)([
|
|
5054
|
+
"fedify",
|
|
5055
|
+
"federation",
|
|
5056
|
+
"actor"
|
|
5057
|
+
]).warn("Failed to fetch the key owner {keyOwner} of {keyId} while verifying the request signature; treating the request as unauthenticated: {error}", {
|
|
5058
|
+
keyId: key.id?.href,
|
|
5059
|
+
keyOwner: error.url.href,
|
|
5060
|
+
error
|
|
5061
|
+
});
|
|
5062
|
+
return null;
|
|
5063
|
+
}
|
|
5064
|
+
throw error;
|
|
5065
|
+
}
|
|
5066
|
+
}).catch((error) => {
|
|
5067
|
+
if (check.owner === promise) check.owner = void 0;
|
|
4945
5068
|
throw error;
|
|
4946
|
-
}
|
|
5069
|
+
});
|
|
5070
|
+
check.owner = promise;
|
|
5071
|
+
return await promise;
|
|
4947
5072
|
}
|
|
4948
5073
|
};
|
|
4949
5074
|
function forwardActivity(ctx, loggerCategory, forwarder, recipients, options) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
const { Temporal } = require("@js-temporal/polyfill");
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
|
-
const require_middleware = require("./middleware-
|
|
3
|
+
const require_middleware = require("./middleware-DNueR0GD.cjs");
|
|
4
4
|
exports.FederationImpl = require_middleware.FederationImpl;
|