@fedify/fedify 1.7.15 → 1.7.16
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/actor-BzWaWDTY.js +146 -0
- package/dist/actor.js +34648 -5
- package/dist/{assert.js → assert-C-mZuSQl.js} +1 -1
- package/dist/{assert_instance_of.js → assert_instance_of-lS0Jr2iu.js} +1 -1
- package/dist/{assert_is_error.js → assert_is_error-CIYFACrT.js} +1 -1
- package/dist/{assert_not_equals.js → assert_not_equals-C1azCAB0.js} +1 -1
- package/dist/{assert_rejects.js → assert_rejects-Bkh5lA1a.js} +2 -2
- package/dist/{assert_throws.js → assert_throws-CmpfkWEM.js} +2 -2
- package/dist/authdocloader-1vrHbYJF.js +51 -0
- package/dist/authdocloader.js +2 -4
- package/dist/{builder.js → builder-8YjpOSrf.js} +5 -5
- package/dist/{client.js → client-CJ3nfMyp.js} +2 -2
- package/dist/compat/transformers.test.js +30 -30
- package/dist/{context.js → context-OXYKUfFL.js} +4 -4
- package/dist/docloader-I3SkMpZK.js +4421 -0
- package/dist/docloader.js +61 -4
- package/dist/{esm.js → esm-BRXvTSrx.js} +1 -1
- package/dist/federation/builder.test.js +17 -17
- package/dist/federation/collection.test.js +8 -8
- package/dist/federation/handler.test.js +36 -36
- package/dist/federation/inbox.test.js +11 -11
- package/dist/federation/keycache.test.js +12 -12
- package/dist/federation/kv.test.js +8 -8
- package/dist/federation/middleware.test.js +39 -39
- package/dist/federation/mq.test.js +10 -10
- package/dist/federation/retry.test.js +5 -5
- package/dist/federation/router.test.js +9 -9
- package/dist/federation/send.test.js +23 -23
- package/dist/http-CiQH4CF3.js +789 -0
- package/dist/http.js +4 -5
- package/dist/{inbox.js → inbox-BqBPO0vG.js} +3 -3
- package/dist/key-Ba-IjS2c.js +259 -0
- package/dist/key-CdNa4Um6.js +16 -0
- package/dist/key.js +1 -7
- package/dist/key2.js +2 -4
- package/dist/{keycache.js → keycache-BdgRTisV.js} +1 -1
- package/dist/{keys.js → keys-CLFIvF3E.js} +1 -1
- package/dist/{ld.js → ld-Dm1tdWDX.js} +4 -4
- package/dist/{lookup2.js → lookup-BumKjgCt.js} +4 -4
- package/dist/lookup-CoCshjhM.js +129 -0
- package/dist/lookup.js +1 -3
- package/dist/middleware-Dvd4BUlF.js +2661 -0
- package/dist/middleware-pC0Ld2I6.js +32 -0
- package/dist/middleware.js +1222 -364
- package/dist/middleware2.js +6 -21
- package/dist/nodeinfo/client.test.js +12 -12
- package/dist/nodeinfo/handler.test.js +34 -34
- package/dist/nodeinfo/semver.test.js +8 -8
- package/dist/nodeinfo/types.test.js +9 -9
- package/dist/{owner.js → owner-BO3ZhyYg.js} +3 -3
- package/dist/proof-Btlfk6hr.js +255 -0
- package/dist/proof.js +330 -8
- package/dist/runtime/authdocloader.test.js +20 -20
- package/dist/runtime/docloader.test.js +13 -13
- package/dist/runtime/key.test.js +15 -15
- package/dist/runtime/langstr.test.js +8 -8
- package/dist/runtime/multibase/multibase.test.js +8 -8
- package/dist/runtime/url.test.js +7 -7
- package/dist/{send.js → send-Dj-482tr.js} +2 -2
- package/dist/sig/http.test.js +20 -20
- package/dist/sig/key.test.js +17 -17
- package/dist/sig/ld.test.js +18 -18
- package/dist/sig/owner.test.js +20 -20
- package/dist/sig/proof.test.js +19 -19
- package/dist/{std__assert.js → std__assert-BdP_WkD-.js} +1 -1
- package/dist/testing/docloader.test.js +8 -8
- package/dist/testing/mod.js +2 -2
- package/dist/{testing.js → testing-qaAD4B0t.js} +1 -1
- package/dist/types-CB_2uuCA.js +51 -0
- package/dist/types.js +397 -3
- package/dist/vocab/actor.test.js +16 -16
- package/dist/vocab/lookup.test.js +17 -17
- package/dist/vocab/type.test.js +9 -9
- package/dist/vocab/vocab.test.js +17 -17
- package/dist/vocab-B8zleLsO.js +34386 -0
- package/dist/vocab.js +133 -34351
- package/dist/webfinger/handler.test.js +34 -34
- package/dist/webfinger/lookup.test.js +11 -11
- package/dist/x/cfworkers.test.js +7 -7
- package/package.json +1 -1
- /package/dist/{assert_equals.js → assert_equals-Dy0MG_Zw.js} +0 -0
- /package/dist/{chunk.js → chunk-DvTpRkcT.js} +0 -0
- /package/dist/{collection.js → collection-XNLQhehO.js} +0 -0
- /package/dist/compat/{transformers.test.d.ts → transformers.test-DnJbd34u.d.ts} +0 -0
- /package/dist/{denokv.js → denokv-NcJeZ6rP.js} +0 -0
- /package/dist/{docloader2.js → docloader-BDSHZfTJ.js} +0 -0
- /package/dist/federation/{builder.test.d.ts → builder.test-Bpt6NOZ6.d.ts} +0 -0
- /package/dist/federation/{collection.test.d.ts → collection.test-DKJ6JOZz.d.ts} +0 -0
- /package/dist/federation/{handler.test.d.ts → handler.test-BMT7uLC0.d.ts} +0 -0
- /package/dist/federation/{inbox.test.d.ts → inbox.test-Do6i02Qp.d.ts} +0 -0
- /package/dist/federation/{keycache.test.d.ts → keycache.test-BT83IPZY.d.ts} +0 -0
- /package/dist/federation/{kv.test.d.ts → kv.test-kFzzF2VN.d.ts} +0 -0
- /package/dist/federation/{middleware.test.d.ts → middleware.test-B1R4_e3-.d.ts} +0 -0
- /package/dist/federation/{mq.test.d.ts → mq.test-l79EQQOe.d.ts} +0 -0
- /package/dist/federation/{retry.test.d.ts → retry.test-BqS50VCX.d.ts} +0 -0
- /package/dist/federation/{router.test.d.ts → router.test-CYQl4po-.d.ts} +0 -0
- /package/dist/federation/{send.test.d.ts → send.test-COUnNUzv.d.ts} +0 -0
- /package/dist/{kv.js → kv-QeuZ51go.js} +0 -0
- /package/dist/{langstr.js → langstr-pFHBDU4y.js} +0 -0
- /package/dist/{multibase.js → multibase-DBcKTV2a.js} +0 -0
- /package/dist/nodeinfo/{client.test.d.ts → client.test-CZLe79hL.d.ts} +0 -0
- /package/dist/nodeinfo/{handler.test.d.ts → handler.test-B-EDZ_hK.d.ts} +0 -0
- /package/dist/nodeinfo/{semver.test.d.ts → semver.test-BEuuQSEM.d.ts} +0 -0
- /package/dist/nodeinfo/{types.test.d.ts → types.test-B5AT89WV.d.ts} +0 -0
- /package/dist/{retry.js → retry-BQet39_l.js} +0 -0
- /package/dist/{router.js → router-BuDkN4RQ.js} +0 -0
- /package/dist/runtime/{authdocloader.test.d.ts → authdocloader.test-hCRKzn9v.d.ts} +0 -0
- /package/dist/runtime/{docloader.test.d.ts → docloader.test-CVd7i_5h.d.ts} +0 -0
- /package/dist/runtime/{key.test.d.ts → key.test-DBsILYSD.d.ts} +0 -0
- /package/dist/runtime/{langstr.test.d.ts → langstr.test-CiKxuuRY.d.ts} +0 -0
- /package/dist/runtime/multibase/{multibase.test.d.ts → multibase.test-Brh6gPBP.d.ts} +0 -0
- /package/dist/runtime/{url.test.d.ts → url.test-DlRqkU2j.d.ts} +0 -0
- /package/dist/{semver.js → semver-D9d-VO-_.js} +0 -0
- /package/dist/sig/{http.test.d.ts → http.test-BpXNAWNI.d.ts} +0 -0
- /package/dist/sig/{key.test.d.ts → key.test-B2iLIugy.d.ts} +0 -0
- /package/dist/sig/{ld.test.d.ts → ld.test-D-cI70Gw.d.ts} +0 -0
- /package/dist/sig/{owner.test.d.ts → owner.test-B_YRjMPj.d.ts} +0 -0
- /package/dist/sig/{proof.test.d.ts → proof.test-BagEM_-4.d.ts} +0 -0
- /package/dist/testing/{docloader.test.d.ts → docloader.test-lrzf6sDZ.d.ts} +0 -0
- /package/dist/testing/{mod.d.ts → mod-3uM8ZvS7.d.ts} +0 -0
- /package/dist/{type.js → type-DFsmi-p1.js} +0 -0
- /package/dist/{url.js → url-BdNvnK9P.js} +0 -0
- /package/dist/vocab/{actor.test.d.ts → actor.test-ClC-iVWk.d.ts} +0 -0
- /package/dist/vocab/{lookup.test.d.ts → lookup.test-Cq1I-27w.d.ts} +0 -0
- /package/dist/vocab/{type.test.d.ts → type.test-bfFiYGcs.d.ts} +0 -0
- /package/dist/vocab/{vocab.test.d.ts → vocab.test-h-ZTisfu.d.ts} +0 -0
- /package/dist/webfinger/{handler.test.d.ts → handler.test-DiUeEDDD.d.ts} +0 -0
- /package/dist/webfinger/{lookup.test.d.ts → lookup.test-D9onm3U3.d.ts} +0 -0
- /package/dist/x/{cfworkers.test.d.ts → cfworkers.test-KXHlJ29z.d.ts} +0 -0
package/dist/middleware.js
CHANGED
|
@@ -1,301 +1,845 @@
|
|
|
1
1
|
|
|
2
2
|
import { Temporal } from "@js-temporal/polyfill";
|
|
3
3
|
import { URLPattern } from "urlpattern-polyfill";
|
|
4
|
-
globalThis.addEventListener = () => {};
|
|
5
4
|
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { t as nodeInfoToJson } from "./types.js";
|
|
10
|
-
import { _ as Object$1, b as OrderedCollectionPage, h as Multikey, m as Link, o as CryptographicKey, t as Activity, y as OrderedCollection } from "./vocab.js";
|
|
5
|
+
import { r as getDefaultActivityTransformers } from "./transformers.js";
|
|
6
|
+
import { d as name, f as version, i as getDocumentLoader, s as kvCache } from "./docloader.js";
|
|
7
|
+
import { G as Multikey, Tt as getTypeId, V as Link, X as OrderedCollectionPage, Y as OrderedCollection, q as Object$1, s as Activity, y as CryptographicKey } from "./actor.js";
|
|
11
8
|
import { t as lookupWebFinger } from "./lookup.js";
|
|
12
|
-
import { t as getTypeId } from "./type.js";
|
|
13
9
|
import { a as validateCryptoKey, i as importJwk, t as exportJwk } from "./key2.js";
|
|
14
|
-
import {
|
|
10
|
+
import { r as verifyRequest, t as doubleKnock } from "./http.js";
|
|
11
|
+
import { a as doesActorOwnKey, d as signJsonLd, f as verifyJsonLd, l as detachSignature, n as signObject, o as getKeyOwner, r as verifyObject, u as hasSignature } from "./proof.js";
|
|
12
|
+
import { n as getNodeInfo, t as nodeInfoToJson } from "./types.js";
|
|
15
13
|
import { t as getAuthenticatedDocumentLoader } from "./authdocloader.js";
|
|
16
|
-
import {
|
|
17
|
-
import { n as getKeyOwner, t as doesActorOwnKey } from "./owner.js";
|
|
18
|
-
import { n as signObject, r as verifyObject } from "./proof.js";
|
|
19
|
-
import { n as traverseCollection, t as lookupObject } from "./lookup2.js";
|
|
20
|
-
import { n as routeActivity } from "./inbox.js";
|
|
21
|
-
import { t as FederationBuilderImpl } from "./builder.js";
|
|
22
|
-
import { t as buildCollectionSynchronizationHeader } from "./collection.js";
|
|
23
|
-
import { t as KvKeyCache } from "./keycache.js";
|
|
24
|
-
import { t as createExponentialBackoffPolicy } from "./retry.js";
|
|
25
|
-
import { n as sendActivity, t as extractInboxes } from "./send.js";
|
|
14
|
+
import { n as lookupObject, r as traverseCollection } from "./vocab.js";
|
|
26
15
|
import { getLogger, withContext } from "@logtape/logtape";
|
|
27
16
|
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
17
|
+
import { encodeHex } from "byte-encodings/hex";
|
|
18
|
+
import { cloneDeep } from "@es-toolkit/es-toolkit";
|
|
19
|
+
import { Router } from "uri-template-router";
|
|
20
|
+
import { parseTemplate } from "url-template";
|
|
28
21
|
import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_HEADER, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
|
|
29
22
|
import { domainToASCII } from "node:url";
|
|
30
23
|
|
|
31
|
-
//#region
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
24
|
+
//#region federation/inbox.ts
|
|
25
|
+
var InboxListenerSet = class InboxListenerSet {
|
|
26
|
+
#listeners;
|
|
27
|
+
constructor() {
|
|
28
|
+
this.#listeners = /* @__PURE__ */ new Map();
|
|
29
|
+
}
|
|
30
|
+
clone() {
|
|
31
|
+
const clone = new InboxListenerSet();
|
|
32
|
+
clone.#listeners = new Map(this.#listeners);
|
|
33
|
+
return clone;
|
|
34
|
+
}
|
|
35
|
+
add(type, listener) {
|
|
36
|
+
if (this.#listeners.has(type)) throw new TypeError("Listener already set for this type.");
|
|
37
|
+
this.#listeners.set(type, listener);
|
|
38
|
+
}
|
|
39
|
+
dispatchWithClass(activity) {
|
|
40
|
+
let cls = activity.constructor;
|
|
41
|
+
const inboxListeners = this.#listeners;
|
|
42
|
+
if (inboxListeners == null) return null;
|
|
43
|
+
while (true) {
|
|
44
|
+
if (inboxListeners.has(cls)) break;
|
|
45
|
+
if (cls === Activity) return null;
|
|
46
|
+
cls = globalThis.Object.getPrototypeOf(cls);
|
|
47
|
+
}
|
|
48
|
+
const listener = inboxListeners.get(cls);
|
|
49
|
+
return {
|
|
50
|
+
class: cls,
|
|
51
|
+
listener
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
dispatch(activity) {
|
|
55
|
+
return this.dispatchWithClass(activity)?.listener ?? null;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider }) {
|
|
59
|
+
const logger$1 = getLogger([
|
|
60
|
+
"fedify",
|
|
61
|
+
"federation",
|
|
62
|
+
"inbox"
|
|
63
|
+
]);
|
|
64
|
+
const cacheKey = activity.id == null ? null : [
|
|
65
|
+
...kvPrefixes.activityIdempotence,
|
|
66
|
+
ctx.origin,
|
|
67
|
+
activity.id.href
|
|
68
|
+
];
|
|
69
|
+
if (cacheKey != null) {
|
|
70
|
+
if (await kv.get(cacheKey) === true) {
|
|
71
|
+
logger$1.debug("Activity {activityId} has already been processed.", {
|
|
72
|
+
activityId: activity.id?.href,
|
|
73
|
+
activity: json,
|
|
74
|
+
recipient
|
|
75
|
+
});
|
|
76
|
+
span.setStatus({
|
|
77
|
+
code: SpanStatusCode.UNSET,
|
|
78
|
+
message: `Activity ${activity.id?.href} has already been processed.`
|
|
79
|
+
});
|
|
80
|
+
return "alreadyProcessed";
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (activity.actorId == null) {
|
|
84
|
+
logger$1.error("Missing actor.", { activity: json });
|
|
85
|
+
span.setStatus({
|
|
86
|
+
code: SpanStatusCode.ERROR,
|
|
87
|
+
message: "Missing actor."
|
|
88
|
+
});
|
|
89
|
+
return "missingActor";
|
|
90
|
+
}
|
|
91
|
+
span.setAttribute("activitypub.actor.id", activity.actorId.href);
|
|
92
|
+
if (queue != null) {
|
|
93
|
+
const carrier = {};
|
|
94
|
+
propagation.inject(context.active(), carrier);
|
|
95
|
+
try {
|
|
96
|
+
await queue.enqueue({
|
|
97
|
+
type: "inbox",
|
|
98
|
+
id: crypto.randomUUID(),
|
|
99
|
+
baseUrl: ctx.origin,
|
|
100
|
+
activity: json,
|
|
101
|
+
identifier: recipient,
|
|
102
|
+
attempt: 0,
|
|
103
|
+
started: (/* @__PURE__ */ new Date()).toISOString(),
|
|
104
|
+
traceContext: carrier
|
|
105
|
+
});
|
|
106
|
+
} catch (error) {
|
|
107
|
+
logger$1.error("Failed to enqueue the incoming activity {activityId}:\n{error}", {
|
|
108
|
+
error,
|
|
109
|
+
activityId: activity.id?.href,
|
|
110
|
+
activity: json,
|
|
111
|
+
recipient
|
|
112
|
+
});
|
|
113
|
+
span.setStatus({
|
|
114
|
+
code: SpanStatusCode.ERROR,
|
|
115
|
+
message: `Failed to enqueue the incoming activity ${activity.id?.href}.`
|
|
116
|
+
});
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
logger$1.info("Activity {activityId} is enqueued.", {
|
|
120
|
+
activityId: activity.id?.href,
|
|
121
|
+
activity: json,
|
|
122
|
+
recipient
|
|
123
|
+
});
|
|
124
|
+
return "enqueued";
|
|
125
|
+
}
|
|
126
|
+
tracerProvider = tracerProvider ?? trace.getTracerProvider();
|
|
127
|
+
return await tracerProvider.getTracer(name, version).startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span$1) => {
|
|
128
|
+
const dispatched = inboxListeners?.dispatchWithClass(activity);
|
|
129
|
+
if (dispatched == null) {
|
|
130
|
+
logger$1.error("Unsupported activity type:\n{activity}", {
|
|
131
|
+
activity: json,
|
|
132
|
+
recipient
|
|
133
|
+
});
|
|
134
|
+
span$1.setStatus({
|
|
135
|
+
code: SpanStatusCode.UNSET,
|
|
136
|
+
message: `Unsupported activity type: ${getTypeId(activity).href}`
|
|
137
|
+
});
|
|
138
|
+
span$1.end();
|
|
139
|
+
return "unsupportedActivity";
|
|
140
|
+
}
|
|
141
|
+
const { class: cls, listener } = dispatched;
|
|
142
|
+
span$1.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
|
|
143
|
+
try {
|
|
144
|
+
await listener(inboxContextFactory(recipient, json, activity?.id?.href, getTypeId(activity).href), activity);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
try {
|
|
147
|
+
await inboxErrorHandler?.(ctx, error);
|
|
148
|
+
} catch (error$1) {
|
|
149
|
+
logger$1.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
150
|
+
error: error$1,
|
|
151
|
+
activityId: activity.id?.href,
|
|
152
|
+
activity: json,
|
|
153
|
+
recipient
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
logger$1.error("Failed to process the incoming activity {activityId}:\n{error}", {
|
|
157
|
+
error,
|
|
158
|
+
activityId: activity.id?.href,
|
|
159
|
+
activity: json,
|
|
160
|
+
recipient
|
|
161
|
+
});
|
|
162
|
+
span$1.setStatus({
|
|
163
|
+
code: SpanStatusCode.ERROR,
|
|
164
|
+
message: String(error)
|
|
165
|
+
});
|
|
166
|
+
span$1.end();
|
|
167
|
+
return "error";
|
|
168
|
+
}
|
|
169
|
+
if (cacheKey != null) await kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
|
|
170
|
+
logger$1.info("Activity {activityId} has been processed.", {
|
|
171
|
+
activityId: activity.id?.href,
|
|
172
|
+
activity: json,
|
|
173
|
+
recipient
|
|
174
|
+
});
|
|
175
|
+
span$1.end();
|
|
176
|
+
return "success";
|
|
177
|
+
});
|
|
119
178
|
}
|
|
120
179
|
|
|
121
180
|
//#endregion
|
|
122
|
-
//#region
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const json = nodeInfoToJson(promise instanceof Promise ? await promise : promise);
|
|
133
|
-
return new Response(JSON.stringify(json), { headers: { "Content-Type": "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\"" } });
|
|
181
|
+
//#region federation/router.ts
|
|
182
|
+
function cloneInnerRouter(router) {
|
|
183
|
+
const clone = new Router();
|
|
184
|
+
clone.nid = router.nid;
|
|
185
|
+
clone.fsm = cloneDeep(router.fsm);
|
|
186
|
+
clone.routeSet = new Set(router.routeSet);
|
|
187
|
+
clone.templateRouteMap = new Map(router.templateRouteMap);
|
|
188
|
+
clone.valueRouteMap = new Map(router.valueRouteMap);
|
|
189
|
+
clone.hierarchy = cloneDeep(router.hierarchy);
|
|
190
|
+
return clone;
|
|
134
191
|
}
|
|
135
192
|
/**
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* @param request The request to handle.
|
|
139
|
-
* @param context The request context.
|
|
140
|
-
* @returns The response to the request.
|
|
193
|
+
* URL router and constructor based on URI Template
|
|
194
|
+
* ([RFC 6570](https://tools.ietf.org/html/rfc6570)).
|
|
141
195
|
*/
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
196
|
+
var Router$1 = class Router$1 {
|
|
197
|
+
#router;
|
|
198
|
+
#templates;
|
|
199
|
+
#templateStrings;
|
|
200
|
+
/**
|
|
201
|
+
* Whether to ignore trailing slashes when matching paths.
|
|
202
|
+
* @since 1.6.0
|
|
203
|
+
*/
|
|
204
|
+
trailingSlashInsensitive;
|
|
205
|
+
/**
|
|
206
|
+
* Create a new {@link Router}.
|
|
207
|
+
* @param options Options for the router.
|
|
208
|
+
*/
|
|
209
|
+
constructor(options = {}) {
|
|
210
|
+
this.#router = new Router();
|
|
211
|
+
this.#templates = {};
|
|
212
|
+
this.#templateStrings = {};
|
|
213
|
+
this.trailingSlashInsensitive = options.trailingSlashInsensitive ?? false;
|
|
214
|
+
}
|
|
215
|
+
clone() {
|
|
216
|
+
const clone = new Router$1({ trailingSlashInsensitive: this.trailingSlashInsensitive });
|
|
217
|
+
clone.#router = cloneInnerRouter(this.#router);
|
|
218
|
+
clone.#templates = { ...this.#templates };
|
|
219
|
+
clone.#templateStrings = { ...this.#templateStrings };
|
|
220
|
+
return clone;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Checks if a path name exists in the router.
|
|
224
|
+
* @param name The name of the path.
|
|
225
|
+
* @returns `true` if the path name exists, otherwise `false`.
|
|
226
|
+
*/
|
|
227
|
+
has(name$1) {
|
|
228
|
+
return name$1 in this.#templates;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Adds a new path rule to the router.
|
|
232
|
+
* @param template The path pattern.
|
|
233
|
+
* @param name The name of the path.
|
|
234
|
+
* @returns The names of the variables in the path pattern.
|
|
235
|
+
*/
|
|
236
|
+
add(template, name$1) {
|
|
237
|
+
if (!template.startsWith("/")) throw new RouterError("Path must start with a slash.");
|
|
238
|
+
const rule = this.#router.addTemplate(template, {}, name$1);
|
|
239
|
+
this.#templates[name$1] = parseTemplate(template);
|
|
240
|
+
this.#templateStrings[name$1] = template;
|
|
241
|
+
return new Set(rule.variables.map((v) => v.varname));
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Resolves a path name and values from a URL, if any match.
|
|
245
|
+
* @param url The URL to resolve.
|
|
246
|
+
* @returns The name of the path and its values, if any match. Otherwise,
|
|
247
|
+
* `null`.
|
|
248
|
+
*/
|
|
249
|
+
route(url) {
|
|
250
|
+
let match = this.#router.resolveURI(url);
|
|
251
|
+
if (match == null) {
|
|
252
|
+
if (!this.trailingSlashInsensitive) return null;
|
|
253
|
+
url = url.endsWith("/") ? url.replace(/\/+$/, "") : `${url}/`;
|
|
254
|
+
match = this.#router.resolveURI(url);
|
|
255
|
+
if (match == null) return null;
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
name: match.matchValue,
|
|
259
|
+
template: this.#templateStrings[match.matchValue],
|
|
260
|
+
values: match.params
|
|
261
|
+
};
|
|
152
262
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
263
|
+
/**
|
|
264
|
+
* Constructs a URL/path from a path name and values.
|
|
265
|
+
* @param name The name of the path.
|
|
266
|
+
* @param values The values to expand the path with.
|
|
267
|
+
* @returns The URL/path, if the name exists. Otherwise, `null`.
|
|
268
|
+
*/
|
|
269
|
+
build(name$1, values) {
|
|
270
|
+
if (name$1 in this.#templates) return this.#templates[name$1].expand(values);
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
};
|
|
160
274
|
/**
|
|
161
|
-
*
|
|
162
|
-
* object.*
|
|
163
|
-
*
|
|
164
|
-
* [public addressing]: https://www.w3.org/TR/activitypub/#public-addressing
|
|
165
|
-
*
|
|
166
|
-
* @since 0.7.0
|
|
275
|
+
* An error thrown by the {@link Router}.
|
|
167
276
|
*/
|
|
168
|
-
|
|
277
|
+
var RouterError = class extends Error {
|
|
278
|
+
/**
|
|
279
|
+
* Create a new {@link RouterError}.
|
|
280
|
+
* @param message The error message.
|
|
281
|
+
*/
|
|
282
|
+
constructor(message) {
|
|
283
|
+
super(message);
|
|
284
|
+
this.name = "RouterError";
|
|
285
|
+
}
|
|
286
|
+
};
|
|
169
287
|
|
|
170
288
|
//#endregion
|
|
171
|
-
//#region
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
289
|
+
//#region federation/builder.ts
|
|
290
|
+
var FederationBuilderImpl = class {
|
|
291
|
+
router;
|
|
292
|
+
actorCallbacks;
|
|
293
|
+
nodeInfoDispatcher;
|
|
294
|
+
objectCallbacks;
|
|
295
|
+
objectTypeIds;
|
|
296
|
+
inboxPath;
|
|
297
|
+
inboxCallbacks;
|
|
298
|
+
outboxCallbacks;
|
|
299
|
+
followingCallbacks;
|
|
300
|
+
followersCallbacks;
|
|
301
|
+
likedCallbacks;
|
|
302
|
+
featuredCallbacks;
|
|
303
|
+
featuredTagsCallbacks;
|
|
304
|
+
inboxListeners;
|
|
305
|
+
inboxErrorHandler;
|
|
306
|
+
sharedInboxKeyDispatcher;
|
|
307
|
+
constructor() {
|
|
308
|
+
this.router = new Router$1();
|
|
309
|
+
this.objectCallbacks = {};
|
|
310
|
+
this.objectTypeIds = {};
|
|
311
|
+
}
|
|
312
|
+
async build(options) {
|
|
313
|
+
const { FederationImpl: FederationImpl$1 } = await import("./middleware2.js");
|
|
314
|
+
const f = new FederationImpl$1(options);
|
|
315
|
+
const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
|
|
316
|
+
f.router = this.router.clone();
|
|
317
|
+
f.router.trailingSlashInsensitive = trailingSlashInsensitiveValue;
|
|
318
|
+
f._initializeRouter();
|
|
319
|
+
f.actorCallbacks = this.actorCallbacks == null ? void 0 : { ...this.actorCallbacks };
|
|
320
|
+
f.nodeInfoDispatcher = this.nodeInfoDispatcher;
|
|
321
|
+
f.objectCallbacks = { ...this.objectCallbacks };
|
|
322
|
+
f.objectTypeIds = { ...this.objectTypeIds };
|
|
323
|
+
f.inboxPath = this.inboxPath;
|
|
324
|
+
f.inboxCallbacks = this.inboxCallbacks == null ? void 0 : { ...this.inboxCallbacks };
|
|
325
|
+
f.outboxCallbacks = this.outboxCallbacks == null ? void 0 : { ...this.outboxCallbacks };
|
|
326
|
+
f.followingCallbacks = this.followingCallbacks == null ? void 0 : { ...this.followingCallbacks };
|
|
327
|
+
f.followersCallbacks = this.followersCallbacks == null ? void 0 : { ...this.followersCallbacks };
|
|
328
|
+
f.likedCallbacks = this.likedCallbacks == null ? void 0 : { ...this.likedCallbacks };
|
|
329
|
+
f.featuredCallbacks = this.featuredCallbacks == null ? void 0 : { ...this.featuredCallbacks };
|
|
330
|
+
f.featuredTagsCallbacks = this.featuredTagsCallbacks == null ? void 0 : { ...this.featuredTagsCallbacks };
|
|
331
|
+
f.inboxListeners = this.inboxListeners?.clone();
|
|
332
|
+
f.inboxErrorHandler = this.inboxErrorHandler;
|
|
333
|
+
f.sharedInboxKeyDispatcher = this.sharedInboxKeyDispatcher;
|
|
334
|
+
return f;
|
|
335
|
+
}
|
|
336
|
+
_getTracer() {
|
|
337
|
+
return trace.getTracer(name, version);
|
|
338
|
+
}
|
|
339
|
+
setActorDispatcher(path, dispatcher) {
|
|
340
|
+
if (this.router.has("actor")) throw new RouterError("Actor dispatcher already set.");
|
|
341
|
+
const variables = this.router.add(path, "actor");
|
|
342
|
+
if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for actor dispatcher must have one variable: {identifier}");
|
|
343
|
+
if (variables.has("handle")) getLogger([
|
|
344
|
+
"fedify",
|
|
345
|
+
"federation",
|
|
346
|
+
"actor"
|
|
347
|
+
]).warn("The {{handle}} variable in the actor dispatcher path is deprecated. Use {{identifier}} instead.");
|
|
348
|
+
const callbacks = { dispatcher: async (context$1, identifier) => {
|
|
349
|
+
const actor = await this._getTracer().startActiveSpan("activitypub.dispatch_actor", {
|
|
350
|
+
kind: SpanKind.SERVER,
|
|
351
|
+
attributes: { "fedify.actor.identifier": identifier }
|
|
352
|
+
}, async (span) => {
|
|
353
|
+
try {
|
|
354
|
+
const actor$1 = await dispatcher(context$1, identifier);
|
|
355
|
+
span.setAttribute("activitypub.actor.id", (actor$1?.id ?? context$1.getActorUri(identifier)).href);
|
|
356
|
+
if (actor$1 == null) span.setStatus({ code: SpanStatusCode.ERROR });
|
|
357
|
+
else span.setAttribute("activitypub.actor.type", getTypeId(actor$1).href);
|
|
358
|
+
return actor$1;
|
|
359
|
+
} catch (error) {
|
|
360
|
+
span.setStatus({
|
|
361
|
+
code: SpanStatusCode.ERROR,
|
|
362
|
+
message: String(error)
|
|
363
|
+
});
|
|
364
|
+
throw error;
|
|
365
|
+
} finally {
|
|
366
|
+
span.end();
|
|
367
|
+
}
|
|
195
368
|
});
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
369
|
+
if (actor == null) return null;
|
|
370
|
+
const logger$1 = getLogger([
|
|
371
|
+
"fedify",
|
|
372
|
+
"federation",
|
|
373
|
+
"actor"
|
|
374
|
+
]);
|
|
375
|
+
if (actor.id == null) logger$1.warn("Actor dispatcher returned an actor without an id property. Set the property with Context.getActorUri(identifier).");
|
|
376
|
+
else if (actor.id.href != context$1.getActorUri(identifier).href) logger$1.warn("Actor dispatcher returned an actor with an id property that does not match the actor URI. Set the property with Context.getActorUri(identifier).");
|
|
377
|
+
if (this.followingCallbacks != null && this.followingCallbacks.dispatcher != null) {
|
|
378
|
+
if (actor.followingId == null) logger$1.warn("You configured a following collection dispatcher, but the actor does not have a following property. Set the property with Context.getFollowingUri(identifier).");
|
|
379
|
+
else if (actor.followingId.href != context$1.getFollowingUri(identifier).href) logger$1.warn("You configured a following collection dispatcher, but the actor's following property does not match the following collection URI. Set the property with Context.getFollowingUri(identifier).");
|
|
380
|
+
}
|
|
381
|
+
if (this.followersCallbacks != null && this.followersCallbacks.dispatcher != null) {
|
|
382
|
+
if (actor.followersId == null) logger$1.warn("You configured a followers collection dispatcher, but the actor does not have a followers property. Set the property with Context.getFollowersUri(identifier).");
|
|
383
|
+
else if (actor.followersId.href != context$1.getFollowersUri(identifier).href) logger$1.warn("You configured a followers collection dispatcher, but the actor's followers property does not match the followers collection URI. Set the property with Context.getFollowersUri(identifier).");
|
|
384
|
+
}
|
|
385
|
+
if (this.outboxCallbacks != null && this.outboxCallbacks.dispatcher != null) {
|
|
386
|
+
if (actor?.outboxId == null) logger$1.warn("You configured an outbox collection dispatcher, but the actor does not have an outbox property. Set the property with Context.getOutboxUri(identifier).");
|
|
387
|
+
else if (actor.outboxId.href != context$1.getOutboxUri(identifier).href) logger$1.warn("You configured an outbox collection dispatcher, but the actor's outbox property does not match the outbox collection URI. Set the property with Context.getOutboxUri(identifier).");
|
|
388
|
+
}
|
|
389
|
+
if (this.likedCallbacks != null && this.likedCallbacks.dispatcher != null) {
|
|
390
|
+
if (actor?.likedId == null) logger$1.warn("You configured a liked collection dispatcher, but the actor does not have a liked property. Set the property with Context.getLikedUri(identifier).");
|
|
391
|
+
else if (actor.likedId.href != context$1.getLikedUri(identifier).href) logger$1.warn("You configured a liked collection dispatcher, but the actor's liked property does not match the liked collection URI. Set the property with Context.getLikedUri(identifier).");
|
|
392
|
+
}
|
|
393
|
+
if (this.featuredCallbacks != null && this.featuredCallbacks.dispatcher != null) {
|
|
394
|
+
if (actor?.featuredId == null) logger$1.warn("You configured a featured collection dispatcher, but the actor does not have a featured property. Set the property with Context.getFeaturedUri(identifier).");
|
|
395
|
+
else if (actor.featuredId.href != context$1.getFeaturedUri(identifier).href) logger$1.warn("You configured a featured collection dispatcher, but the actor's featured property does not match the featured collection URI. Set the property with Context.getFeaturedUri(identifier).");
|
|
396
|
+
}
|
|
397
|
+
if (this.featuredTagsCallbacks != null && this.featuredTagsCallbacks.dispatcher != null) {
|
|
398
|
+
if (actor?.featuredTagsId == null) logger$1.warn("You configured a featured tags collection dispatcher, but the actor does not have a featuredTags property. Set the property with Context.getFeaturedTagsUri(identifier).");
|
|
399
|
+
else if (actor.featuredTagsId.href != context$1.getFeaturedTagsUri(identifier).href) logger$1.warn("You configured a featured tags collection dispatcher, but the actor's featuredTags property does not match the featured tags collection URI. Set the property with Context.getFeaturedTagsUri(identifier).");
|
|
400
|
+
}
|
|
401
|
+
if (this.router.has("inbox")) {
|
|
402
|
+
if (actor.inboxId == null) logger$1.warn("You configured inbox listeners, but the actor does not have an inbox property. Set the property with Context.getInboxUri(identifier).");
|
|
403
|
+
else if (actor.inboxId.href != context$1.getInboxUri(identifier).href) logger$1.warn("You configured inbox listeners, but the actor's inbox property does not match the inbox URI. Set the property with Context.getInboxUri(identifier).");
|
|
404
|
+
if (actor.endpoints == null || actor.endpoints.sharedInbox == null) logger$1.warn("You configured inbox listeners, but the actor does not have a endpoints.sharedInbox property. Set the property with Context.getInboxUri().");
|
|
405
|
+
else if (actor.endpoints.sharedInbox.href != context$1.getInboxUri().href) logger$1.warn("You configured inbox listeners, but the actor's endpoints.sharedInbox property does not match the shared inbox URI. Set the property with Context.getInboxUri().");
|
|
406
|
+
}
|
|
407
|
+
if (callbacks.keyPairsDispatcher != null) {
|
|
408
|
+
if (actor.publicKeyId == null) logger$1.warn("You configured a key pairs dispatcher, but the actor does not have a publicKey property. Set the property with Context.getActorKeyPairs(identifier).");
|
|
409
|
+
if (actor.assertionMethodId == null) logger$1.warn("You configured a key pairs dispatcher, but the actor does not have an assertionMethod property. Set the property with Context.getActorKeyPairs(identifier).");
|
|
410
|
+
}
|
|
411
|
+
return actor;
|
|
412
|
+
} };
|
|
413
|
+
this.actorCallbacks = callbacks;
|
|
414
|
+
const setters = {
|
|
415
|
+
setKeyPairsDispatcher: (dispatcher$1) => {
|
|
416
|
+
callbacks.keyPairsDispatcher = (ctx, identifier) => this._getTracer().startActiveSpan("activitypub.dispatch_actor_key_pairs", {
|
|
417
|
+
kind: SpanKind.SERVER,
|
|
418
|
+
attributes: {
|
|
419
|
+
"activitypub.actor.id": ctx.getActorUri(identifier).href,
|
|
420
|
+
"fedify.actor.identifier": identifier
|
|
421
|
+
}
|
|
422
|
+
}, async (span) => {
|
|
423
|
+
try {
|
|
424
|
+
return await dispatcher$1(ctx, identifier);
|
|
425
|
+
} catch (e) {
|
|
426
|
+
span.setStatus({
|
|
427
|
+
code: SpanStatusCode.ERROR,
|
|
428
|
+
message: String(e)
|
|
429
|
+
});
|
|
430
|
+
throw e;
|
|
431
|
+
} finally {
|
|
432
|
+
span.end();
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
return setters;
|
|
436
|
+
},
|
|
437
|
+
mapHandle(mapper) {
|
|
438
|
+
callbacks.handleMapper = mapper;
|
|
439
|
+
return setters;
|
|
440
|
+
},
|
|
441
|
+
mapAlias(mapper) {
|
|
442
|
+
callbacks.aliasMapper = mapper;
|
|
443
|
+
return setters;
|
|
444
|
+
},
|
|
445
|
+
authorize(predicate) {
|
|
446
|
+
callbacks.authorizePredicate = predicate;
|
|
447
|
+
return setters;
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
return setters;
|
|
451
|
+
}
|
|
452
|
+
setNodeInfoDispatcher(path, dispatcher) {
|
|
453
|
+
if (this.router.has("nodeInfo")) throw new RouterError("NodeInfo dispatcher already set.");
|
|
454
|
+
if (this.router.add(path, "nodeInfo").size !== 0) throw new RouterError("Path for NodeInfo dispatcher must have no variables.");
|
|
455
|
+
this.nodeInfoDispatcher = dispatcher;
|
|
456
|
+
}
|
|
457
|
+
setObjectDispatcher(cls, path, dispatcher) {
|
|
458
|
+
const routeName = `object:${cls.typeId.href}`;
|
|
459
|
+
if (this.router.has(routeName)) throw new RouterError(`Object dispatcher for ${cls.name} already set.`);
|
|
460
|
+
const variables = this.router.add(path, routeName);
|
|
461
|
+
if (variables.size < 1) throw new RouterError("Path for object dispatcher must have at least one variable.");
|
|
462
|
+
const callbacks = {
|
|
463
|
+
dispatcher: (ctx, values) => {
|
|
464
|
+
return this._getTracer().startActiveSpan("activitypub.dispatch_object", {
|
|
465
|
+
kind: SpanKind.SERVER,
|
|
466
|
+
attributes: {
|
|
467
|
+
"fedify.object.type": cls.typeId.href,
|
|
468
|
+
...globalThis.Object.fromEntries(globalThis.Object.entries(values).map(([k, v]) => [`fedify.object.values.${k}`, v]))
|
|
469
|
+
}
|
|
470
|
+
}, async (span) => {
|
|
471
|
+
try {
|
|
472
|
+
const object = await dispatcher(ctx, values);
|
|
473
|
+
span.setAttribute("activitypub.object.id", (object?.id ?? ctx.getObjectUri(cls, values)).href);
|
|
474
|
+
if (object == null) span.setStatus({ code: SpanStatusCode.ERROR });
|
|
475
|
+
else span.setAttribute("activitypub.object.type", getTypeId(object).href);
|
|
476
|
+
return object;
|
|
477
|
+
} catch (e) {
|
|
478
|
+
span.setStatus({
|
|
479
|
+
code: SpanStatusCode.ERROR,
|
|
480
|
+
message: String(e)
|
|
481
|
+
});
|
|
482
|
+
throw e;
|
|
483
|
+
} finally {
|
|
484
|
+
span.end();
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
},
|
|
488
|
+
parameters: variables
|
|
489
|
+
};
|
|
490
|
+
this.objectCallbacks[cls.typeId.href] = callbacks;
|
|
491
|
+
this.objectTypeIds[cls.typeId.href] = cls;
|
|
492
|
+
const setters = { authorize(predicate) {
|
|
493
|
+
callbacks.authorizePredicate = predicate;
|
|
494
|
+
return setters;
|
|
495
|
+
} };
|
|
496
|
+
return setters;
|
|
497
|
+
}
|
|
498
|
+
setInboxDispatcher(path, dispatcher) {
|
|
499
|
+
if (this.inboxCallbacks != null) throw new RouterError("Inbox dispatcher already set.");
|
|
500
|
+
if (this.router.has("inbox")) {
|
|
501
|
+
if (this.inboxPath !== path) throw new RouterError("Inbox dispatcher path must match inbox listener path.");
|
|
502
|
+
} else {
|
|
503
|
+
const variables = this.router.add(path, "inbox");
|
|
504
|
+
if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for inbox dispatcher must have one variable: {identifier}");
|
|
505
|
+
if (variables.has("handle")) getLogger([
|
|
506
|
+
"fedify",
|
|
507
|
+
"federation",
|
|
508
|
+
"inbox"
|
|
509
|
+
]).warn("The {{handle}} variable in the inbox dispatcher path is deprecated. Use {{identifier}} instead.");
|
|
510
|
+
this.inboxPath = path;
|
|
199
511
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
512
|
+
const callbacks = { dispatcher };
|
|
513
|
+
this.inboxCallbacks = callbacks;
|
|
514
|
+
const setters = {
|
|
515
|
+
setCounter(counter) {
|
|
516
|
+
callbacks.counter = counter;
|
|
517
|
+
return setters;
|
|
518
|
+
},
|
|
519
|
+
setFirstCursor(cursor) {
|
|
520
|
+
callbacks.firstCursor = cursor;
|
|
521
|
+
return setters;
|
|
522
|
+
},
|
|
523
|
+
setLastCursor(cursor) {
|
|
524
|
+
callbacks.lastCursor = cursor;
|
|
525
|
+
return setters;
|
|
526
|
+
},
|
|
527
|
+
authorize(predicate) {
|
|
528
|
+
callbacks.authorizePredicate = predicate;
|
|
529
|
+
return setters;
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
return setters;
|
|
213
533
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
534
|
+
setOutboxDispatcher(path, dispatcher) {
|
|
535
|
+
if (this.router.has("outbox")) throw new RouterError("Outbox dispatcher already set.");
|
|
536
|
+
const variables = this.router.add(path, "outbox");
|
|
537
|
+
if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for outbox dispatcher must have one variable: {identifier}");
|
|
538
|
+
if (variables.has("handle")) getLogger([
|
|
539
|
+
"fedify",
|
|
540
|
+
"federation",
|
|
541
|
+
"outbox"
|
|
542
|
+
]).warn("The {{handle}} variable in the outbox dispatcher path is deprecated. Use {{identifier}} instead.");
|
|
543
|
+
const callbacks = { dispatcher };
|
|
544
|
+
this.outboxCallbacks = callbacks;
|
|
545
|
+
const setters = {
|
|
546
|
+
setCounter(counter) {
|
|
547
|
+
callbacks.counter = counter;
|
|
548
|
+
return setters;
|
|
549
|
+
},
|
|
550
|
+
setFirstCursor(cursor) {
|
|
551
|
+
callbacks.firstCursor = cursor;
|
|
552
|
+
return setters;
|
|
553
|
+
},
|
|
554
|
+
setLastCursor(cursor) {
|
|
555
|
+
callbacks.lastCursor = cursor;
|
|
556
|
+
return setters;
|
|
557
|
+
},
|
|
558
|
+
authorize(predicate) {
|
|
559
|
+
callbacks.authorizePredicate = predicate;
|
|
560
|
+
return setters;
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
return setters;
|
|
218
564
|
}
|
|
219
|
-
|
|
220
|
-
if (
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
|
|
565
|
+
setFollowingDispatcher(path, dispatcher) {
|
|
566
|
+
if (this.router.has("following")) throw new RouterError("Following collection dispatcher already set.");
|
|
567
|
+
const variables = this.router.add(path, "following");
|
|
568
|
+
if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for following collection dispatcher must have one variable: {identifier}");
|
|
569
|
+
if (variables.has("handle")) getLogger([
|
|
570
|
+
"fedify",
|
|
571
|
+
"federation",
|
|
572
|
+
"collection"
|
|
573
|
+
]).warn("The {{handle}} variable in the following collection dispatcher path is deprecated. Use {{identifier}} instead.");
|
|
574
|
+
const callbacks = { dispatcher };
|
|
575
|
+
this.followingCallbacks = callbacks;
|
|
576
|
+
const setters = {
|
|
577
|
+
setCounter(counter) {
|
|
578
|
+
callbacks.counter = counter;
|
|
579
|
+
return setters;
|
|
580
|
+
},
|
|
581
|
+
setFirstCursor(cursor) {
|
|
582
|
+
callbacks.firstCursor = cursor;
|
|
583
|
+
return setters;
|
|
584
|
+
},
|
|
585
|
+
setLastCursor(cursor) {
|
|
586
|
+
callbacks.lastCursor = cursor;
|
|
587
|
+
return setters;
|
|
588
|
+
},
|
|
589
|
+
authorize(predicate) {
|
|
590
|
+
callbacks.authorizePredicate = predicate;
|
|
591
|
+
return setters;
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
return setters;
|
|
230
595
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
596
|
+
setFollowersDispatcher(path, dispatcher) {
|
|
597
|
+
if (this.router.has("followers")) throw new RouterError("Followers collection dispatcher already set.");
|
|
598
|
+
const variables = this.router.add(path, "followers");
|
|
599
|
+
if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for followers collection dispatcher must have one variable: {identifier}");
|
|
600
|
+
if (variables.has("handle")) getLogger([
|
|
601
|
+
"fedify",
|
|
602
|
+
"federation",
|
|
603
|
+
"collection"
|
|
604
|
+
]).warn("The {{handle}} variable in the followers collection dispatcher path is deprecated. Use {{identifier}} instead.");
|
|
605
|
+
const callbacks = { dispatcher };
|
|
606
|
+
this.followersCallbacks = callbacks;
|
|
607
|
+
const setters = {
|
|
608
|
+
setCounter(counter) {
|
|
609
|
+
callbacks.counter = counter;
|
|
610
|
+
return setters;
|
|
611
|
+
},
|
|
612
|
+
setFirstCursor(cursor) {
|
|
613
|
+
callbacks.firstCursor = cursor;
|
|
614
|
+
return setters;
|
|
615
|
+
},
|
|
616
|
+
setLastCursor(cursor) {
|
|
617
|
+
callbacks.lastCursor = cursor;
|
|
618
|
+
return setters;
|
|
619
|
+
},
|
|
620
|
+
authorize(predicate) {
|
|
621
|
+
callbacks.authorizePredicate = predicate;
|
|
622
|
+
return setters;
|
|
247
623
|
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (identifier == null) return await onNotFound(request);
|
|
251
|
-
const actor = await actorDispatcher(context$1, identifier);
|
|
252
|
-
if (actor == null) {
|
|
253
|
-
logger.error("Actor {identifier} not found.", { identifier });
|
|
254
|
-
return await onNotFound(request);
|
|
624
|
+
};
|
|
625
|
+
return setters;
|
|
255
626
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
627
|
+
setLikedDispatcher(path, dispatcher) {
|
|
628
|
+
if (this.router.has("liked")) throw new RouterError("Liked collection dispatcher already set.");
|
|
629
|
+
const variables = this.router.add(path, "liked");
|
|
630
|
+
if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for liked collection dispatcher must have one variable: {identifier}");
|
|
631
|
+
if (variables.has("handle")) getLogger([
|
|
632
|
+
"fedify",
|
|
633
|
+
"federation",
|
|
634
|
+
"collection"
|
|
635
|
+
]).warn("The {{handle}} variable in the liked collection dispatcher path is deprecated. Use {{identifier}} instead.");
|
|
636
|
+
const callbacks = { dispatcher };
|
|
637
|
+
this.likedCallbacks = callbacks;
|
|
638
|
+
const setters = {
|
|
639
|
+
setCounter(counter) {
|
|
640
|
+
callbacks.counter = counter;
|
|
641
|
+
return setters;
|
|
642
|
+
},
|
|
643
|
+
setFirstCursor(cursor) {
|
|
644
|
+
callbacks.firstCursor = cursor;
|
|
645
|
+
return setters;
|
|
646
|
+
},
|
|
647
|
+
setLastCursor(cursor) {
|
|
648
|
+
callbacks.lastCursor = cursor;
|
|
649
|
+
return setters;
|
|
650
|
+
},
|
|
651
|
+
authorize(predicate) {
|
|
652
|
+
callbacks.authorizePredicate = predicate;
|
|
653
|
+
return setters;
|
|
654
|
+
}
|
|
275
655
|
};
|
|
276
|
-
|
|
277
|
-
|
|
656
|
+
return setters;
|
|
657
|
+
}
|
|
658
|
+
setFeaturedDispatcher(path, dispatcher) {
|
|
659
|
+
if (this.router.has("featured")) throw new RouterError("Featured collection dispatcher already set.");
|
|
660
|
+
const variables = this.router.add(path, "featured");
|
|
661
|
+
if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for featured collection dispatcher must have one variable: {identifier}");
|
|
662
|
+
if (variables.has("handle")) getLogger([
|
|
663
|
+
"fedify",
|
|
664
|
+
"federation",
|
|
665
|
+
"collection"
|
|
666
|
+
]).warn("The {{handle}} variable in the featured collection dispatcher path is deprecated. Use {{identifier}} instead.");
|
|
667
|
+
const callbacks = { dispatcher };
|
|
668
|
+
this.featuredCallbacks = callbacks;
|
|
669
|
+
const setters = {
|
|
670
|
+
setCounter(counter) {
|
|
671
|
+
callbacks.counter = counter;
|
|
672
|
+
return setters;
|
|
673
|
+
},
|
|
674
|
+
setFirstCursor(cursor) {
|
|
675
|
+
callbacks.firstCursor = cursor;
|
|
676
|
+
return setters;
|
|
677
|
+
},
|
|
678
|
+
setLastCursor(cursor) {
|
|
679
|
+
callbacks.lastCursor = cursor;
|
|
680
|
+
return setters;
|
|
681
|
+
},
|
|
682
|
+
authorize(predicate) {
|
|
683
|
+
callbacks.authorizePredicate = predicate;
|
|
684
|
+
return setters;
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
return setters;
|
|
688
|
+
}
|
|
689
|
+
setFeaturedTagsDispatcher(path, dispatcher) {
|
|
690
|
+
if (this.router.has("featuredTags")) throw new RouterError("Featured tags collection dispatcher already set.");
|
|
691
|
+
const variables = this.router.add(path, "featuredTags");
|
|
692
|
+
if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for featured tags collection dispatcher must have one variable: {identifier}");
|
|
693
|
+
if (variables.has("handle")) getLogger([
|
|
694
|
+
"fedify",
|
|
695
|
+
"federation",
|
|
696
|
+
"collection"
|
|
697
|
+
]).warn("The {{handle}} variable in the featured tags collection dispatcher path is deprecated. Use {{identifier}} instead.");
|
|
698
|
+
const callbacks = { dispatcher };
|
|
699
|
+
this.featuredTagsCallbacks = callbacks;
|
|
700
|
+
const setters = {
|
|
701
|
+
setCounter(counter) {
|
|
702
|
+
callbacks.counter = counter;
|
|
703
|
+
return setters;
|
|
704
|
+
},
|
|
705
|
+
setFirstCursor(cursor) {
|
|
706
|
+
callbacks.firstCursor = cursor;
|
|
707
|
+
return setters;
|
|
708
|
+
},
|
|
709
|
+
setLastCursor(cursor) {
|
|
710
|
+
callbacks.lastCursor = cursor;
|
|
711
|
+
return setters;
|
|
712
|
+
},
|
|
713
|
+
authorize(predicate) {
|
|
714
|
+
callbacks.authorizePredicate = predicate;
|
|
715
|
+
return setters;
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
return setters;
|
|
719
|
+
}
|
|
720
|
+
setInboxListeners(inboxPath, sharedInboxPath) {
|
|
721
|
+
if (this.inboxListeners != null) throw new RouterError("Inbox listeners already set.");
|
|
722
|
+
if (this.router.has("inbox")) {
|
|
723
|
+
if (this.inboxPath !== inboxPath) throw new RouterError("Inbox listener path must match inbox dispatcher path.");
|
|
724
|
+
} else {
|
|
725
|
+
const variables = this.router.add(inboxPath, "inbox");
|
|
726
|
+
if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for inbox must have one variable: {identifier}");
|
|
727
|
+
this.inboxPath = inboxPath;
|
|
728
|
+
if (variables.has("handle")) getLogger([
|
|
729
|
+
"fedify",
|
|
730
|
+
"federation",
|
|
731
|
+
"inbox"
|
|
732
|
+
]).warn("The {{handle}} variable in the inbox path is deprecated. Use {{identifier}} instead.");
|
|
733
|
+
}
|
|
734
|
+
if (sharedInboxPath != null) {
|
|
735
|
+
if (this.router.add(sharedInboxPath, "sharedInbox").size !== 0) throw new RouterError("Path for shared inbox must have no variables.");
|
|
736
|
+
}
|
|
737
|
+
const listeners = this.inboxListeners = new InboxListenerSet();
|
|
738
|
+
const setters = {
|
|
739
|
+
on(type, listener) {
|
|
740
|
+
listeners.add(type, listener);
|
|
741
|
+
return setters;
|
|
742
|
+
},
|
|
743
|
+
onError: (handler) => {
|
|
744
|
+
this.inboxErrorHandler = handler;
|
|
745
|
+
return setters;
|
|
746
|
+
},
|
|
747
|
+
setSharedKeyDispatcher: (dispatcher) => {
|
|
748
|
+
this.sharedInboxKeyDispatcher = dispatcher;
|
|
749
|
+
return setters;
|
|
750
|
+
}
|
|
751
|
+
};
|
|
752
|
+
return setters;
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
/**
|
|
756
|
+
* Creates a new {@link FederationBuilder} instance.
|
|
757
|
+
* @returns A new {@link FederationBuilder} instance.
|
|
758
|
+
* @since 1.6.0
|
|
759
|
+
*/
|
|
760
|
+
function createFederationBuilder() {
|
|
761
|
+
return new FederationBuilderImpl();
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
//#endregion
|
|
765
|
+
//#region federation/collection.ts
|
|
766
|
+
/**
|
|
767
|
+
* Calculates the [partial follower collection digest][1].
|
|
768
|
+
*
|
|
769
|
+
* [1]: https://w3id.org/fep/8fcf#partial-follower-collection-digest
|
|
770
|
+
* @param uris The URIs to calculate the digest. Duplicate URIs are ignored.
|
|
771
|
+
* @returns The digest.
|
|
772
|
+
*/
|
|
773
|
+
async function digest(uris) {
|
|
774
|
+
const processed = /* @__PURE__ */ new Set();
|
|
775
|
+
const encoder = new TextEncoder();
|
|
776
|
+
const result = new Uint8Array(32);
|
|
777
|
+
for (const uri of uris) {
|
|
778
|
+
const u = uri instanceof URL ? uri.href : uri;
|
|
779
|
+
if (processed.has(u)) continue;
|
|
780
|
+
processed.add(u);
|
|
781
|
+
const encoded = encoder.encode(u);
|
|
782
|
+
const digest$1 = new Uint8Array(await crypto.subtle.digest("SHA-256", encoded));
|
|
783
|
+
for (let i = 0; i < 32; i++) result[i] ^= digest$1[i];
|
|
784
|
+
}
|
|
785
|
+
return result;
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Builds [`Collection-Synchronization`][1] header content.
|
|
789
|
+
*
|
|
790
|
+
* [1]: https://w3id.org/fep/8fcf#the-collection-synchronization-http-header
|
|
791
|
+
*
|
|
792
|
+
* @param collectionId The sender's followers collection URI.
|
|
793
|
+
* @param actorIds The actor URIs to digest.
|
|
794
|
+
* @returns The header content.
|
|
795
|
+
*/
|
|
796
|
+
async function buildCollectionSynchronizationHeader(collectionId, actorIds) {
|
|
797
|
+
const [anyActorId] = actorIds;
|
|
798
|
+
const baseUrl = new URL(anyActorId);
|
|
799
|
+
const url = new URL(collectionId);
|
|
800
|
+
url.searchParams.set("base-url", `${baseUrl.origin}/`);
|
|
801
|
+
return `collectionId="${collectionId}", url="${url}", digest="${encodeHex(await digest(actorIds))}"`;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
//#endregion
|
|
805
|
+
//#region federation/keycache.ts
|
|
806
|
+
var KvKeyCache = class {
|
|
807
|
+
kv;
|
|
808
|
+
prefix;
|
|
809
|
+
options;
|
|
810
|
+
nullKeys;
|
|
811
|
+
constructor(kv, prefix, options = {}) {
|
|
812
|
+
this.kv = kv;
|
|
813
|
+
this.prefix = prefix;
|
|
814
|
+
this.nullKeys = /* @__PURE__ */ new Set();
|
|
815
|
+
this.options = options;
|
|
278
816
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (
|
|
817
|
+
async get(keyId) {
|
|
818
|
+
if (this.nullKeys.has(keyId.href)) return null;
|
|
819
|
+
const serialized = await this.kv.get([...this.prefix, keyId.href]);
|
|
820
|
+
if (serialized == null) return void 0;
|
|
821
|
+
try {
|
|
822
|
+
return await CryptographicKey.fromJsonLd(serialized, this.options);
|
|
823
|
+
} catch {
|
|
824
|
+
try {
|
|
825
|
+
return await Multikey.fromJsonLd(serialized, this.options);
|
|
826
|
+
} catch {
|
|
827
|
+
await this.kv.delete([...this.prefix, keyId.href]);
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
283
831
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
832
|
+
async set(keyId, key) {
|
|
833
|
+
if (key == null) {
|
|
834
|
+
this.nullKeys.add(keyId.href);
|
|
835
|
+
await this.kv.delete([...this.prefix, keyId.href]);
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
this.nullKeys.delete(keyId.href);
|
|
839
|
+
const serialized = await key.toJsonLd(this.options);
|
|
840
|
+
await this.kv.set([...this.prefix, keyId.href], serialized);
|
|
288
841
|
}
|
|
289
|
-
|
|
290
|
-
subject: resourceUrl.href,
|
|
291
|
-
aliases,
|
|
292
|
-
links
|
|
293
|
-
};
|
|
294
|
-
return new Response(JSON.stringify(jrd), { headers: {
|
|
295
|
-
"Content-Type": "application/jrd+json",
|
|
296
|
-
"Access-Control-Allow-Origin": "*"
|
|
297
|
-
} });
|
|
298
|
-
}
|
|
842
|
+
};
|
|
299
843
|
|
|
300
844
|
//#endregion
|
|
301
845
|
//#region federation/negotiation.ts
|
|
@@ -364,18 +908,18 @@ function acceptsJsonLd(request) {
|
|
|
364
908
|
return types.includes("application/activity+json") || types.includes("application/ld+json") || types.includes("application/json");
|
|
365
909
|
}
|
|
366
910
|
async function handleActor(request, { identifier, context: context$1, actorDispatcher, authorizePredicate, onNotFound, onNotAcceptable, onUnauthorized }) {
|
|
367
|
-
const logger$
|
|
911
|
+
const logger$1 = getLogger([
|
|
368
912
|
"fedify",
|
|
369
913
|
"federation",
|
|
370
914
|
"actor"
|
|
371
915
|
]);
|
|
372
916
|
if (actorDispatcher == null) {
|
|
373
|
-
logger$
|
|
917
|
+
logger$1.debug("Actor dispatcher is not set.", { identifier });
|
|
374
918
|
return await onNotFound(request);
|
|
375
919
|
}
|
|
376
920
|
const actor = await actorDispatcher(context$1, identifier);
|
|
377
921
|
if (actor == null) {
|
|
378
|
-
logger$
|
|
922
|
+
logger$1.debug("Actor {identifier} not found.", { identifier });
|
|
379
923
|
return await onNotFound(request);
|
|
380
924
|
}
|
|
381
925
|
if (!acceptsJsonLd(request)) return await onNotAcceptable(request);
|
|
@@ -621,13 +1165,13 @@ async function handleInbox(request, options) {
|
|
|
621
1165
|
});
|
|
622
1166
|
}
|
|
623
1167
|
async function handleInboxInternal(request, { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, tracerProvider }, span) {
|
|
624
|
-
const logger$
|
|
1168
|
+
const logger$1 = getLogger([
|
|
625
1169
|
"fedify",
|
|
626
1170
|
"federation",
|
|
627
1171
|
"inbox"
|
|
628
1172
|
]);
|
|
629
1173
|
if (actorDispatcher == null) {
|
|
630
|
-
logger$
|
|
1174
|
+
logger$1.error("Actor dispatcher is not set.", { recipient });
|
|
631
1175
|
span.setStatus({
|
|
632
1176
|
code: SpanStatusCode.ERROR,
|
|
633
1177
|
message: "Actor dispatcher is not set."
|
|
@@ -635,7 +1179,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
635
1179
|
return await onNotFound(request);
|
|
636
1180
|
} else if (recipient != null) {
|
|
637
1181
|
if (await actorDispatcher(ctx, recipient) == null) {
|
|
638
|
-
logger$
|
|
1182
|
+
logger$1.error("Actor {recipient} not found.", { recipient });
|
|
639
1183
|
span.setStatus({
|
|
640
1184
|
code: SpanStatusCode.ERROR,
|
|
641
1185
|
message: `Actor ${recipient} not found.`
|
|
@@ -644,7 +1188,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
644
1188
|
}
|
|
645
1189
|
}
|
|
646
1190
|
if (request.bodyUsed) {
|
|
647
|
-
logger$
|
|
1191
|
+
logger$1.error("Request body has already been read.", { recipient });
|
|
648
1192
|
span.setStatus({
|
|
649
1193
|
code: SpanStatusCode.ERROR,
|
|
650
1194
|
message: "Request body has already been read."
|
|
@@ -654,7 +1198,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
654
1198
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
655
1199
|
});
|
|
656
1200
|
} else if (request.body?.locked) {
|
|
657
|
-
logger$
|
|
1201
|
+
logger$1.error("Request body is locked.", { recipient });
|
|
658
1202
|
span.setStatus({
|
|
659
1203
|
code: SpanStatusCode.ERROR,
|
|
660
1204
|
message: "Request body is locked."
|
|
@@ -668,14 +1212,14 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
668
1212
|
try {
|
|
669
1213
|
json = await request.clone().json();
|
|
670
1214
|
} catch (error) {
|
|
671
|
-
logger$
|
|
1215
|
+
logger$1.error("Failed to parse JSON:\n{error}", {
|
|
672
1216
|
recipient,
|
|
673
1217
|
error
|
|
674
1218
|
});
|
|
675
1219
|
try {
|
|
676
1220
|
await inboxErrorHandler?.(ctx, error);
|
|
677
1221
|
} catch (error$1) {
|
|
678
|
-
logger$
|
|
1222
|
+
logger$1.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
679
1223
|
error: error$1,
|
|
680
1224
|
activity: json,
|
|
681
1225
|
recipient
|
|
@@ -701,7 +1245,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
701
1245
|
});
|
|
702
1246
|
} catch (error) {
|
|
703
1247
|
if (error instanceof Error && error.name === "jsonld.SyntaxError") {
|
|
704
|
-
logger$
|
|
1248
|
+
logger$1.error("Failed to parse JSON-LD:\n{error}", {
|
|
705
1249
|
recipient,
|
|
706
1250
|
error
|
|
707
1251
|
});
|
|
@@ -715,13 +1259,13 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
715
1259
|
const jsonWithoutSig = detachSignature(json);
|
|
716
1260
|
let activity = null;
|
|
717
1261
|
if (ldSigVerified) {
|
|
718
|
-
logger$
|
|
1262
|
+
logger$1.debug("Linked Data Signatures are verified.", {
|
|
719
1263
|
recipient,
|
|
720
1264
|
json
|
|
721
1265
|
});
|
|
722
1266
|
activity = await Activity.fromJsonLd(jsonWithoutSig, ctx);
|
|
723
1267
|
} else {
|
|
724
|
-
logger$
|
|
1268
|
+
logger$1.debug("Linked Data Signatures are not verified.", {
|
|
725
1269
|
recipient,
|
|
726
1270
|
json
|
|
727
1271
|
});
|
|
@@ -733,7 +1277,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
733
1277
|
tracerProvider
|
|
734
1278
|
});
|
|
735
1279
|
} catch (error) {
|
|
736
|
-
logger$
|
|
1280
|
+
logger$1.error("Failed to parse activity:\n{error}", {
|
|
737
1281
|
recipient,
|
|
738
1282
|
activity: json,
|
|
739
1283
|
error
|
|
@@ -741,7 +1285,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
741
1285
|
try {
|
|
742
1286
|
await inboxErrorHandler?.(ctx, error);
|
|
743
1287
|
} catch (error$1) {
|
|
744
|
-
logger$
|
|
1288
|
+
logger$1.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
745
1289
|
error: error$1,
|
|
746
1290
|
activity: json,
|
|
747
1291
|
recipient
|
|
@@ -756,11 +1300,11 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
756
1300
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
757
1301
|
});
|
|
758
1302
|
}
|
|
759
|
-
if (activity == null) logger$
|
|
1303
|
+
if (activity == null) logger$1.debug("Object Integrity Proofs are not verified.", {
|
|
760
1304
|
recipient,
|
|
761
1305
|
activity: json
|
|
762
1306
|
});
|
|
763
|
-
else logger$
|
|
1307
|
+
else logger$1.debug("Object Integrity Proofs are verified.", {
|
|
764
1308
|
recipient,
|
|
765
1309
|
activity: json
|
|
766
1310
|
});
|
|
@@ -776,7 +1320,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
776
1320
|
tracerProvider
|
|
777
1321
|
});
|
|
778
1322
|
if (key == null) {
|
|
779
|
-
logger$
|
|
1323
|
+
logger$1.error("Failed to verify the request's HTTP Signatures.", { recipient });
|
|
780
1324
|
span.setStatus({
|
|
781
1325
|
code: SpanStatusCode.ERROR,
|
|
782
1326
|
message: `Failed to verify the request's HTTP Signatures.`
|
|
@@ -785,7 +1329,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
785
1329
|
status: 401,
|
|
786
1330
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
787
1331
|
});
|
|
788
|
-
} else logger$
|
|
1332
|
+
} else logger$1.debug("HTTP Signatures are verified.", { recipient });
|
|
789
1333
|
httpSigKey = key;
|
|
790
1334
|
}
|
|
791
1335
|
activity = await Activity.fromJsonLd(jsonWithoutSig, ctx);
|
|
@@ -793,7 +1337,7 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
793
1337
|
if (activity.id != null) span.setAttribute("activitypub.activity.id", activity.id.href);
|
|
794
1338
|
span.setAttribute("activitypub.activity.type", getTypeId(activity).href);
|
|
795
1339
|
if (httpSigKey != null && !await doesActorOwnKey(activity, httpSigKey, ctx)) {
|
|
796
|
-
logger$
|
|
1340
|
+
logger$1.error("The signer ({keyId}) and the actor ({actorId}) do not match.", {
|
|
797
1341
|
activity: json,
|
|
798
1342
|
recipient,
|
|
799
1343
|
keyId: httpSigKey.id?.href,
|
|
@@ -874,6 +1418,320 @@ async function respondWithObjectIfAcceptable(object, request, options) {
|
|
|
874
1418
|
return response;
|
|
875
1419
|
}
|
|
876
1420
|
|
|
1421
|
+
//#endregion
|
|
1422
|
+
//#region nodeinfo/handler.ts
|
|
1423
|
+
/**
|
|
1424
|
+
* Handles a NodeInfo request. You would not typically call this function
|
|
1425
|
+
* directly, but instead use {@link Federation.handle} method.
|
|
1426
|
+
* @param request The NodeInfo request to handle.
|
|
1427
|
+
* @param parameters The parameters for handling the request.
|
|
1428
|
+
* @returns The response to the request.
|
|
1429
|
+
*/
|
|
1430
|
+
async function handleNodeInfo(_request, { context: context$1, nodeInfoDispatcher }) {
|
|
1431
|
+
const promise = nodeInfoDispatcher(context$1);
|
|
1432
|
+
const json = nodeInfoToJson(promise instanceof Promise ? await promise : promise);
|
|
1433
|
+
return new Response(JSON.stringify(json), { headers: { "Content-Type": "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\"" } });
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* Handles a request to `/.well-known/nodeinfo`. You would not typically call
|
|
1437
|
+
* this function directly, but instead use {@link Federation.handle} method.
|
|
1438
|
+
* @param request The request to handle.
|
|
1439
|
+
* @param context The request context.
|
|
1440
|
+
* @returns The response to the request.
|
|
1441
|
+
*/
|
|
1442
|
+
function handleNodeInfoJrd(_request, context$1) {
|
|
1443
|
+
const links = [];
|
|
1444
|
+
try {
|
|
1445
|
+
links.push({
|
|
1446
|
+
rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
|
|
1447
|
+
href: context$1.getNodeInfoUri().href,
|
|
1448
|
+
type: "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\""
|
|
1449
|
+
});
|
|
1450
|
+
} catch (e) {
|
|
1451
|
+
if (!(e instanceof RouterError)) throw e;
|
|
1452
|
+
}
|
|
1453
|
+
const jrd = { links };
|
|
1454
|
+
const response = new Response(JSON.stringify(jrd), { headers: { "Content-Type": "application/jrd+json" } });
|
|
1455
|
+
return Promise.resolve(response);
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
//#endregion
|
|
1459
|
+
//#region webfinger/handler.ts
|
|
1460
|
+
const logger = getLogger([
|
|
1461
|
+
"fedify",
|
|
1462
|
+
"webfinger",
|
|
1463
|
+
"server"
|
|
1464
|
+
]);
|
|
1465
|
+
/**
|
|
1466
|
+
* Handles a WebFinger request. You would not typically call this function
|
|
1467
|
+
* directly, but instead use {@link Federation.fetch} method.
|
|
1468
|
+
* @param request The WebFinger request to handle.
|
|
1469
|
+
* @param parameters The parameters for handling the request.
|
|
1470
|
+
* @returns The response to the request.
|
|
1471
|
+
*/
|
|
1472
|
+
async function handleWebFinger(request, options) {
|
|
1473
|
+
if (options.tracer == null) return await handleWebFingerInternal(request, options);
|
|
1474
|
+
return await options.tracer.startActiveSpan("webfinger.handle", { kind: SpanKind.SERVER }, async (span) => {
|
|
1475
|
+
try {
|
|
1476
|
+
const response = await handleWebFingerInternal(request, options);
|
|
1477
|
+
span.setStatus({ code: response.ok ? SpanStatusCode.UNSET : SpanStatusCode.ERROR });
|
|
1478
|
+
return response;
|
|
1479
|
+
} catch (error) {
|
|
1480
|
+
span.setStatus({
|
|
1481
|
+
code: SpanStatusCode.ERROR,
|
|
1482
|
+
message: String(error)
|
|
1483
|
+
});
|
|
1484
|
+
throw error;
|
|
1485
|
+
} finally {
|
|
1486
|
+
span.end();
|
|
1487
|
+
}
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
async function handleWebFingerInternal(request, { context: context$1, host, actorDispatcher, actorHandleMapper, actorAliasMapper, onNotFound, span }) {
|
|
1491
|
+
if (actorDispatcher == null) return await onNotFound(request);
|
|
1492
|
+
const resource = context$1.url.searchParams.get("resource");
|
|
1493
|
+
if (resource == null) return new Response("Missing resource parameter.", { status: 400 });
|
|
1494
|
+
span?.setAttribute("webfinger.resource", resource);
|
|
1495
|
+
let resourceUrl;
|
|
1496
|
+
try {
|
|
1497
|
+
resourceUrl = new URL(resource);
|
|
1498
|
+
} catch (e) {
|
|
1499
|
+
if (e instanceof TypeError) return new Response("Invalid resource URL.", { status: 400 });
|
|
1500
|
+
throw e;
|
|
1501
|
+
}
|
|
1502
|
+
span?.setAttribute("webfinger.resource.scheme", resourceUrl.protocol.replace(/:$/, ""));
|
|
1503
|
+
if (actorDispatcher == null) {
|
|
1504
|
+
logger.error("Actor dispatcher is not set.");
|
|
1505
|
+
return await onNotFound(request);
|
|
1506
|
+
}
|
|
1507
|
+
async function mapUsernameToIdentifier(username) {
|
|
1508
|
+
if (actorHandleMapper == null) {
|
|
1509
|
+
logger.error("No actor handle mapper is set; use the WebFinger username {username} as the actor's internal identifier.", { username });
|
|
1510
|
+
return username;
|
|
1511
|
+
}
|
|
1512
|
+
const identifier$1 = await actorHandleMapper(context$1, username);
|
|
1513
|
+
if (identifier$1 == null) {
|
|
1514
|
+
logger.error("Actor {username} not found.", { username });
|
|
1515
|
+
return null;
|
|
1516
|
+
}
|
|
1517
|
+
return identifier$1;
|
|
1518
|
+
}
|
|
1519
|
+
let identifier = null;
|
|
1520
|
+
const uriParsed = context$1.parseUri(resourceUrl);
|
|
1521
|
+
if (uriParsed?.type != "actor") {
|
|
1522
|
+
const match = /^acct:([^@]+)@([^@]+)$/.exec(resource);
|
|
1523
|
+
if (match == null) {
|
|
1524
|
+
const result = await actorAliasMapper?.(context$1, resourceUrl);
|
|
1525
|
+
if (result == null) return await onNotFound(request);
|
|
1526
|
+
if ("identifier" in result) identifier = result.identifier;
|
|
1527
|
+
else identifier = await mapUsernameToIdentifier(result.username);
|
|
1528
|
+
} else {
|
|
1529
|
+
const portMatch = /:\d+$/.exec(match[2]);
|
|
1530
|
+
const normalizedHost = portMatch == null ? domainToASCII(match[2].toLowerCase()) : domainToASCII(match[2].substring(0, portMatch.index).toLowerCase()) + portMatch[0];
|
|
1531
|
+
if (normalizedHost != context$1.url.host && normalizedHost != host) return await onNotFound(request);
|
|
1532
|
+
else {
|
|
1533
|
+
identifier = await mapUsernameToIdentifier(match[1]);
|
|
1534
|
+
resourceUrl = new URL(`acct:${match[1]}@${normalizedHost}`);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
} else identifier = uriParsed.identifier;
|
|
1538
|
+
if (identifier == null) return await onNotFound(request);
|
|
1539
|
+
const actor = await actorDispatcher(context$1, identifier);
|
|
1540
|
+
if (actor == null) {
|
|
1541
|
+
logger.error("Actor {identifier} not found.", { identifier });
|
|
1542
|
+
return await onNotFound(request);
|
|
1543
|
+
}
|
|
1544
|
+
const links = [{
|
|
1545
|
+
rel: "self",
|
|
1546
|
+
href: context$1.getActorUri(identifier).href,
|
|
1547
|
+
type: "application/activity+json"
|
|
1548
|
+
}];
|
|
1549
|
+
for (const url of actor.urls) if (url instanceof Link && url.href != null) links.push({
|
|
1550
|
+
rel: url.rel ?? "http://webfinger.net/rel/profile-page",
|
|
1551
|
+
href: url.href.href,
|
|
1552
|
+
type: url.mediaType == null ? void 0 : url.mediaType
|
|
1553
|
+
});
|
|
1554
|
+
else if (url instanceof URL) links.push({
|
|
1555
|
+
rel: "http://webfinger.net/rel/profile-page",
|
|
1556
|
+
href: url.href
|
|
1557
|
+
});
|
|
1558
|
+
for await (const image of actor.getIcons()) {
|
|
1559
|
+
if (image.url?.href == null) continue;
|
|
1560
|
+
const link = {
|
|
1561
|
+
rel: "http://webfinger.net/rel/avatar",
|
|
1562
|
+
href: image.url.href.toString()
|
|
1563
|
+
};
|
|
1564
|
+
if (image.mediaType != null) link.type = image.mediaType;
|
|
1565
|
+
links.push(link);
|
|
1566
|
+
}
|
|
1567
|
+
const aliases = [];
|
|
1568
|
+
if (resourceUrl.protocol != "acct:" && actor.preferredUsername != null) {
|
|
1569
|
+
aliases.push(`acct:${actor.preferredUsername}@${host ?? context$1.url.host}`);
|
|
1570
|
+
if (host != null && host !== context$1.url.host) aliases.push(`acct:${actor.preferredUsername}@${context$1.url.host}`);
|
|
1571
|
+
}
|
|
1572
|
+
if (resourceUrl.href !== context$1.getActorUri(identifier).href) aliases.push(context$1.getActorUri(identifier).href);
|
|
1573
|
+
if (resourceUrl.protocol === "acct:" && host != null && host !== context$1.url.host && !resourceUrl.href.endsWith(`@${host}`)) {
|
|
1574
|
+
const username = resourceUrl.href.replace(/^acct:/, "").replace(/@.*$/, "");
|
|
1575
|
+
aliases.push(`acct:${username}@${host}`);
|
|
1576
|
+
}
|
|
1577
|
+
const jrd = {
|
|
1578
|
+
subject: resourceUrl.href,
|
|
1579
|
+
aliases,
|
|
1580
|
+
links
|
|
1581
|
+
};
|
|
1582
|
+
return new Response(JSON.stringify(jrd), { headers: {
|
|
1583
|
+
"Content-Type": "application/jrd+json",
|
|
1584
|
+
"Access-Control-Allow-Origin": "*"
|
|
1585
|
+
} });
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
//#endregion
|
|
1589
|
+
//#region federation/retry.ts
|
|
1590
|
+
/**
|
|
1591
|
+
* Creates an exponential backoff retry policy. The delay between retries
|
|
1592
|
+
* starts at the `initialDelay` and is multiplied by the `factor` for each
|
|
1593
|
+
* subsequent retry, up to the `maxDelay`. The policy will give up after
|
|
1594
|
+
* `maxAttempts` attempts. The actual delay is randomized to avoid
|
|
1595
|
+
* synchronization (jitter).
|
|
1596
|
+
* @param options The options for the policy.
|
|
1597
|
+
* @returns The retry policy.
|
|
1598
|
+
* @since 0.12.0
|
|
1599
|
+
*/
|
|
1600
|
+
function createExponentialBackoffPolicy(options = {}) {
|
|
1601
|
+
const initialDelay = Temporal.Duration.from(options.initialDelay ?? { seconds: 1 });
|
|
1602
|
+
const maxDelay = Temporal.Duration.from(options.maxDelay ?? { hours: 12 });
|
|
1603
|
+
const maxAttempts = options.maxAttempts ?? 10;
|
|
1604
|
+
const factor = options.factor ?? 2;
|
|
1605
|
+
const jitter = options.jitter ?? true;
|
|
1606
|
+
return ({ attempts }) => {
|
|
1607
|
+
if (attempts >= maxAttempts) return null;
|
|
1608
|
+
let milliseconds = initialDelay.total("millisecond");
|
|
1609
|
+
milliseconds *= factor ** attempts;
|
|
1610
|
+
if (jitter) {
|
|
1611
|
+
milliseconds *= 1 + Math.random();
|
|
1612
|
+
milliseconds = Math.round(milliseconds);
|
|
1613
|
+
}
|
|
1614
|
+
const delay$1 = Temporal.Duration.from({ milliseconds });
|
|
1615
|
+
return Temporal.Duration.compare(delay$1, maxDelay) > 0 ? maxDelay : delay$1;
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
//#endregion
|
|
1620
|
+
//#region federation/send.ts
|
|
1621
|
+
/**
|
|
1622
|
+
* Extracts the inbox URLs from recipients.
|
|
1623
|
+
* @param parameters The parameters to extract the inboxes.
|
|
1624
|
+
* See also {@link ExtractInboxesParameters}.
|
|
1625
|
+
* @returns The inboxes as a map of inbox URL to actor URIs.
|
|
1626
|
+
*/
|
|
1627
|
+
function extractInboxes({ recipients, preferSharedInbox, excludeBaseUris }) {
|
|
1628
|
+
const inboxes = {};
|
|
1629
|
+
for (const recipient of recipients) {
|
|
1630
|
+
let inbox;
|
|
1631
|
+
let sharedInbox = false;
|
|
1632
|
+
if (preferSharedInbox && recipient.endpoints?.sharedInbox != null) {
|
|
1633
|
+
inbox = recipient.endpoints.sharedInbox;
|
|
1634
|
+
sharedInbox = true;
|
|
1635
|
+
} else inbox = recipient.inboxId;
|
|
1636
|
+
if (inbox != null && recipient.id != null) {
|
|
1637
|
+
if (excludeBaseUris != null && excludeBaseUris.some((u) => u.origin === inbox?.origin)) continue;
|
|
1638
|
+
inboxes[inbox.href] ??= {
|
|
1639
|
+
actorIds: /* @__PURE__ */ new Set(),
|
|
1640
|
+
sharedInbox
|
|
1641
|
+
};
|
|
1642
|
+
inboxes[inbox.href].actorIds.add(recipient.id.href);
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
return inboxes;
|
|
1646
|
+
}
|
|
1647
|
+
/**
|
|
1648
|
+
* Sends an {@link Activity} to an inbox.
|
|
1649
|
+
*
|
|
1650
|
+
* @param parameters The parameters for sending the activity.
|
|
1651
|
+
* See also {@link SendActivityParameters}.
|
|
1652
|
+
* @throws {Error} If the activity fails to send.
|
|
1653
|
+
*/
|
|
1654
|
+
function sendActivity(options) {
|
|
1655
|
+
const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
|
|
1656
|
+
return tracerProvider.getTracer(name, version).startActiveSpan("activitypub.send_activity", {
|
|
1657
|
+
kind: SpanKind.CLIENT,
|
|
1658
|
+
attributes: { "activitypub.shared_inbox": options.sharedInbox ?? false }
|
|
1659
|
+
}, async (span) => {
|
|
1660
|
+
if (options.activityId != null) span.setAttribute("activitypub.activity.id", options.activityId);
|
|
1661
|
+
if (options.activityType != null) span.setAttribute("activitypub.activity.type", options.activityType);
|
|
1662
|
+
try {
|
|
1663
|
+
await sendActivityInternal({
|
|
1664
|
+
...options,
|
|
1665
|
+
tracerProvider
|
|
1666
|
+
});
|
|
1667
|
+
} catch (e) {
|
|
1668
|
+
span.setStatus({
|
|
1669
|
+
code: SpanStatusCode.ERROR,
|
|
1670
|
+
message: String(e)
|
|
1671
|
+
});
|
|
1672
|
+
throw e;
|
|
1673
|
+
} finally {
|
|
1674
|
+
span.end();
|
|
1675
|
+
}
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
async function sendActivityInternal({ activity, activityId, keys, inbox, headers, specDeterminer, tracerProvider }) {
|
|
1679
|
+
const logger$1 = getLogger([
|
|
1680
|
+
"fedify",
|
|
1681
|
+
"federation",
|
|
1682
|
+
"outbox"
|
|
1683
|
+
]);
|
|
1684
|
+
headers = new Headers(headers);
|
|
1685
|
+
headers.set("Content-Type", "application/activity+json");
|
|
1686
|
+
const request = new Request(inbox, {
|
|
1687
|
+
method: "POST",
|
|
1688
|
+
headers,
|
|
1689
|
+
body: JSON.stringify(activity)
|
|
1690
|
+
});
|
|
1691
|
+
let rsaKey = null;
|
|
1692
|
+
for (const key of keys) if (key.privateKey.algorithm.name === "RSASSA-PKCS1-v1_5") {
|
|
1693
|
+
rsaKey = key;
|
|
1694
|
+
break;
|
|
1695
|
+
}
|
|
1696
|
+
if (rsaKey == null) logger$1.warn("No supported key found to sign the request to {inbox}. The request will be sent without a signature. In order to sign the request, at least one RSASSA-PKCS1-v1_5 key must be provided.", {
|
|
1697
|
+
inbox: inbox.href,
|
|
1698
|
+
keys: keys.map((pair) => ({
|
|
1699
|
+
keyId: pair.keyId.href,
|
|
1700
|
+
privateKey: pair.privateKey
|
|
1701
|
+
}))
|
|
1702
|
+
});
|
|
1703
|
+
let response;
|
|
1704
|
+
try {
|
|
1705
|
+
response = rsaKey == null ? await fetch(request) : await doubleKnock(request, rsaKey, {
|
|
1706
|
+
tracerProvider,
|
|
1707
|
+
specDeterminer
|
|
1708
|
+
});
|
|
1709
|
+
} catch (error) {
|
|
1710
|
+
logger$1.error("Failed to send activity {activityId} to {inbox}:\n{error}", {
|
|
1711
|
+
activityId,
|
|
1712
|
+
inbox: inbox.href,
|
|
1713
|
+
error
|
|
1714
|
+
});
|
|
1715
|
+
throw error;
|
|
1716
|
+
}
|
|
1717
|
+
if (!response.ok) {
|
|
1718
|
+
let error;
|
|
1719
|
+
try {
|
|
1720
|
+
error = await response.text();
|
|
1721
|
+
} catch (_) {
|
|
1722
|
+
error = "";
|
|
1723
|
+
}
|
|
1724
|
+
logger$1.error("Failed to send activity {activityId} to {inbox} ({status} {statusText}):\n{error}", {
|
|
1725
|
+
activityId,
|
|
1726
|
+
inbox: inbox.href,
|
|
1727
|
+
status: response.status,
|
|
1728
|
+
statusText: response.statusText,
|
|
1729
|
+
error
|
|
1730
|
+
});
|
|
1731
|
+
throw new Error(`Failed to send activity ${activityId} to ${inbox.href} (${response.status} ${response.statusText}):\n${error}`);
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
|
|
877
1735
|
//#endregion
|
|
878
1736
|
//#region federation/middleware.ts
|
|
879
1737
|
/**
|
|
@@ -911,7 +1769,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
911
1769
|
firstKnock;
|
|
912
1770
|
constructor(options) {
|
|
913
1771
|
super();
|
|
914
|
-
const logger$
|
|
1772
|
+
const logger$1 = getLogger(["fedify", "federation"]);
|
|
915
1773
|
this.kv = options.kv;
|
|
916
1774
|
this.kvPrefixes = {
|
|
917
1775
|
activityIdempotence: ["_fedify", "activityIdempotence"],
|
|
@@ -968,7 +1826,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
968
1826
|
if (options.documentLoader != null) {
|
|
969
1827
|
if (options.documentLoaderFactory != null) throw new TypeError("Cannot set both documentLoader and documentLoaderFactory options at a time; use documentLoaderFactory only.");
|
|
970
1828
|
this.documentLoaderFactory = () => options.documentLoader;
|
|
971
|
-
logger$
|
|
1829
|
+
logger$1.warn("The documentLoader option is deprecated; use documentLoaderFactory option instead.");
|
|
972
1830
|
} else this.documentLoaderFactory = options.documentLoaderFactory ?? ((opts) => {
|
|
973
1831
|
return kvCache({
|
|
974
1832
|
loader: getDocumentLoader({
|
|
@@ -982,7 +1840,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
982
1840
|
if (options.contextLoader != null) {
|
|
983
1841
|
if (options.contextLoaderFactory != null) throw new TypeError("Cannot set both contextLoader and contextLoaderFactory options at a time; use contextLoaderFactory only.");
|
|
984
1842
|
this.contextLoaderFactory = () => options.contextLoader;
|
|
985
|
-
logger$
|
|
1843
|
+
logger$1.warn("The contextLoader option is deprecated; use contextLoaderFactory option instead.");
|
|
986
1844
|
} else this.contextLoaderFactory = options.contextLoaderFactory ?? this.documentLoaderFactory;
|
|
987
1845
|
this.authenticatedDocumentLoaderFactory = options.authenticatedDocumentLoaderFactory ?? ((identity) => getAuthenticatedDocumentLoader(identity, {
|
|
988
1846
|
allowPrivateAddress,
|
|
@@ -1009,24 +1867,24 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1009
1867
|
}
|
|
1010
1868
|
async _startQueueInternal(ctxData, signal, queue) {
|
|
1011
1869
|
if (this.inboxQueue == null && this.outboxQueue == null) return;
|
|
1012
|
-
const logger$
|
|
1870
|
+
const logger$1 = getLogger([
|
|
1013
1871
|
"fedify",
|
|
1014
1872
|
"federation",
|
|
1015
1873
|
"queue"
|
|
1016
1874
|
]);
|
|
1017
1875
|
const promises = [];
|
|
1018
1876
|
if (this.inboxQueue != null && (queue == null || queue === "inbox") && !this.inboxQueueStarted) {
|
|
1019
|
-
logger$
|
|
1877
|
+
logger$1.debug("Starting an inbox task worker.");
|
|
1020
1878
|
this.inboxQueueStarted = true;
|
|
1021
1879
|
promises.push(this.inboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
|
|
1022
1880
|
}
|
|
1023
1881
|
if (this.outboxQueue != null && this.outboxQueue !== this.inboxQueue && (queue == null || queue === "outbox") && !this.outboxQueueStarted) {
|
|
1024
|
-
logger$
|
|
1882
|
+
logger$1.debug("Starting an outbox task worker.");
|
|
1025
1883
|
this.outboxQueueStarted = true;
|
|
1026
1884
|
promises.push(this.outboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
|
|
1027
1885
|
}
|
|
1028
1886
|
if (this.fanoutQueue != null && this.fanoutQueue !== this.inboxQueue && this.fanoutQueue !== this.outboxQueue && (queue == null || queue === "fanout") && !this.fanoutQueueStarted) {
|
|
1029
|
-
logger$
|
|
1887
|
+
logger$1.debug("Starting a fanout task worker.");
|
|
1030
1888
|
this.fanoutQueueStarted = true;
|
|
1031
1889
|
promises.push(this.fanoutQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
|
|
1032
1890
|
}
|
|
@@ -1125,7 +1983,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1125
1983
|
});
|
|
1126
1984
|
}
|
|
1127
1985
|
async #listenOutboxMessage(_, message, span) {
|
|
1128
|
-
const logger$
|
|
1986
|
+
const logger$1 = getLogger([
|
|
1129
1987
|
"fedify",
|
|
1130
1988
|
"federation",
|
|
1131
1989
|
"outbox"
|
|
@@ -1174,41 +2032,41 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1174
2032
|
try {
|
|
1175
2033
|
this.onOutboxError?.(error, activity);
|
|
1176
2034
|
} catch (error$1) {
|
|
1177
|
-
logger$
|
|
2035
|
+
logger$1.error("An unexpected error occurred in onError handler:\n{error}", {
|
|
1178
2036
|
...logData,
|
|
1179
2037
|
error: error$1
|
|
1180
2038
|
});
|
|
1181
2039
|
}
|
|
1182
2040
|
if (this.outboxQueue?.nativeRetrial) {
|
|
1183
|
-
logger$
|
|
2041
|
+
logger$1.error("Failed to send activity {activityId} to {inbox}; backend will handle retry:\n{error}", {
|
|
1184
2042
|
...logData,
|
|
1185
2043
|
error
|
|
1186
2044
|
});
|
|
1187
2045
|
throw error;
|
|
1188
2046
|
}
|
|
1189
|
-
const delay = this.outboxRetryPolicy({
|
|
2047
|
+
const delay$1 = this.outboxRetryPolicy({
|
|
1190
2048
|
elapsedTime: Temporal.Instant.from(message.started).until(Temporal.Now.instant()),
|
|
1191
2049
|
attempts: message.attempt
|
|
1192
2050
|
});
|
|
1193
|
-
if (delay != null) {
|
|
1194
|
-
logger$
|
|
2051
|
+
if (delay$1 != null) {
|
|
2052
|
+
logger$1.error("Failed to send activity {activityId} to {inbox} (attempt #{attempt}); retry...:\n{error}", {
|
|
1195
2053
|
...logData,
|
|
1196
2054
|
error
|
|
1197
2055
|
});
|
|
1198
2056
|
await this.outboxQueue?.enqueue({
|
|
1199
2057
|
...message,
|
|
1200
2058
|
attempt: message.attempt + 1
|
|
1201
|
-
}, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
|
|
1202
|
-
} else logger$
|
|
2059
|
+
}, { delay: Temporal.Duration.compare(delay$1, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay$1 });
|
|
2060
|
+
} else logger$1.error("Failed to send activity {activityId} to {inbox} after {attempt} attempts; giving up:\n{error}", {
|
|
1203
2061
|
...logData,
|
|
1204
2062
|
error
|
|
1205
2063
|
});
|
|
1206
2064
|
return;
|
|
1207
2065
|
}
|
|
1208
|
-
logger$
|
|
2066
|
+
logger$1.info("Successfully sent activity {activityId} to {inbox}.", { ...logData });
|
|
1209
2067
|
}
|
|
1210
2068
|
async #listenInboxMessage(ctxData, message, span) {
|
|
1211
|
-
const logger$
|
|
2069
|
+
const logger$1 = getLogger([
|
|
1212
2070
|
"fedify",
|
|
1213
2071
|
"federation",
|
|
1214
2072
|
"inbox"
|
|
@@ -1230,7 +2088,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1230
2088
|
];
|
|
1231
2089
|
if (cacheKey != null) {
|
|
1232
2090
|
if (await this.kv.get(cacheKey) === true) {
|
|
1233
|
-
logger$
|
|
2091
|
+
logger$1.debug("Activity {activityId} has already been processed.", {
|
|
1234
2092
|
activityId: activity.id?.href,
|
|
1235
2093
|
activity: message.activity,
|
|
1236
2094
|
recipient: message.identifier
|
|
@@ -1241,7 +2099,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1241
2099
|
await this._getTracer().startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span$1) => {
|
|
1242
2100
|
const dispatched = this.inboxListeners?.dispatchWithClass(activity);
|
|
1243
2101
|
if (dispatched == null) {
|
|
1244
|
-
logger$
|
|
2102
|
+
logger$1.error("Unsupported activity type:\n{activity}", {
|
|
1245
2103
|
activityId: activity.id?.href,
|
|
1246
2104
|
activity: message.activity,
|
|
1247
2105
|
recipient: message.identifier,
|
|
@@ -1262,7 +2120,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1262
2120
|
try {
|
|
1263
2121
|
await this.inboxErrorHandler?.(context$1, error);
|
|
1264
2122
|
} catch (error$1) {
|
|
1265
|
-
logger$
|
|
2123
|
+
logger$1.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
1266
2124
|
error: error$1,
|
|
1267
2125
|
trial: message.attempt,
|
|
1268
2126
|
activityId: activity.id?.href,
|
|
@@ -1271,7 +2129,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1271
2129
|
});
|
|
1272
2130
|
}
|
|
1273
2131
|
if (this.inboxQueue?.nativeRetrial) {
|
|
1274
|
-
logger$
|
|
2132
|
+
logger$1.error("Failed to process the incoming activity {activityId}; backend will handle retry:\n{error}", {
|
|
1275
2133
|
error,
|
|
1276
2134
|
activityId: activity.id?.href,
|
|
1277
2135
|
activity: message.activity,
|
|
@@ -1284,12 +2142,12 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1284
2142
|
span$1.end();
|
|
1285
2143
|
throw error;
|
|
1286
2144
|
}
|
|
1287
|
-
const delay = this.inboxRetryPolicy({
|
|
2145
|
+
const delay$1 = this.inboxRetryPolicy({
|
|
1288
2146
|
elapsedTime: Temporal.Instant.from(message.started).until(Temporal.Now.instant()),
|
|
1289
2147
|
attempts: message.attempt
|
|
1290
2148
|
});
|
|
1291
|
-
if (delay != null) {
|
|
1292
|
-
logger$
|
|
2149
|
+
if (delay$1 != null) {
|
|
2150
|
+
logger$1.error("Failed to process the incoming activity {activityId} (attempt #{attempt}); retry...:\n{error}", {
|
|
1293
2151
|
error,
|
|
1294
2152
|
attempt: message.attempt,
|
|
1295
2153
|
activityId: activity.id?.href,
|
|
@@ -1299,8 +2157,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1299
2157
|
await this.inboxQueue?.enqueue({
|
|
1300
2158
|
...message,
|
|
1301
2159
|
attempt: message.attempt + 1
|
|
1302
|
-
}, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
|
|
1303
|
-
} else logger$
|
|
2160
|
+
}, { delay: Temporal.Duration.compare(delay$1, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay$1 });
|
|
2161
|
+
} else logger$1.error("Failed to process the incoming activity {activityId} after {trial} attempts; giving up:\n{error}", {
|
|
1304
2162
|
error,
|
|
1305
2163
|
activityId: activity.id?.href,
|
|
1306
2164
|
activity: message.activity,
|
|
@@ -1314,7 +2172,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1314
2172
|
return;
|
|
1315
2173
|
}
|
|
1316
2174
|
if (cacheKey != null) await this.kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
|
|
1317
|
-
logger$
|
|
2175
|
+
logger$1.info("Activity {activityId} has been processed.", {
|
|
1318
2176
|
activityId: activity.id?.href,
|
|
1319
2177
|
activity: message.activity,
|
|
1320
2178
|
recipient: message.identifier
|
|
@@ -1363,7 +2221,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1363
2221
|
};
|
|
1364
2222
|
}
|
|
1365
2223
|
async sendActivity(keys, inboxes, activity, options) {
|
|
1366
|
-
const logger$
|
|
2224
|
+
const logger$1 = getLogger([
|
|
1367
2225
|
"fedify",
|
|
1368
2226
|
"federation",
|
|
1369
2227
|
"outbox"
|
|
@@ -1397,7 +2255,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1397
2255
|
format: "compact",
|
|
1398
2256
|
contextLoader
|
|
1399
2257
|
});
|
|
1400
|
-
if (rsaKey == null) logger$
|
|
2258
|
+
if (rsaKey == null) logger$1.warn("No supported key found to create a Linked Data signature for the activity {activityId}. The activity will be sent without a Linked Data signature. In order to create a Linked Data signature, at least one RSASSA-PKCS1-v1_5 key must be provided.", {
|
|
1401
2259
|
activityId,
|
|
1402
2260
|
keys: keys.map((pair) => ({
|
|
1403
2261
|
keyId: pair.keyId.href,
|
|
@@ -1408,7 +2266,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1408
2266
|
contextLoader,
|
|
1409
2267
|
tracerProvider: this.tracerProvider
|
|
1410
2268
|
});
|
|
1411
|
-
if (!proofCreated) logger$
|
|
2269
|
+
if (!proofCreated) logger$1.warn("No supported key found to create a proof for the activity {activityId}. The activity will be sent without a proof. In order to create a proof, at least one Ed25519 key must be provided.", {
|
|
1412
2270
|
activityId,
|
|
1413
2271
|
keys: keys.map((pair) => ({
|
|
1414
2272
|
keyId: pair.keyId.href,
|
|
@@ -1416,11 +2274,11 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1416
2274
|
}))
|
|
1417
2275
|
});
|
|
1418
2276
|
if (immediate || this.outboxQueue == null) {
|
|
1419
|
-
if (immediate) logger$
|
|
2277
|
+
if (immediate) logger$1.debug("Sending activity immediately without queue since immediate option is set.", {
|
|
1420
2278
|
activityId: activity.id.href,
|
|
1421
2279
|
activity: jsonLd
|
|
1422
2280
|
});
|
|
1423
|
-
else logger$
|
|
2281
|
+
else logger$1.debug("Sending activity immediately without queue since queue is not set.", {
|
|
1424
2282
|
activityId: activity.id.href,
|
|
1425
2283
|
activity: jsonLd
|
|
1426
2284
|
});
|
|
@@ -1439,7 +2297,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1439
2297
|
await Promise.all(promises);
|
|
1440
2298
|
return;
|
|
1441
2299
|
}
|
|
1442
|
-
logger$
|
|
2300
|
+
logger$1.debug("Enqueuing activity {activityId} to send later.", {
|
|
1443
2301
|
activityId: activity.id.href,
|
|
1444
2302
|
activity: jsonLd
|
|
1445
2303
|
});
|
|
@@ -1478,7 +2336,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1478
2336
|
const promises = messages.map((m) => outboxQueue.enqueue(m));
|
|
1479
2337
|
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
1480
2338
|
if (errors.length > 0) {
|
|
1481
|
-
logger$
|
|
2339
|
+
logger$1.error("Failed to enqueue activity {activityId} to send later: {errors}", {
|
|
1482
2340
|
activityId: activity.id.href,
|
|
1483
2341
|
errors
|
|
1484
2342
|
});
|
|
@@ -1488,7 +2346,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1488
2346
|
} else try {
|
|
1489
2347
|
await outboxQueue.enqueueMany(messages);
|
|
1490
2348
|
} catch (error) {
|
|
1491
|
-
logger$
|
|
2349
|
+
logger$1.error("Failed to enqueue activity {activityId} to send later: {error}", {
|
|
1492
2350
|
activityId: activity.id.href,
|
|
1493
2351
|
error
|
|
1494
2352
|
});
|
|
@@ -1505,7 +2363,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1505
2363
|
[ATTR_URL_FULL]: request.url
|
|
1506
2364
|
}
|
|
1507
2365
|
}, async (span) => {
|
|
1508
|
-
const logger$
|
|
2366
|
+
const logger$1 = getLogger([
|
|
1509
2367
|
"fedify",
|
|
1510
2368
|
"federation",
|
|
1511
2369
|
"http"
|
|
@@ -1524,7 +2382,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1524
2382
|
message: `${error}`
|
|
1525
2383
|
});
|
|
1526
2384
|
span.end();
|
|
1527
|
-
logger$
|
|
2385
|
+
logger$1.error("An error occurred while serving request {method} {url}: {error}", {
|
|
1528
2386
|
method: request.method,
|
|
1529
2387
|
url: request.url,
|
|
1530
2388
|
error
|
|
@@ -1548,9 +2406,9 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1548
2406
|
url: request.url,
|
|
1549
2407
|
status: response.status
|
|
1550
2408
|
};
|
|
1551
|
-
if (response.status >= 500) logger$
|
|
1552
|
-
else if (response.status >= 400) logger$
|
|
1553
|
-
else logger$
|
|
2409
|
+
if (response.status >= 500) logger$1.error(logTpl, values);
|
|
2410
|
+
else if (response.status >= 400) logger$1.warn(logTpl, values);
|
|
2411
|
+
else logger$1.info(logTpl, values);
|
|
1554
2412
|
return response;
|
|
1555
2413
|
});
|
|
1556
2414
|
});
|
|
@@ -1867,13 +2725,13 @@ var ContextImpl = class ContextImpl {
|
|
|
1867
2725
|
if (uri == null) return null;
|
|
1868
2726
|
if (uri.origin !== this.origin && uri.origin !== this.canonicalOrigin) return null;
|
|
1869
2727
|
const route = this.federation.router.route(uri.pathname);
|
|
1870
|
-
const logger$
|
|
2728
|
+
const logger$1 = getLogger(["fedify", "federation"]);
|
|
1871
2729
|
if (route == null) return null;
|
|
1872
2730
|
else if (route.name === "sharedInbox") return {
|
|
1873
2731
|
type: "inbox",
|
|
1874
2732
|
identifier: void 0,
|
|
1875
2733
|
get handle() {
|
|
1876
|
-
logger$
|
|
2734
|
+
logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
|
|
1877
2735
|
}
|
|
1878
2736
|
};
|
|
1879
2737
|
const identifier = "identifier" in route.values ? route.values.identifier : route.values.handle;
|
|
@@ -1881,7 +2739,7 @@ var ContextImpl = class ContextImpl {
|
|
|
1881
2739
|
type: "actor",
|
|
1882
2740
|
identifier,
|
|
1883
2741
|
get handle() {
|
|
1884
|
-
logger$
|
|
2742
|
+
logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
|
|
1885
2743
|
return identifier;
|
|
1886
2744
|
}
|
|
1887
2745
|
};
|
|
@@ -1897,7 +2755,7 @@ var ContextImpl = class ContextImpl {
|
|
|
1897
2755
|
type: "inbox",
|
|
1898
2756
|
identifier,
|
|
1899
2757
|
get handle() {
|
|
1900
|
-
logger$
|
|
2758
|
+
logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
|
|
1901
2759
|
return identifier;
|
|
1902
2760
|
}
|
|
1903
2761
|
};
|
|
@@ -1905,7 +2763,7 @@ var ContextImpl = class ContextImpl {
|
|
|
1905
2763
|
type: "outbox",
|
|
1906
2764
|
identifier,
|
|
1907
2765
|
get handle() {
|
|
1908
|
-
logger$
|
|
2766
|
+
logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
|
|
1909
2767
|
return identifier;
|
|
1910
2768
|
}
|
|
1911
2769
|
};
|
|
@@ -1913,7 +2771,7 @@ var ContextImpl = class ContextImpl {
|
|
|
1913
2771
|
type: "following",
|
|
1914
2772
|
identifier,
|
|
1915
2773
|
get handle() {
|
|
1916
|
-
logger$
|
|
2774
|
+
logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
|
|
1917
2775
|
return identifier;
|
|
1918
2776
|
}
|
|
1919
2777
|
};
|
|
@@ -1921,7 +2779,7 @@ var ContextImpl = class ContextImpl {
|
|
|
1921
2779
|
type: "followers",
|
|
1922
2780
|
identifier,
|
|
1923
2781
|
get handle() {
|
|
1924
|
-
logger$
|
|
2782
|
+
logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
|
|
1925
2783
|
return identifier;
|
|
1926
2784
|
}
|
|
1927
2785
|
};
|
|
@@ -1929,7 +2787,7 @@ var ContextImpl = class ContextImpl {
|
|
|
1929
2787
|
type: "liked",
|
|
1930
2788
|
identifier,
|
|
1931
2789
|
get handle() {
|
|
1932
|
-
logger$
|
|
2790
|
+
logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
|
|
1933
2791
|
return identifier;
|
|
1934
2792
|
}
|
|
1935
2793
|
};
|
|
@@ -1937,7 +2795,7 @@ var ContextImpl = class ContextImpl {
|
|
|
1937
2795
|
type: "featured",
|
|
1938
2796
|
identifier,
|
|
1939
2797
|
get handle() {
|
|
1940
|
-
logger$
|
|
2798
|
+
logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
|
|
1941
2799
|
return identifier;
|
|
1942
2800
|
}
|
|
1943
2801
|
};
|
|
@@ -1945,19 +2803,19 @@ var ContextImpl = class ContextImpl {
|
|
|
1945
2803
|
type: "featuredTags",
|
|
1946
2804
|
identifier,
|
|
1947
2805
|
get handle() {
|
|
1948
|
-
logger$
|
|
2806
|
+
logger$1.warn("The ParseUriResult.handle property is deprecated; use ParseUriResult.identifier instead.");
|
|
1949
2807
|
return identifier;
|
|
1950
2808
|
}
|
|
1951
2809
|
};
|
|
1952
2810
|
return null;
|
|
1953
2811
|
}
|
|
1954
2812
|
async getActorKeyPairs(identifier) {
|
|
1955
|
-
const logger$
|
|
2813
|
+
const logger$1 = getLogger([
|
|
1956
2814
|
"fedify",
|
|
1957
2815
|
"federation",
|
|
1958
2816
|
"actor"
|
|
1959
2817
|
]);
|
|
1960
|
-
if (this.invokedFromActorKeyPairsDispatcher != null) logger$
|
|
2818
|
+
if (this.invokedFromActorKeyPairsDispatcher != null) logger$1.warn("Context.getActorKeyPairs({getActorKeyPairsIdentifier}) method is invoked from the actor key pairs dispatcher ({actorKeyPairsDispatcherIdentifier}); this may cause an infinite loop.", {
|
|
1961
2819
|
getActorKeyPairsIdentifier: identifier,
|
|
1962
2820
|
actorKeyPairsDispatcherIdentifier: this.invokedFromActorKeyPairsDispatcher.identifier
|
|
1963
2821
|
});
|
|
@@ -1965,7 +2823,7 @@ var ContextImpl = class ContextImpl {
|
|
|
1965
2823
|
try {
|
|
1966
2824
|
keyPairs = await this.getKeyPairsFromIdentifier(identifier);
|
|
1967
2825
|
} catch (_) {
|
|
1968
|
-
logger$
|
|
2826
|
+
logger$1.warn("No actor key pairs dispatcher registered.");
|
|
1969
2827
|
return [];
|
|
1970
2828
|
}
|
|
1971
2829
|
const owner = this.getActorUri(identifier);
|
|
@@ -1989,7 +2847,7 @@ var ContextImpl = class ContextImpl {
|
|
|
1989
2847
|
return result;
|
|
1990
2848
|
}
|
|
1991
2849
|
async getKeyPairsFromIdentifier(identifier) {
|
|
1992
|
-
const logger$
|
|
2850
|
+
const logger$1 = getLogger([
|
|
1993
2851
|
"fedify",
|
|
1994
2852
|
"federation",
|
|
1995
2853
|
"actor"
|
|
@@ -2000,7 +2858,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2000
2858
|
handle: identifier
|
|
2001
2859
|
});
|
|
2002
2860
|
if (path == null) {
|
|
2003
|
-
logger$
|
|
2861
|
+
logger$1.warn("No actor dispatcher registered.");
|
|
2004
2862
|
return [];
|
|
2005
2863
|
}
|
|
2006
2864
|
const actorUri = new URL(path, this.canonicalOrigin);
|
|
@@ -2008,7 +2866,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2008
2866
|
...this,
|
|
2009
2867
|
invokedFromActorKeyPairsDispatcher: { identifier }
|
|
2010
2868
|
}), identifier);
|
|
2011
|
-
if (keyPairs.length < 1) logger$
|
|
2869
|
+
if (keyPairs.length < 1) logger$1.warn("No key pairs found for actor {identifier}.", { identifier });
|
|
2012
2870
|
let i = 0;
|
|
2013
2871
|
const result = [];
|
|
2014
2872
|
for (const keyPair of keyPairs) {
|
|
@@ -2123,7 +2981,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2123
2981
|
});
|
|
2124
2982
|
}
|
|
2125
2983
|
async sendActivityInternal(sender, recipients, activity, options, span) {
|
|
2126
|
-
const logger$
|
|
2984
|
+
const logger$1 = getLogger([
|
|
2127
2985
|
"fedify",
|
|
2128
2986
|
"federation",
|
|
2129
2987
|
"outbox"
|
|
@@ -2137,7 +2995,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2137
2995
|
if ("username" in sender) username = sender.username;
|
|
2138
2996
|
else {
|
|
2139
2997
|
username = sender.handle;
|
|
2140
|
-
logger$
|
|
2998
|
+
logger$1.warn("The \"handle\" property for the sender parameter is deprecated; use \"identifier\" or \"username\" instead.", { sender });
|
|
2141
2999
|
}
|
|
2142
3000
|
if (this.federation.actorCallbacks?.handleMapper == null) identifier = username;
|
|
2143
3001
|
else {
|
|
@@ -2174,7 +3032,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2174
3032
|
for (const activityTransformer of this.federation.activityTransformers) activity = activityTransformer(activity, this);
|
|
2175
3033
|
span?.setAttribute("activitypub.activity.id", activity?.id?.href ?? "");
|
|
2176
3034
|
if (activity.actorId == null) {
|
|
2177
|
-
logger$
|
|
3035
|
+
logger$1.error("Activity {activityId} to send does not have an actor.", {
|
|
2178
3036
|
activity,
|
|
2179
3037
|
activityId: activity?.id?.href
|
|
2180
3038
|
});
|
|
@@ -2185,7 +3043,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2185
3043
|
preferSharedInbox: options.preferSharedInbox,
|
|
2186
3044
|
excludeBaseUris: options.excludeBaseUris
|
|
2187
3045
|
});
|
|
2188
|
-
logger$
|
|
3046
|
+
logger$1.debug("Sending activity {activityId} to inboxes:\n{inboxes}", {
|
|
2189
3047
|
inboxes: globalThis.Object.keys(inboxes),
|
|
2190
3048
|
activityId: activity.id?.href,
|
|
2191
3049
|
activity
|
|
@@ -2271,7 +3129,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2271
3129
|
});
|
|
2272
3130
|
}
|
|
2273
3131
|
async routeActivityInternal(recipient, activity, options = {}, span) {
|
|
2274
|
-
const logger$
|
|
3132
|
+
const logger$1 = getLogger([
|
|
2275
3133
|
"fedify",
|
|
2276
3134
|
"federation",
|
|
2277
3135
|
"inbox"
|
|
@@ -2285,12 +3143,12 @@ var ContextImpl = class ContextImpl {
|
|
|
2285
3143
|
tracerProvider: options.tracerProvider ?? this.tracerProvider,
|
|
2286
3144
|
keyCache
|
|
2287
3145
|
}) == null) {
|
|
2288
|
-
logger$
|
|
3146
|
+
logger$1.debug("Object Integrity Proofs are not verified.", {
|
|
2289
3147
|
recipient,
|
|
2290
3148
|
activity: json
|
|
2291
3149
|
});
|
|
2292
3150
|
if (activity.id == null) {
|
|
2293
|
-
logger$
|
|
3151
|
+
logger$1.debug("Activity is missing an ID; unable to fetch.", {
|
|
2294
3152
|
recipient,
|
|
2295
3153
|
activity: json
|
|
2296
3154
|
});
|
|
@@ -2298,26 +3156,26 @@ var ContextImpl = class ContextImpl {
|
|
|
2298
3156
|
}
|
|
2299
3157
|
const fetched = await this.lookupObject(activity.id, options);
|
|
2300
3158
|
if (fetched == null) {
|
|
2301
|
-
logger$
|
|
3159
|
+
logger$1.debug("Failed to fetch the remote activity object {activityId}.", {
|
|
2302
3160
|
recipient,
|
|
2303
3161
|
activity: json,
|
|
2304
3162
|
activityId: activity.id.href
|
|
2305
3163
|
});
|
|
2306
3164
|
return false;
|
|
2307
3165
|
} else if (!(fetched instanceof Activity)) {
|
|
2308
|
-
logger$
|
|
3166
|
+
logger$1.debug("Fetched object is not an Activity.", {
|
|
2309
3167
|
recipient,
|
|
2310
3168
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
2311
3169
|
});
|
|
2312
3170
|
return false;
|
|
2313
3171
|
} else if (fetched.id?.href !== activity.id.href) {
|
|
2314
|
-
logger$
|
|
3172
|
+
logger$1.debug("Fetched activity object has a different ID; failed to verify.", {
|
|
2315
3173
|
recipient,
|
|
2316
3174
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
2317
3175
|
});
|
|
2318
3176
|
return false;
|
|
2319
3177
|
} else if (fetched.actorIds.length < 1) {
|
|
2320
|
-
logger$
|
|
3178
|
+
logger$1.debug("Fetched activity object is missing an actor; unable to verify.", {
|
|
2321
3179
|
recipient,
|
|
2322
3180
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
2323
3181
|
});
|
|
@@ -2325,15 +3183,15 @@ var ContextImpl = class ContextImpl {
|
|
|
2325
3183
|
}
|
|
2326
3184
|
const activityId = fetched.id;
|
|
2327
3185
|
if (!fetched.actorIds.every((actor) => actor.origin === activityId.origin)) {
|
|
2328
|
-
logger$
|
|
3186
|
+
logger$1.debug("Fetched activity object has actors from different origins; unable to verify.", {
|
|
2329
3187
|
recipient,
|
|
2330
3188
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
2331
3189
|
});
|
|
2332
3190
|
return false;
|
|
2333
3191
|
}
|
|
2334
|
-
logger$
|
|
3192
|
+
logger$1.debug("Successfully fetched the remote activity object {activityId}; ignore the original activity and use the fetched one, which is trustworthy.");
|
|
2335
3193
|
activity = fetched;
|
|
2336
|
-
} else logger$
|
|
3194
|
+
} else logger$1.debug("Object Integrity Proofs are verified.", {
|
|
2337
3195
|
recipient,
|
|
2338
3196
|
activity: json
|
|
2339
3197
|
});
|
|
@@ -2477,7 +3335,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
2477
3335
|
});
|
|
2478
3336
|
}
|
|
2479
3337
|
async forwardActivityInternal(forwarder, recipients, options) {
|
|
2480
|
-
const logger$
|
|
3338
|
+
const logger$1 = getLogger([
|
|
2481
3339
|
"fedify",
|
|
2482
3340
|
"federation",
|
|
2483
3341
|
"inbox"
|
|
@@ -2491,7 +3349,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
2491
3349
|
if ("username" in forwarder) username = forwarder.username;
|
|
2492
3350
|
else {
|
|
2493
3351
|
username = forwarder.handle;
|
|
2494
|
-
logger$
|
|
3352
|
+
logger$1.warn("The \"handle\" property for the forwarder parameter is deprecated; use \"identifier\" or \"username\" instead.", { forwarder });
|
|
2495
3353
|
}
|
|
2496
3354
|
if (this.federation.actorCallbacks?.handleMapper == null) identifier = username;
|
|
2497
3355
|
else {
|
|
@@ -2515,7 +3373,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
2515
3373
|
}
|
|
2516
3374
|
if (!hasProof) {
|
|
2517
3375
|
if (options?.skipIfUnsigned) return;
|
|
2518
|
-
logger$
|
|
3376
|
+
logger$1.warn("The received activity {activityId} is not signed; even if it is forwarded to other servers as is, it may not be accepted by them due to the lack of a signature/proof.");
|
|
2519
3377
|
}
|
|
2520
3378
|
}
|
|
2521
3379
|
if (recipients === "followers") {
|
|
@@ -2529,14 +3387,14 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
2529
3387
|
preferSharedInbox: options?.preferSharedInbox,
|
|
2530
3388
|
excludeBaseUris: options?.excludeBaseUris
|
|
2531
3389
|
});
|
|
2532
|
-
logger$
|
|
3390
|
+
logger$1.debug("Forwarding activity {activityId} to inboxes:\n{inboxes}", {
|
|
2533
3391
|
inboxes: globalThis.Object.keys(inboxes),
|
|
2534
3392
|
activityId: this.activityId,
|
|
2535
3393
|
activity: this.activity
|
|
2536
3394
|
});
|
|
2537
3395
|
if (options?.immediate || this.federation.outboxQueue == null) {
|
|
2538
|
-
if (options?.immediate) logger$
|
|
2539
|
-
else logger$
|
|
3396
|
+
if (options?.immediate) logger$1.debug("Forwarding activity immediately without queue since immediate option is set.");
|
|
3397
|
+
else logger$1.debug("Forwarding activity immediately without queue since queue is not set.");
|
|
2540
3398
|
const promises = [];
|
|
2541
3399
|
for (const inbox in inboxes) promises.push(sendActivity({
|
|
2542
3400
|
keys,
|
|
@@ -2551,7 +3409,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
2551
3409
|
await Promise.all(promises);
|
|
2552
3410
|
return;
|
|
2553
3411
|
}
|
|
2554
|
-
logger$
|
|
3412
|
+
logger$1.debug("Enqueuing activity {activityId} to forward later.", {
|
|
2555
3413
|
activityId: this.activityId,
|
|
2556
3414
|
activity: this.activity
|
|
2557
3415
|
});
|
|
@@ -2589,7 +3447,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
2589
3447
|
const promises = messages.map((m) => outboxQueue.enqueue(m));
|
|
2590
3448
|
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2591
3449
|
if (errors.length > 0) {
|
|
2592
|
-
logger$
|
|
3450
|
+
logger$1.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
|
|
2593
3451
|
activityId: this.activityId,
|
|
2594
3452
|
errors
|
|
2595
3453
|
});
|
|
@@ -2599,7 +3457,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
2599
3457
|
} else try {
|
|
2600
3458
|
await outboxQueue.enqueueMany(messages);
|
|
2601
3459
|
} catch (error) {
|
|
2602
|
-
logger$
|
|
3460
|
+
logger$1.error("Failed to enqueue activity {activityId} to forward later:\n{error}", {
|
|
2603
3461
|
activityId: this.activityId,
|
|
2604
3462
|
error
|
|
2605
3463
|
});
|
|
@@ -2658,4 +3516,4 @@ function getRequestId(request) {
|
|
|
2658
3516
|
}
|
|
2659
3517
|
|
|
2660
3518
|
//#endregion
|
|
2661
|
-
export {
|
|
3519
|
+
export { createFederation as a, respondWithObjectIfAcceptable as c, createFederationBuilder as d, Router$1 as f, KvSpecDeterminer as i, buildCollectionSynchronizationHeader as l, FederationImpl as n, createExponentialBackoffPolicy as o, RouterError as p, InboxContextImpl as r, respondWithObject as s, ContextImpl as t, digest as u };
|