@fedify/fedify 2.0.8 → 2.0.9
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/{assert-MZs1qjMx.js → assert-ddO5KLpe.mjs} +5 -9
- package/dist/{assert_equals-DSbWqCm3.js → assert_equals-Ew3jOFa3.mjs} +55 -69
- package/dist/{assert_instance_of-DHz7EHNU.js → assert_instance_of-C4Ri6VuN.mjs} +5 -9
- package/dist/{assert_not_equals-C80BG-_5.js → assert_not_equals--wG9hV7u.mjs} +6 -13
- package/dist/{assert_rejects-Ce45JcFg.js → assert_rejects-B-qJtC9Z.mjs} +6 -11
- package/dist/{assert_throws-BNXdRGWP.js → assert_throws-4NwKEy2q.mjs} +5 -10
- package/dist/{builder-B5cKln9v.js → builder-DDoQaGOu.mjs} +32 -41
- package/dist/{chunk-CGaQZ11T.cjs → chunk-DDcVe30Y.cjs} +23 -24
- package/dist/{chunk-DJNbSFdH.js → chunk-nlSIicah.js} +8 -8
- package/dist/{client-CoCIaTNO.js → client-A1UrnX6I.mjs} +9 -13
- package/dist/{client-BxMZiQaD.d.ts → client-AtlibPOU.d.ts} +1 -1
- package/dist/{client-C97KOq3x.d.cts → client-z-8dc-e1.d.cts} +1 -1
- package/dist/{collection-CcnIw1qY.js → collection-ChgDTHLz.mjs} +7 -12
- package/dist/compat/mod.cjs +5 -8
- package/dist/compat/mod.d.cts +78 -6
- package/dist/compat/mod.d.ts +78 -6
- package/dist/compat/mod.js +4 -8
- package/dist/compat/transformers.test.mjs +62 -0
- package/dist/{context-D3QkEtZd.d.cts → context-CNIt-Qn7.d.cts} +9 -18
- package/dist/{context-DZJhUmzF.d.ts → context-Dyg7P1qW.d.ts} +9 -18
- package/dist/{context-pa9aIrwp.js → context-Juj6bdHC.mjs} +7 -11
- package/dist/deno-CuVDEdyj.mjs +8 -0
- package/dist/{docloader-CBHh0rC5.js → docloader-BPq9yzC_.mjs} +8 -14
- package/dist/{esm-nLm00z9V.js → esm-DVILvP5e.mjs} +50 -89
- package/dist/federation/builder.test.d.mts +2 -0
- package/dist/federation/{builder.test.js → builder.test.mjs} +19 -38
- package/dist/federation/collection.test.d.mts +2 -0
- package/dist/federation/collection.test.mjs +21 -0
- package/dist/federation/handler.test.d.mts +2 -0
- package/dist/federation/{handler.test.js → handler.test.mjs} +26 -56
- package/dist/federation/idempotency.test.d.mts +2 -0
- package/dist/federation/{idempotency.test.js → idempotency.test.mjs} +31 -62
- package/dist/federation/inbox.test.d.mts +2 -0
- package/dist/federation/{inbox.test.js → inbox.test.mjs} +8 -12
- package/dist/federation/keycache.test.d.mts +2 -0
- package/dist/federation/{keycache.test.js → keycache.test.mjs} +11 -15
- package/dist/federation/kv.test.d.mts +2 -0
- package/dist/federation/{kv.test.js → kv.test.mjs} +11 -22
- package/dist/federation/middleware.test.d.mts +2 -0
- package/dist/federation/{middleware.test.js → middleware.test.mjs} +146 -225
- package/dist/federation/mod.cjs +327 -16
- package/dist/federation/mod.d.cts +3 -6
- package/dist/federation/mod.d.ts +3 -6
- package/dist/federation/mod.js +322 -13
- package/dist/federation/mq.test.d.mts +2 -0
- package/dist/federation/{mq.test.js → mq.test.mjs} +21 -35
- package/dist/federation/negotiation.test.d.mts +2 -0
- package/dist/federation/{negotiation.test.js → negotiation.test.mjs} +9 -16
- package/dist/federation/retry.test.d.mts +2 -0
- package/dist/federation/{retry.test.js → retry.test.mjs} +8 -11
- package/dist/federation/router.test.d.mts +2 -0
- package/dist/federation/{router.test.js → router.test.mjs} +11 -16
- package/dist/federation/send.test.d.mts +2 -0
- package/dist/federation/{send.test.js → send.test.mjs} +22 -29
- package/dist/federation/webfinger.test.d.mts +2 -0
- package/dist/federation/{webfinger.test.js → webfinger.test.mjs} +22 -55
- package/dist/{http-DkHdFfrc.d.ts → http-B2wiNmSo.d.ts} +1 -6
- package/dist/{http-C_RwU_oN.js → http-Bz7avX57.js} +25 -156
- package/dist/{http-Cz3MlXAZ.d.cts → http-C_tEAiZj.d.cts} +1 -6
- package/dist/{http-Br3-1dRf.js → http-DI213UHg.mjs} +17 -33
- package/dist/{http-DGs_78tx.cjs → http-DKBDoudA.cjs} +110 -235
- package/dist/{inbox-3bZUqDLE.js → inbox-Bdn-CSRd.mjs} +18 -26
- package/dist/{key-D7Y_J9kt.js → key-DzJf84o7.mjs} +12 -19
- package/dist/{keycache-BASM0rrX.js → keycache-DaQ3ndaJ.mjs} +5 -9
- package/dist/{keys-ZbcByPg9.js → keys-CtZLJq76.mjs} +5 -9
- package/dist/{kv-QzKcOQgP.js → kv-BrZHNugx.mjs} +6 -10
- package/dist/{kv-BL4nlICN.d.cts → kv-CbLNp3zQ.d.cts} +1 -1
- package/dist/{kv-DXEUEP6z.d.ts → kv-GFYnFoOl.d.ts} +1 -1
- package/dist/{kv-cache-CMM5VJsc.js → kv-cache-DBd7BezJ.js} +6 -13
- package/dist/{kv-cache-9PANi4tA.cjs → kv-cache-Dj1Q7TiW.cjs} +27 -34
- package/dist/{kv-cache-El7We5sy.js → kv-cache-OWmRLHir.mjs} +4 -8
- package/dist/{ld-Bjq9Z4St.js → ld-DczS1fLK.mjs} +17 -31
- package/dist/middleware-B5CiOImA.mjs +5 -0
- package/dist/{middleware-Bj30TZll.js → middleware-BKNu57ZI.js} +320 -363
- package/dist/middleware-C36TOX-2.cjs +4 -0
- package/dist/{middleware-CQeA5yF7.cjs → middleware-CyjmpK70.cjs} +513 -564
- package/dist/{middleware-DozhKfB6.js → middleware-DoHz9oIo.mjs} +260 -292
- package/dist/{mod-DPkRU3EK.d.cts → mod-1xhgsHef.d.cts} +2 -2
- package/dist/{mod-DUWcVv49.d.ts → mod-BGtYJZKu.d.ts} +2 -2
- package/dist/{mod-DXsQakeS.d.cts → mod-Bld7oeqf.d.cts} +3 -3
- package/dist/{mod-DnSsduJF.d.ts → mod-BnAKGh2w.d.ts} +2 -2
- package/dist/{mod-CwZXZJ9d.d.ts → mod-DTOUyCce.d.ts} +3 -3
- package/dist/{mod-Di3W5OdP.d.cts → mod-DWoQffTD.d.cts} +2 -2
- package/dist/mod.cjs +29 -68
- package/dist/mod.d.cts +11 -14
- package/dist/mod.d.ts +11 -15
- package/dist/mod.js +17 -65
- package/dist/{negotiation-5NPJL6zp.js → negotiation-BehA2uul.mjs} +7 -11
- package/dist/nodeinfo/client.test.d.mts +2 -0
- package/dist/nodeinfo/{client.test.js → client.test.mjs} +22 -40
- package/dist/nodeinfo/handler.test.d.mts +2 -0
- package/dist/nodeinfo/{handler.test.js → handler.test.mjs} +13 -42
- package/dist/nodeinfo/mod.cjs +5 -8
- package/dist/nodeinfo/mod.d.cts +2 -3
- package/dist/nodeinfo/mod.d.ts +2 -3
- package/dist/nodeinfo/mod.js +4 -8
- package/dist/nodeinfo/types.test.d.mts +2 -0
- package/dist/nodeinfo/{types.test.js → types.test.mjs} +9 -16
- package/dist/otel/exporter.test.d.mts +2 -0
- package/dist/otel/{exporter.test.js → exporter.test.mjs} +117 -169
- package/dist/otel/mod.cjs +15 -20
- package/dist/otel/mod.d.cts +2 -2
- package/dist/otel/mod.d.ts +2 -2
- package/dist/otel/mod.js +8 -14
- package/dist/{owner-gd0Q9FuU.d.ts → owner-74ARJ5TL.d.ts} +1 -1
- package/dist/{owner-1AbPBOOZ.d.cts → owner-CptqhsOy.d.cts} +1 -1
- package/dist/{owner-CImU2dKz.js → owner-DXMGUEOr.mjs} +11 -16
- package/dist/{proof-BygvN4r5.js → proof-C-7NljBU.js} +32 -58
- package/dist/{proof-DLL0MLmV.js → proof-CEOujj0L.mjs} +21 -33
- package/dist/{proof-UhA5do8k.cjs → proof-DMu-6A_w.cjs} +133 -157
- package/dist/{retry-D4GJ670a.js → retry-Ddbq3AcK.mjs} +4 -7
- package/dist/{router-D9eI0s4b.js → router-CrMLXoOr.mjs} +4 -8
- package/dist/runtime/mod.cjs +11 -13
- package/dist/runtime/mod.d.cts +6 -2
- package/dist/runtime/mod.d.ts +0 -1
- package/dist/runtime/mod.js +4 -7
- package/dist/{send-DbW03azY.js → send-DIfrLTB_.mjs} +8 -13
- package/dist/sig/http.test.d.mts +2 -0
- package/dist/sig/{http.test.js → http.test.mjs} +117 -199
- package/dist/sig/key.test.d.mts +2 -0
- package/dist/sig/{key.test.js → key.test.mjs} +11 -18
- package/dist/sig/ld.test.d.mts +2 -0
- package/dist/sig/{ld.test.js → ld.test.mjs} +22 -35
- package/dist/sig/mod.cjs +6 -9
- package/dist/sig/mod.d.cts +3 -3
- package/dist/sig/mod.d.ts +3 -3
- package/dist/sig/mod.js +5 -9
- package/dist/sig/owner.test.d.mts +2 -0
- package/dist/sig/{owner.test.js → owner.test.mjs} +19 -34
- package/dist/sig/proof.test.d.mts +2 -0
- package/dist/sig/{proof.test.js → proof.test.mjs} +16 -27
- package/dist/{std__assert-DWivtrGR.js → std__assert-Duiq_YC9.mjs} +12 -24
- package/dist/testing/{mod.d.ts → mod.d.mts} +26 -78
- package/dist/testing/mod.mjs +6 -0
- package/dist/{transformers-3g8GZwkZ.cjs → transformers-NeAONrAq.cjs} +20 -25
- package/dist/{transformers-C3FLHUd6.js → transformers-ve6e2xcg.js} +3 -7
- package/dist/{types-CPz01LGH.js → types-C37hquWI.mjs} +4 -7
- package/dist/{types-Cd_hszr_.cjs → types-KC4QAoxe.cjs} +29 -34
- package/dist/{types-C93Ob9cU.js → types-hvL8ElAs.js} +8 -13
- package/dist/utils/docloader.test.d.mts +2 -0
- package/dist/utils/{docloader.test.js → docloader.test.mjs} +14 -24
- package/dist/utils/kv-cache.test.d.mts +2 -0
- package/dist/utils/{kv-cache.test.js → kv-cache.test.mjs} +25 -40
- package/dist/utils/mod.cjs +5 -9
- package/dist/utils/mod.d.cts +1 -3
- package/dist/utils/mod.d.ts +1 -3
- package/dist/utils/mod.js +4 -9
- package/dist/vocab/cjs.test.d.mts +2 -0
- package/dist/vocab/cjs.test.mjs +14 -0
- package/dist/vocab/mod.cjs +10 -12
- package/dist/vocab/mod.js +3 -5
- package/package.json +7 -7
- package/dist/compat/transformers.test.d.ts +0 -3
- package/dist/compat/transformers.test.js +0 -87
- package/dist/compat-Bb4NuTUO.js +0 -4
- package/dist/compat-DmDDELst.cjs +0 -4
- package/dist/deno-4w047OFk.js +0 -121
- package/dist/federation/builder.test.d.ts +0 -3
- package/dist/federation/collection.test.d.ts +0 -3
- package/dist/federation/collection.test.js +0 -32
- package/dist/federation/handler.test.d.ts +0 -3
- package/dist/federation/idempotency.test.d.ts +0 -3
- package/dist/federation/inbox.test.d.ts +0 -3
- package/dist/federation/keycache.test.d.ts +0 -3
- package/dist/federation/kv.test.d.ts +0 -3
- package/dist/federation/middleware.test.d.ts +0 -3
- package/dist/federation/mq.test.d.ts +0 -3
- package/dist/federation/negotiation.test.d.ts +0 -3
- package/dist/federation/retry.test.d.ts +0 -3
- package/dist/federation/router.test.d.ts +0 -3
- package/dist/federation/send.test.d.ts +0 -3
- package/dist/federation/webfinger.test.d.ts +0 -3
- package/dist/federation-Bp3HI26G.cjs +0 -350
- package/dist/federation-DaMfqRm4.js +0 -332
- package/dist/middleware-B73ZyDmk.js +0 -12
- package/dist/middleware-Dr61i4Jo.cjs +0 -12
- package/dist/middleware-_1PYruC5.js +0 -26
- package/dist/mod-Bh8mqlYw.d.cts +0 -9
- package/dist/mod-D6HodEq7.d.ts +0 -7
- package/dist/mod-DVwHUI_x.d.cts +0 -80
- package/dist/mod-DosD6NsG.d.ts +0 -82
- package/dist/mod-gq_Xfdz8.d.cts +0 -1
- package/dist/nodeinfo/client.test.d.ts +0 -3
- package/dist/nodeinfo/handler.test.d.ts +0 -3
- package/dist/nodeinfo/types.test.d.ts +0 -3
- package/dist/nodeinfo-DoESQxq5.js +0 -4
- package/dist/nodeinfo-DuMYTpbZ.cjs +0 -4
- package/dist/otel/exporter.test.d.ts +0 -3
- package/dist/runtime-c2Njxsry.cjs +0 -17
- package/dist/runtime-poamPCMb.js +0 -13
- package/dist/sig/http.test.d.ts +0 -3
- package/dist/sig/key.test.d.ts +0 -3
- package/dist/sig/ld.test.d.ts +0 -3
- package/dist/sig/owner.test.d.ts +0 -3
- package/dist/sig/proof.test.d.ts +0 -3
- package/dist/sig-BNhspNOf.js +0 -4
- package/dist/sig-vX39WyWI.cjs +0 -4
- package/dist/testing/mod.js +0 -10
- package/dist/utils/docloader.test.d.ts +0 -3
- package/dist/utils/kv-cache.test.d.ts +0 -3
- package/dist/utils-BQ9KqEK9.cjs +0 -4
- package/dist/utils-Dn5OPdSW.js +0 -4
- /package/dist/{mod-AGjRfPjT.d.ts → compat/transformers.test.d.mts} +0 -0
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { getAuthenticatedDocumentLoader, kvCache } from "./kv-cache-CMM5VJsc.js";
|
|
1
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
import { t as __exportAll } from "./chunk-nlSIicah.js";
|
|
4
|
+
import { r as getDefaultActivityTransformers } from "./transformers-ve6e2xcg.js";
|
|
5
|
+
import { c as validateCryptoKey, i as exportJwk, l as name, r as verifyRequest, s as importJwk, t as doubleKnock, u as version } from "./http-Bz7avX57.js";
|
|
6
|
+
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-C-7NljBU.js";
|
|
7
|
+
import { n as getNodeInfo, t as nodeInfoToJson } from "./types-hvL8ElAs.js";
|
|
8
|
+
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-DBd7BezJ.js";
|
|
10
9
|
import { getLogger, withContext } from "@logtape/logtape";
|
|
11
10
|
import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
|
|
12
11
|
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
@@ -18,7 +17,6 @@ import { getDocumentLoader } from "@fedify/vocab-runtime";
|
|
|
18
17
|
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";
|
|
19
18
|
import { lookupWebFinger } from "@fedify/webfinger";
|
|
20
19
|
import { domainToASCII } from "node:url";
|
|
21
|
-
|
|
22
20
|
//#region src/federation/inbox.ts
|
|
23
21
|
var InboxListenerSet = class InboxListenerSet {
|
|
24
22
|
#listeners;
|
|
@@ -54,7 +52,7 @@ var InboxListenerSet = class InboxListenerSet {
|
|
|
54
52
|
}
|
|
55
53
|
};
|
|
56
54
|
async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, tracerProvider, idempotencyStrategy }) {
|
|
57
|
-
const logger
|
|
55
|
+
const logger = getLogger([
|
|
58
56
|
"fedify",
|
|
59
57
|
"federation",
|
|
60
58
|
"inbox"
|
|
@@ -64,10 +62,8 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
64
62
|
const inboxContext = inboxContextFactory(recipient, json, activity.id?.href, getTypeId(activity).href);
|
|
65
63
|
const strategy = idempotencyStrategy ?? "per-inbox";
|
|
66
64
|
let keyString;
|
|
67
|
-
if (typeof strategy === "function")
|
|
68
|
-
|
|
69
|
-
keyString = result;
|
|
70
|
-
} else switch (strategy) {
|
|
65
|
+
if (typeof strategy === "function") keyString = await strategy(inboxContext, activity);
|
|
66
|
+
else switch (strategy) {
|
|
71
67
|
case "global":
|
|
72
68
|
keyString = activity.id.href;
|
|
73
69
|
break;
|
|
@@ -82,9 +78,8 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
82
78
|
if (keyString != null) cacheKey = [...kvPrefixes.activityIdempotence, keyString];
|
|
83
79
|
}
|
|
84
80
|
if (cacheKey != null) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
logger$1.debug("Activity {activityId} has already been processed.", {
|
|
81
|
+
if (await kv.get(cacheKey) === true) {
|
|
82
|
+
logger.debug("Activity {activityId} has already been processed.", {
|
|
88
83
|
activityId: activity.id?.href,
|
|
89
84
|
activity: json,
|
|
90
85
|
recipient
|
|
@@ -97,7 +92,7 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
97
92
|
}
|
|
98
93
|
}
|
|
99
94
|
if (activity.actorId == null) {
|
|
100
|
-
logger
|
|
95
|
+
logger.error("Missing actor.", { activity: json });
|
|
101
96
|
span.setStatus({
|
|
102
97
|
code: SpanStatusCode.ERROR,
|
|
103
98
|
message: "Missing actor."
|
|
@@ -120,7 +115,7 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
120
115
|
traceContext: carrier
|
|
121
116
|
});
|
|
122
117
|
} catch (error) {
|
|
123
|
-
logger
|
|
118
|
+
logger.error("Failed to enqueue the incoming activity {activityId}:\n{error}", {
|
|
124
119
|
error,
|
|
125
120
|
activityId: activity.id?.href,
|
|
126
121
|
activity: json,
|
|
@@ -132,7 +127,7 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
132
127
|
});
|
|
133
128
|
throw error;
|
|
134
129
|
}
|
|
135
|
-
logger
|
|
130
|
+
logger.info("Activity {activityId} is enqueued.", {
|
|
136
131
|
activityId: activity.id?.href,
|
|
137
132
|
activity: json,
|
|
138
133
|
recipient
|
|
@@ -140,60 +135,58 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
140
135
|
return "enqueued";
|
|
141
136
|
}
|
|
142
137
|
tracerProvider = tracerProvider ?? trace.getTracerProvider();
|
|
143
|
-
|
|
144
|
-
return await tracer.startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span$1) => {
|
|
138
|
+
return await tracerProvider.getTracer(name, version).startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span) => {
|
|
145
139
|
const dispatched = inboxListeners?.dispatchWithClass(activity);
|
|
146
140
|
if (dispatched == null) {
|
|
147
|
-
logger
|
|
141
|
+
logger.error("Unsupported activity type:\n{activity}", {
|
|
148
142
|
activity: json,
|
|
149
143
|
recipient
|
|
150
144
|
});
|
|
151
|
-
span
|
|
145
|
+
span.setStatus({
|
|
152
146
|
code: SpanStatusCode.UNSET,
|
|
153
147
|
message: `Unsupported activity type: ${getTypeId(activity).href}`
|
|
154
148
|
});
|
|
155
|
-
span
|
|
149
|
+
span.end();
|
|
156
150
|
return "unsupportedActivity";
|
|
157
151
|
}
|
|
158
152
|
const { class: cls, listener } = dispatched;
|
|
159
|
-
span
|
|
153
|
+
span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
|
|
160
154
|
try {
|
|
161
155
|
await listener(inboxContextFactory(recipient, json, activity?.id?.href, getTypeId(activity).href), activity);
|
|
162
156
|
} catch (error) {
|
|
163
157
|
try {
|
|
164
158
|
await inboxErrorHandler?.(ctx, error);
|
|
165
|
-
} catch (error
|
|
166
|
-
logger
|
|
167
|
-
error
|
|
159
|
+
} catch (error) {
|
|
160
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
161
|
+
error,
|
|
168
162
|
activityId: activity.id?.href,
|
|
169
163
|
activity: json,
|
|
170
164
|
recipient
|
|
171
165
|
});
|
|
172
166
|
}
|
|
173
|
-
logger
|
|
167
|
+
logger.error("Failed to process the incoming activity {activityId}:\n{error}", {
|
|
174
168
|
error,
|
|
175
169
|
activityId: activity.id?.href,
|
|
176
170
|
activity: json,
|
|
177
171
|
recipient
|
|
178
172
|
});
|
|
179
|
-
span
|
|
173
|
+
span.setStatus({
|
|
180
174
|
code: SpanStatusCode.ERROR,
|
|
181
175
|
message: String(error)
|
|
182
176
|
});
|
|
183
|
-
span
|
|
177
|
+
span.end();
|
|
184
178
|
return "error";
|
|
185
179
|
}
|
|
186
180
|
if (cacheKey != null) await kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
|
|
187
|
-
logger
|
|
181
|
+
logger.info("Activity {activityId} has been processed.", {
|
|
188
182
|
activityId: activity.id?.href,
|
|
189
183
|
activity: json,
|
|
190
184
|
recipient
|
|
191
185
|
});
|
|
192
|
-
span
|
|
186
|
+
span.end();
|
|
193
187
|
return "success";
|
|
194
188
|
});
|
|
195
189
|
}
|
|
196
|
-
|
|
197
190
|
//#endregion
|
|
198
191
|
//#region src/federation/router.ts
|
|
199
192
|
function cloneInnerRouter(router) {
|
|
@@ -301,7 +294,6 @@ var RouterError = class extends Error {
|
|
|
301
294
|
this.name = "RouterError";
|
|
302
295
|
}
|
|
303
296
|
};
|
|
304
|
-
|
|
305
297
|
//#endregion
|
|
306
298
|
//#region src/federation/builder.ts
|
|
307
299
|
var FederationBuilderImpl = class {
|
|
@@ -338,8 +330,8 @@ var FederationBuilderImpl = class {
|
|
|
338
330
|
this.collectionTypeIds = {};
|
|
339
331
|
}
|
|
340
332
|
async build(options) {
|
|
341
|
-
const { FederationImpl
|
|
342
|
-
const f = new FederationImpl
|
|
333
|
+
const { FederationImpl } = await Promise.resolve().then(() => middleware_exports);
|
|
334
|
+
const f = new FederationImpl(options);
|
|
343
335
|
const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
|
|
344
336
|
f.router = this.router.clone();
|
|
345
337
|
f.router.trailingSlashInsensitive = trailingSlashInsensitiveValue;
|
|
@@ -365,23 +357,23 @@ var FederationBuilderImpl = class {
|
|
|
365
357
|
return f;
|
|
366
358
|
}
|
|
367
359
|
_getTracer() {
|
|
368
|
-
return trace.getTracer(
|
|
360
|
+
return trace.getTracer(name, version);
|
|
369
361
|
}
|
|
370
362
|
setActorDispatcher(path, dispatcher) {
|
|
371
363
|
if (this.router.has("actor")) throw new RouterError("Actor dispatcher already set.");
|
|
372
364
|
const variables = this.router.add(path, "actor");
|
|
373
365
|
if (variables.size !== 1 || !variables.has("identifier")) throw new RouterError("Path for actor dispatcher must have one variable: {identifier}");
|
|
374
|
-
const callbacks = { dispatcher: async (context
|
|
366
|
+
const callbacks = { dispatcher: async (context, identifier) => {
|
|
375
367
|
const actor = await this._getTracer().startActiveSpan("activitypub.dispatch_actor", {
|
|
376
368
|
kind: SpanKind.SERVER,
|
|
377
369
|
attributes: { "fedify.actor.identifier": identifier }
|
|
378
370
|
}, async (span) => {
|
|
379
371
|
try {
|
|
380
|
-
const actor
|
|
381
|
-
span.setAttribute("activitypub.actor.id", (actor
|
|
382
|
-
if (actor
|
|
383
|
-
else span.setAttribute("activitypub.actor.type", getTypeId(actor
|
|
384
|
-
return actor
|
|
372
|
+
const actor = await dispatcher(context, identifier);
|
|
373
|
+
span.setAttribute("activitypub.actor.id", (actor?.id ?? context.getActorUri(identifier)).href);
|
|
374
|
+
if (actor == null) span.setStatus({ code: SpanStatusCode.ERROR });
|
|
375
|
+
else span.setAttribute("activitypub.actor.type", getTypeId(actor).href);
|
|
376
|
+
return actor;
|
|
385
377
|
} catch (error) {
|
|
386
378
|
span.setStatus({
|
|
387
379
|
code: SpanStatusCode.ERROR,
|
|
@@ -393,52 +385,52 @@ var FederationBuilderImpl = class {
|
|
|
393
385
|
}
|
|
394
386
|
});
|
|
395
387
|
if (actor == null) return null;
|
|
396
|
-
const logger
|
|
388
|
+
const logger = getLogger([
|
|
397
389
|
"fedify",
|
|
398
390
|
"federation",
|
|
399
391
|
"actor"
|
|
400
392
|
]);
|
|
401
|
-
if (actor.id == null) logger
|
|
402
|
-
else if (actor.id.href != context
|
|
393
|
+
if (actor.id == null) logger.warn("Actor dispatcher returned an actor without an id property. Set the property with Context.getActorUri(identifier).");
|
|
394
|
+
else if (actor.id.href != context.getActorUri(identifier).href) logger.warn("Actor dispatcher returned an actor with an id property that does not match the actor URI. Set the property with Context.getActorUri(identifier).");
|
|
403
395
|
if (this.followingCallbacks != null && this.followingCallbacks.dispatcher != null) {
|
|
404
|
-
if (actor.followingId == null) logger
|
|
405
|
-
else if (actor.followingId.href != context
|
|
396
|
+
if (actor.followingId == null) logger.warn("You configured a following collection dispatcher, but the actor does not have a following property. Set the property with Context.getFollowingUri(identifier).");
|
|
397
|
+
else if (actor.followingId.href != context.getFollowingUri(identifier).href) logger.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).");
|
|
406
398
|
}
|
|
407
399
|
if (this.followersCallbacks != null && this.followersCallbacks.dispatcher != null) {
|
|
408
|
-
if (actor.followersId == null) logger
|
|
409
|
-
else if (actor.followersId.href != context
|
|
400
|
+
if (actor.followersId == null) logger.warn("You configured a followers collection dispatcher, but the actor does not have a followers property. Set the property with Context.getFollowersUri(identifier).");
|
|
401
|
+
else if (actor.followersId.href != context.getFollowersUri(identifier).href) logger.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).");
|
|
410
402
|
}
|
|
411
403
|
if (this.outboxCallbacks != null && this.outboxCallbacks.dispatcher != null) {
|
|
412
|
-
if (actor?.outboxId == null) logger
|
|
413
|
-
else if (actor.outboxId.href != context
|
|
404
|
+
if (actor?.outboxId == null) logger.warn("You configured an outbox collection dispatcher, but the actor does not have an outbox property. Set the property with Context.getOutboxUri(identifier).");
|
|
405
|
+
else if (actor.outboxId.href != context.getOutboxUri(identifier).href) logger.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).");
|
|
414
406
|
}
|
|
415
407
|
if (this.likedCallbacks != null && this.likedCallbacks.dispatcher != null) {
|
|
416
|
-
if (actor?.likedId == null) logger
|
|
417
|
-
else if (actor.likedId.href != context
|
|
408
|
+
if (actor?.likedId == null) logger.warn("You configured a liked collection dispatcher, but the actor does not have a liked property. Set the property with Context.getLikedUri(identifier).");
|
|
409
|
+
else if (actor.likedId.href != context.getLikedUri(identifier).href) logger.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).");
|
|
418
410
|
}
|
|
419
411
|
if (this.featuredCallbacks != null && this.featuredCallbacks.dispatcher != null) {
|
|
420
|
-
if (actor?.featuredId == null) logger
|
|
421
|
-
else if (actor.featuredId.href != context
|
|
412
|
+
if (actor?.featuredId == null) logger.warn("You configured a featured collection dispatcher, but the actor does not have a featured property. Set the property with Context.getFeaturedUri(identifier).");
|
|
413
|
+
else if (actor.featuredId.href != context.getFeaturedUri(identifier).href) logger.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).");
|
|
422
414
|
}
|
|
423
415
|
if (this.featuredTagsCallbacks != null && this.featuredTagsCallbacks.dispatcher != null) {
|
|
424
|
-
if (actor?.featuredTagsId == null) logger
|
|
425
|
-
else if (actor.featuredTagsId.href != context
|
|
416
|
+
if (actor?.featuredTagsId == null) logger.warn("You configured a featured tags collection dispatcher, but the actor does not have a featuredTags property. Set the property with Context.getFeaturedTagsUri(identifier).");
|
|
417
|
+
else if (actor.featuredTagsId.href != context.getFeaturedTagsUri(identifier).href) logger.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).");
|
|
426
418
|
}
|
|
427
419
|
if (this.router.has("inbox")) {
|
|
428
|
-
if (actor.inboxId == null) logger
|
|
429
|
-
else if (actor.inboxId.href != context
|
|
430
|
-
if (actor.endpoints == null || actor.endpoints.sharedInbox == null) logger
|
|
431
|
-
else if (actor.endpoints.sharedInbox.href != context
|
|
420
|
+
if (actor.inboxId == null) logger.warn("You configured inbox listeners, but the actor does not have an inbox property. Set the property with Context.getInboxUri(identifier).");
|
|
421
|
+
else if (actor.inboxId.href != context.getInboxUri(identifier).href) logger.warn("You configured inbox listeners, but the actor's inbox property does not match the inbox URI. Set the property with Context.getInboxUri(identifier).");
|
|
422
|
+
if (actor.endpoints == null || actor.endpoints.sharedInbox == null) logger.warn("You configured inbox listeners, but the actor does not have a endpoints.sharedInbox property. Set the property with Context.getInboxUri().");
|
|
423
|
+
else if (actor.endpoints.sharedInbox.href != context.getInboxUri().href) logger.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().");
|
|
432
424
|
}
|
|
433
425
|
if (callbacks.keyPairsDispatcher != null) {
|
|
434
|
-
if (actor.publicKeyId == null) logger
|
|
435
|
-
if (actor.assertionMethodId == null) logger
|
|
426
|
+
if (actor.publicKeyId == null) logger.warn("You configured a key pairs dispatcher, but the actor does not have a publicKey property. Set the property with Context.getActorKeyPairs(identifier).");
|
|
427
|
+
if (actor.assertionMethodId == null) logger.warn("You configured a key pairs dispatcher, but the actor does not have an assertionMethod property. Set the property with Context.getActorKeyPairs(identifier).");
|
|
436
428
|
}
|
|
437
429
|
return actor;
|
|
438
430
|
} };
|
|
439
431
|
this.actorCallbacks = callbacks;
|
|
440
432
|
const setters = {
|
|
441
|
-
setKeyPairsDispatcher: (dispatcher
|
|
433
|
+
setKeyPairsDispatcher: (dispatcher) => {
|
|
442
434
|
callbacks.keyPairsDispatcher = (ctx, identifier) => this._getTracer().startActiveSpan("activitypub.dispatch_actor_key_pairs", {
|
|
443
435
|
kind: SpanKind.SERVER,
|
|
444
436
|
attributes: {
|
|
@@ -447,7 +439,7 @@ var FederationBuilderImpl = class {
|
|
|
447
439
|
}
|
|
448
440
|
}, async (span) => {
|
|
449
441
|
try {
|
|
450
|
-
return await dispatcher
|
|
442
|
+
return await dispatcher(ctx, identifier);
|
|
451
443
|
} catch (e) {
|
|
452
444
|
span.setStatus({
|
|
453
445
|
code: SpanStatusCode.ERROR,
|
|
@@ -477,8 +469,7 @@ var FederationBuilderImpl = class {
|
|
|
477
469
|
}
|
|
478
470
|
setNodeInfoDispatcher(path, dispatcher) {
|
|
479
471
|
if (this.router.has("nodeInfo")) throw new RouterError("NodeInfo dispatcher already set.");
|
|
480
|
-
|
|
481
|
-
if (variables.size !== 0) throw new RouterError("Path for NodeInfo dispatcher must have no variables.");
|
|
472
|
+
if (this.router.add(path, "nodeInfo").size !== 0) throw new RouterError("Path for NodeInfo dispatcher must have no variables.");
|
|
482
473
|
this.nodeInfoDispatcher = dispatcher;
|
|
483
474
|
}
|
|
484
475
|
setWebFingerLinksDispatcher(dispatcher) {
|
|
@@ -491,8 +482,7 @@ var FederationBuilderImpl = class {
|
|
|
491
482
|
if (variables.size < 1) throw new RouterError("Path for object dispatcher must have at least one variable.");
|
|
492
483
|
const callbacks = {
|
|
493
484
|
dispatcher: (ctx, values) => {
|
|
494
|
-
|
|
495
|
-
return tracer.startActiveSpan("activitypub.dispatch_object", {
|
|
485
|
+
return this._getTracer().startActiveSpan("activitypub.dispatch_object", {
|
|
496
486
|
kind: SpanKind.SERVER,
|
|
497
487
|
attributes: {
|
|
498
488
|
"fedify.object.type": cls.typeId.href,
|
|
@@ -723,8 +713,7 @@ var FederationBuilderImpl = class {
|
|
|
723
713
|
this.inboxPath = inboxPath;
|
|
724
714
|
}
|
|
725
715
|
if (sharedInboxPath != null) {
|
|
726
|
-
|
|
727
|
-
if (siVars.size !== 0) throw new RouterError("Path for shared inbox must have no variables.");
|
|
716
|
+
if (this.router.add(sharedInboxPath, "sharedInbox").size !== 0) throw new RouterError("Path for shared inbox must have no variables.");
|
|
728
717
|
}
|
|
729
718
|
const listeners = this.inboxListeners = new InboxListenerSet();
|
|
730
719
|
const setters = {
|
|
@@ -758,8 +747,7 @@ var FederationBuilderImpl = class {
|
|
|
758
747
|
const routeName = `${collectionType}:${this.#uniqueCollectionId(name)}`;
|
|
759
748
|
if (this.router.has(routeName)) throw new RouterError(`Collection dispatcher for ${strName} already set.`);
|
|
760
749
|
if (this.collectionCallbacks[name] != null) throw new RouterError(`Collection dispatcher for ${strName} already set.`);
|
|
761
|
-
|
|
762
|
-
if (variables.size < 1) throw new RouterError("Path for collection dispatcher must have at least one variable.");
|
|
750
|
+
if (this.router.add(path, routeName).size < 1) throw new RouterError("Path for collection dispatcher must have at least one variable.");
|
|
763
751
|
const callbacks = { dispatcher };
|
|
764
752
|
this.collectionCallbacks[name] = callbacks;
|
|
765
753
|
this.collectionTypeIds[name] = itemType;
|
|
@@ -794,8 +782,7 @@ var FederationBuilderImpl = class {
|
|
|
794
782
|
getCollectionPath(name, values) {
|
|
795
783
|
if (!(name in this.collectionCallbacks)) return null;
|
|
796
784
|
const routeName = this.#uniqueCollectionId(name);
|
|
797
|
-
|
|
798
|
-
return path;
|
|
785
|
+
return this.router.build(`collection:${routeName}`, values) ?? this.router.build(`orderedCollection:${routeName}`, values);
|
|
799
786
|
}
|
|
800
787
|
setOutboxPermanentFailureHandler(handler) {
|
|
801
788
|
this.outboxPermanentFailureHandler = handler;
|
|
@@ -821,7 +808,6 @@ var FederationBuilderImpl = class {
|
|
|
821
808
|
function createFederationBuilder() {
|
|
822
809
|
return new FederationBuilderImpl();
|
|
823
810
|
}
|
|
824
|
-
|
|
825
811
|
//#endregion
|
|
826
812
|
//#region src/federation/collection.ts
|
|
827
813
|
/**
|
|
@@ -840,8 +826,8 @@ async function digest(uris) {
|
|
|
840
826
|
if (processed.has(u)) continue;
|
|
841
827
|
processed.add(u);
|
|
842
828
|
const encoded = encoder.encode(u);
|
|
843
|
-
const digest
|
|
844
|
-
for (let i = 0; i < 32; i++) result[i] ^= digest
|
|
829
|
+
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", encoded));
|
|
830
|
+
for (let i = 0; i < 32; i++) result[i] ^= digest[i];
|
|
845
831
|
}
|
|
846
832
|
return result;
|
|
847
833
|
}
|
|
@@ -859,10 +845,8 @@ async function buildCollectionSynchronizationHeader(collectionId, actorIds) {
|
|
|
859
845
|
const baseUrl = new URL(anyActorId);
|
|
860
846
|
const url = new URL(collectionId);
|
|
861
847
|
url.searchParams.set("base-url", `${baseUrl.origin}/`);
|
|
862
|
-
|
|
863
|
-
return `collectionId="${collectionId}", url="${url}", digest="${hash}"`;
|
|
848
|
+
return `collectionId="${collectionId}", url="${url}", digest="${encodeHex(await digest(actorIds))}"`;
|
|
864
849
|
}
|
|
865
|
-
|
|
866
850
|
//#endregion
|
|
867
851
|
//#region src/federation/keycache.ts
|
|
868
852
|
const NULL_KEY_CACHE_VALUE = { _fedify: "key-unavailable" };
|
|
@@ -896,7 +880,7 @@ var KvKeyCache = class {
|
|
|
896
880
|
return await Multikey.fromJsonLd(serialized, this.options);
|
|
897
881
|
} catch {
|
|
898
882
|
await this.kv.delete([...this.prefix, keyId.href]);
|
|
899
|
-
return
|
|
883
|
+
return;
|
|
900
884
|
}
|
|
901
885
|
}
|
|
902
886
|
}
|
|
@@ -911,7 +895,6 @@ var KvKeyCache = class {
|
|
|
911
895
|
await this.kv.set([...this.prefix, keyId.href], serialized);
|
|
912
896
|
}
|
|
913
897
|
};
|
|
914
|
-
|
|
915
898
|
//#endregion
|
|
916
899
|
//#region src/federation/negotiation.ts
|
|
917
900
|
function compareSpecs(a, b) {
|
|
@@ -956,8 +939,8 @@ function parseMediaType(str, i) {
|
|
|
956
939
|
function parseAccept(accept) {
|
|
957
940
|
const accepts = accept.split(",").map((p) => p.trim());
|
|
958
941
|
const mediaTypes = [];
|
|
959
|
-
for (const [index, accept
|
|
960
|
-
const mediaType = parseMediaType(accept
|
|
942
|
+
for (const [index, accept] of accepts.entries()) {
|
|
943
|
+
const mediaType = parseMediaType(accept.trim(), index);
|
|
961
944
|
if (mediaType) mediaTypes.push(mediaType);
|
|
962
945
|
}
|
|
963
946
|
return mediaTypes;
|
|
@@ -966,8 +949,7 @@ function getFullType(spec) {
|
|
|
966
949
|
return `${spec.type}/${spec.subtype}`;
|
|
967
950
|
}
|
|
968
951
|
function preferredMediaTypes(accept) {
|
|
969
|
-
|
|
970
|
-
return accepts.filter(isQuality).sort(compareSpecs).map(getFullType);
|
|
952
|
+
return parseAccept(accept === void 0 ? "*/*" : accept ?? "").filter(isQuality).sort(compareSpecs).map(getFullType);
|
|
971
953
|
}
|
|
972
954
|
function acceptsJsonLd(request) {
|
|
973
955
|
const accept = request.headers.get("Accept");
|
|
@@ -976,7 +958,6 @@ function acceptsJsonLd(request) {
|
|
|
976
958
|
if (types[0] === "text/html" || types[0] === "application/xhtml+xml") return false;
|
|
977
959
|
return types.includes("application/activity+json") || types.includes("application/ld+json") || types.includes("application/json");
|
|
978
960
|
}
|
|
979
|
-
|
|
980
961
|
//#endregion
|
|
981
962
|
//#region src/federation/handler.ts
|
|
982
963
|
/**
|
|
@@ -986,25 +967,25 @@ function acceptsJsonLd(request) {
|
|
|
986
967
|
* @param parameters The parameters for handling the actor.
|
|
987
968
|
* @returns A promise that resolves to an HTTP response.
|
|
988
969
|
*/
|
|
989
|
-
async function handleActor(request, { identifier, context
|
|
990
|
-
const logger
|
|
970
|
+
async function handleActor(request, { identifier, context, actorDispatcher, authorizePredicate, onNotFound, onUnauthorized }) {
|
|
971
|
+
const logger = getLogger([
|
|
991
972
|
"fedify",
|
|
992
973
|
"federation",
|
|
993
974
|
"actor"
|
|
994
975
|
]);
|
|
995
976
|
if (actorDispatcher == null) {
|
|
996
|
-
logger
|
|
977
|
+
logger.debug("Actor dispatcher is not set.", { identifier });
|
|
997
978
|
return await onNotFound(request);
|
|
998
979
|
}
|
|
999
|
-
const actor = await actorDispatcher(context
|
|
980
|
+
const actor = await actorDispatcher(context, identifier);
|
|
1000
981
|
if (actor == null) {
|
|
1001
|
-
logger
|
|
982
|
+
logger.debug("Actor {identifier} not found.", { identifier });
|
|
1002
983
|
return await onNotFound(request);
|
|
1003
984
|
}
|
|
1004
985
|
if (authorizePredicate != null) {
|
|
1005
|
-
if (!await authorizePredicate(context
|
|
986
|
+
if (!await authorizePredicate(context, identifier)) return await onUnauthorized(request);
|
|
1006
987
|
}
|
|
1007
|
-
const jsonLd = await actor.toJsonLd(context
|
|
988
|
+
const jsonLd = await actor.toJsonLd(context);
|
|
1008
989
|
return new Response(JSON.stringify(jsonLd), { headers: {
|
|
1009
990
|
"Content-Type": "application/activity+json",
|
|
1010
991
|
Vary: "Accept"
|
|
@@ -1017,14 +998,14 @@ async function handleActor(request, { identifier, context: context$1, actorDispa
|
|
|
1017
998
|
* @param parameters The parameters for handling the object.
|
|
1018
999
|
* @returns A promise that resolves to an HTTP response.
|
|
1019
1000
|
*/
|
|
1020
|
-
async function handleObject(request, { values, context
|
|
1001
|
+
async function handleObject(request, { values, context, objectDispatcher, authorizePredicate, onNotFound, onUnauthorized }) {
|
|
1021
1002
|
if (objectDispatcher == null) return await onNotFound(request);
|
|
1022
|
-
const object = await objectDispatcher(context
|
|
1003
|
+
const object = await objectDispatcher(context, values);
|
|
1023
1004
|
if (object == null) return await onNotFound(request);
|
|
1024
1005
|
if (authorizePredicate != null) {
|
|
1025
|
-
if (!await authorizePredicate(context
|
|
1006
|
+
if (!await authorizePredicate(context, values)) return await onUnauthorized(request);
|
|
1026
1007
|
}
|
|
1027
|
-
const jsonLd = await object.toJsonLd(context
|
|
1008
|
+
const jsonLd = await object.toJsonLd(context);
|
|
1028
1009
|
return new Response(JSON.stringify(jsonLd), { headers: {
|
|
1029
1010
|
"Content-Type": "application/activity+json",
|
|
1030
1011
|
Vary: "Accept"
|
|
@@ -1040,18 +1021,17 @@ async function handleObject(request, { values, context: context$1, objectDispatc
|
|
|
1040
1021
|
* @param parameters The parameters for handling the collection.
|
|
1041
1022
|
* @returns A promise that resolves to an HTTP response.
|
|
1042
1023
|
*/
|
|
1043
|
-
async function handleCollection(request, { name, identifier, uriGetter, filter, filterPredicate, context
|
|
1044
|
-
const spanName = name.trim().replace(/\s+/g, "_");
|
|
1024
|
+
async function handleCollection(request, { name: name$1, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, onUnauthorized, onNotFound }) {
|
|
1025
|
+
const spanName = name$1.trim().replace(/\s+/g, "_");
|
|
1045
1026
|
tracerProvider = tracerProvider ?? trace.getTracerProvider();
|
|
1046
|
-
const tracer = tracerProvider.getTracer(
|
|
1047
|
-
const
|
|
1048
|
-
const cursor = url.searchParams.get("cursor");
|
|
1027
|
+
const tracer = tracerProvider.getTracer(name, version);
|
|
1028
|
+
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
1049
1029
|
if (collectionCallbacks == null) return await onNotFound(request);
|
|
1050
1030
|
let collection;
|
|
1051
1031
|
const baseUri = uriGetter(identifier);
|
|
1052
1032
|
if (cursor == null) {
|
|
1053
|
-
const firstCursor = await collectionCallbacks.firstCursor?.(context
|
|
1054
|
-
const totalItems = filter == null ? await collectionCallbacks.counter?.(context
|
|
1033
|
+
const firstCursor = await collectionCallbacks.firstCursor?.(context, identifier);
|
|
1034
|
+
const totalItems = filter == null ? await collectionCallbacks.counter?.(context, identifier) : void 0;
|
|
1055
1035
|
if (firstCursor == null) {
|
|
1056
1036
|
const itemsOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection ${spanName}`, {
|
|
1057
1037
|
kind: SpanKind.SERVER,
|
|
@@ -1062,7 +1042,7 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
1062
1042
|
}, async (span) => {
|
|
1063
1043
|
if (totalItems != null) span.setAttribute("activitypub.collection.total_items", Number(totalItems));
|
|
1064
1044
|
try {
|
|
1065
|
-
const page = await collectionCallbacks.dispatcher(context
|
|
1045
|
+
const page = await collectionCallbacks.dispatcher(context, identifier, null, filter);
|
|
1066
1046
|
if (page == null) {
|
|
1067
1047
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1068
1048
|
return await onNotFound(request);
|
|
@@ -1084,15 +1064,15 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
1084
1064
|
collection = new OrderedCollection({
|
|
1085
1065
|
id: baseUri,
|
|
1086
1066
|
totalItems: totalItems == null ? null : Number(totalItems),
|
|
1087
|
-
items: filterCollectionItems(itemsOrResponse, name, filterPredicate)
|
|
1067
|
+
items: filterCollectionItems(itemsOrResponse, name$1, filterPredicate)
|
|
1088
1068
|
});
|
|
1089
1069
|
} else {
|
|
1090
|
-
const lastCursor = await collectionCallbacks.lastCursor?.(context
|
|
1091
|
-
const first = new URL(context
|
|
1070
|
+
const lastCursor = await collectionCallbacks.lastCursor?.(context, identifier);
|
|
1071
|
+
const first = new URL(context.url);
|
|
1092
1072
|
first.searchParams.set("cursor", firstCursor);
|
|
1093
1073
|
let last = null;
|
|
1094
1074
|
if (lastCursor != null) {
|
|
1095
|
-
last = new URL(context
|
|
1075
|
+
last = new URL(context.url);
|
|
1096
1076
|
last.searchParams.set("cursor", lastCursor);
|
|
1097
1077
|
}
|
|
1098
1078
|
collection = new OrderedCollection({
|
|
@@ -1105,7 +1085,7 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
1105
1085
|
} else {
|
|
1106
1086
|
const uri = new URL(baseUri);
|
|
1107
1087
|
uri.searchParams.set("cursor", cursor);
|
|
1108
|
-
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name}`, {
|
|
1088
|
+
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
|
|
1109
1089
|
kind: SpanKind.SERVER,
|
|
1110
1090
|
attributes: {
|
|
1111
1091
|
"activitypub.collection.id": uri.href,
|
|
@@ -1114,7 +1094,7 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
1114
1094
|
}
|
|
1115
1095
|
}, async (span) => {
|
|
1116
1096
|
try {
|
|
1117
|
-
const page = await collectionCallbacks.dispatcher(context
|
|
1097
|
+
const page = await collectionCallbacks.dispatcher(context, identifier, cursor, filter);
|
|
1118
1098
|
if (page == null) {
|
|
1119
1099
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1120
1100
|
return await onNotFound(request);
|
|
@@ -1135,28 +1115,28 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
1135
1115
|
const { items, prevCursor, nextCursor } = pageOrResponse;
|
|
1136
1116
|
let prev = null;
|
|
1137
1117
|
if (prevCursor != null) {
|
|
1138
|
-
prev = new URL(context
|
|
1118
|
+
prev = new URL(context.url);
|
|
1139
1119
|
prev.searchParams.set("cursor", prevCursor);
|
|
1140
1120
|
}
|
|
1141
1121
|
let next = null;
|
|
1142
1122
|
if (nextCursor != null) {
|
|
1143
|
-
next = new URL(context
|
|
1123
|
+
next = new URL(context.url);
|
|
1144
1124
|
next.searchParams.set("cursor", nextCursor);
|
|
1145
1125
|
}
|
|
1146
|
-
const partOf = new URL(context
|
|
1126
|
+
const partOf = new URL(context.url);
|
|
1147
1127
|
partOf.searchParams.delete("cursor");
|
|
1148
1128
|
collection = new OrderedCollectionPage({
|
|
1149
1129
|
id: uri,
|
|
1150
1130
|
prev,
|
|
1151
1131
|
next,
|
|
1152
|
-
items: filterCollectionItems(items, name, filterPredicate),
|
|
1132
|
+
items: filterCollectionItems(items, name$1, filterPredicate),
|
|
1153
1133
|
partOf
|
|
1154
1134
|
});
|
|
1155
1135
|
}
|
|
1156
1136
|
if (collectionCallbacks.authorizePredicate != null) {
|
|
1157
|
-
if (!await collectionCallbacks.authorizePredicate(context
|
|
1137
|
+
if (!await collectionCallbacks.authorizePredicate(context, identifier)) return await onUnauthorized(request);
|
|
1158
1138
|
}
|
|
1159
|
-
const jsonLd = await collection.toJsonLd(context
|
|
1139
|
+
const jsonLd = await collection.toJsonLd(context);
|
|
1160
1140
|
return new Response(JSON.stringify(jsonLd), { headers: {
|
|
1161
1141
|
"Content-Type": "application/activity+json",
|
|
1162
1142
|
Vary: "Accept"
|
|
@@ -1201,9 +1181,7 @@ function filterCollectionItems(items, collectionName, filterPredicate) {
|
|
|
1201
1181
|
* @returns A promise that resolves to an HTTP response.
|
|
1202
1182
|
*/
|
|
1203
1183
|
async function handleInbox(request, options) {
|
|
1204
|
-
|
|
1205
|
-
const tracer = tracerProvider.getTracer(deno_default.name, deno_default.version);
|
|
1206
|
-
return await tracer.startActiveSpan("activitypub.inbox", {
|
|
1184
|
+
return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("activitypub.inbox", {
|
|
1207
1185
|
kind: options.queue == null ? SpanKind.SERVER : SpanKind.PRODUCER,
|
|
1208
1186
|
attributes: { "activitypub.shared_inbox": options.recipient == null }
|
|
1209
1187
|
}, async (span) => {
|
|
@@ -1231,22 +1209,21 @@ async function handleInbox(request, options) {
|
|
|
1231
1209
|
*/
|
|
1232
1210
|
async function handleInboxInternal(request, parameters, span) {
|
|
1233
1211
|
const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, tracerProvider } = parameters;
|
|
1234
|
-
const logger
|
|
1212
|
+
const logger = getLogger([
|
|
1235
1213
|
"fedify",
|
|
1236
1214
|
"federation",
|
|
1237
1215
|
"inbox"
|
|
1238
1216
|
]);
|
|
1239
1217
|
if (actorDispatcher == null) {
|
|
1240
|
-
logger
|
|
1218
|
+
logger.error("Actor dispatcher is not set.", { recipient });
|
|
1241
1219
|
span.setStatus({
|
|
1242
1220
|
code: SpanStatusCode.ERROR,
|
|
1243
1221
|
message: "Actor dispatcher is not set."
|
|
1244
1222
|
});
|
|
1245
1223
|
return await onNotFound(request);
|
|
1246
1224
|
} else if (recipient != null) {
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
logger$1.error("Actor {recipient} not found.", { recipient });
|
|
1225
|
+
if (await actorDispatcher(ctx, recipient) == null) {
|
|
1226
|
+
logger.error("Actor {recipient} not found.", { recipient });
|
|
1250
1227
|
span.setStatus({
|
|
1251
1228
|
code: SpanStatusCode.ERROR,
|
|
1252
1229
|
message: `Actor ${recipient} not found.`
|
|
@@ -1255,7 +1232,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1255
1232
|
}
|
|
1256
1233
|
}
|
|
1257
1234
|
if (request.bodyUsed) {
|
|
1258
|
-
logger
|
|
1235
|
+
logger.error("Request body has already been read.", { recipient });
|
|
1259
1236
|
span.setStatus({
|
|
1260
1237
|
code: SpanStatusCode.ERROR,
|
|
1261
1238
|
message: "Request body has already been read."
|
|
@@ -1265,7 +1242,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1265
1242
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
1266
1243
|
});
|
|
1267
1244
|
} else if (request.body?.locked) {
|
|
1268
|
-
logger
|
|
1245
|
+
logger.error("Request body is locked.", { recipient });
|
|
1269
1246
|
span.setStatus({
|
|
1270
1247
|
code: SpanStatusCode.ERROR,
|
|
1271
1248
|
message: "Request body is locked."
|
|
@@ -1279,15 +1256,15 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1279
1256
|
try {
|
|
1280
1257
|
json = await request.clone().json();
|
|
1281
1258
|
} catch (error) {
|
|
1282
|
-
logger
|
|
1259
|
+
logger.error("Failed to parse JSON:\n{error}", {
|
|
1283
1260
|
recipient,
|
|
1284
1261
|
error
|
|
1285
1262
|
});
|
|
1286
1263
|
try {
|
|
1287
1264
|
await inboxErrorHandler?.(ctx, error);
|
|
1288
|
-
} catch (error
|
|
1289
|
-
logger
|
|
1290
|
-
error
|
|
1265
|
+
} catch (error) {
|
|
1266
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
1267
|
+
error,
|
|
1291
1268
|
activity: json,
|
|
1292
1269
|
recipient
|
|
1293
1270
|
});
|
|
@@ -1312,7 +1289,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1312
1289
|
});
|
|
1313
1290
|
} catch (error) {
|
|
1314
1291
|
if (error instanceof Error && error.name === "jsonld.SyntaxError") {
|
|
1315
|
-
logger
|
|
1292
|
+
logger.error("Failed to parse JSON-LD:\n{error}", {
|
|
1316
1293
|
recipient,
|
|
1317
1294
|
error
|
|
1318
1295
|
});
|
|
@@ -1326,13 +1303,13 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1326
1303
|
const jsonWithoutSig = detachSignature(json);
|
|
1327
1304
|
let activity = null;
|
|
1328
1305
|
if (ldSigVerified) {
|
|
1329
|
-
logger
|
|
1306
|
+
logger.debug("Linked Data Signatures are verified.", {
|
|
1330
1307
|
recipient,
|
|
1331
1308
|
json
|
|
1332
1309
|
});
|
|
1333
1310
|
activity = await Activity.fromJsonLd(jsonWithoutSig, ctx);
|
|
1334
1311
|
} else {
|
|
1335
|
-
logger
|
|
1312
|
+
logger.debug("Linked Data Signatures are not verified.", {
|
|
1336
1313
|
recipient,
|
|
1337
1314
|
json
|
|
1338
1315
|
});
|
|
@@ -1344,16 +1321,16 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1344
1321
|
tracerProvider
|
|
1345
1322
|
});
|
|
1346
1323
|
} catch (error) {
|
|
1347
|
-
logger
|
|
1324
|
+
logger.error("Failed to parse activity:\n{error}", {
|
|
1348
1325
|
recipient,
|
|
1349
1326
|
activity: json,
|
|
1350
1327
|
error
|
|
1351
1328
|
});
|
|
1352
1329
|
try {
|
|
1353
1330
|
await inboxErrorHandler?.(ctx, error);
|
|
1354
|
-
} catch (error
|
|
1355
|
-
logger
|
|
1356
|
-
error
|
|
1331
|
+
} catch (error) {
|
|
1332
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
1333
|
+
error,
|
|
1357
1334
|
activity: json,
|
|
1358
1335
|
recipient
|
|
1359
1336
|
});
|
|
@@ -1367,11 +1344,11 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1367
1344
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
1368
1345
|
});
|
|
1369
1346
|
}
|
|
1370
|
-
if (activity == null) logger
|
|
1347
|
+
if (activity == null) logger.debug("Object Integrity Proofs are not verified.", {
|
|
1371
1348
|
recipient,
|
|
1372
1349
|
activity: json
|
|
1373
1350
|
});
|
|
1374
|
-
else logger
|
|
1351
|
+
else logger.debug("Object Integrity Proofs are verified.", {
|
|
1375
1352
|
recipient,
|
|
1376
1353
|
activity: json
|
|
1377
1354
|
});
|
|
@@ -1387,17 +1364,16 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1387
1364
|
tracerProvider
|
|
1388
1365
|
});
|
|
1389
1366
|
if (key == null) {
|
|
1390
|
-
logger
|
|
1367
|
+
logger.error("Failed to verify the request's HTTP Signatures.", { recipient });
|
|
1391
1368
|
span.setStatus({
|
|
1392
1369
|
code: SpanStatusCode.ERROR,
|
|
1393
1370
|
message: `Failed to verify the request's HTTP Signatures.`
|
|
1394
1371
|
});
|
|
1395
|
-
|
|
1372
|
+
return new Response("Failed to verify the request signature.", {
|
|
1396
1373
|
status: 401,
|
|
1397
1374
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
1398
1375
|
});
|
|
1399
|
-
|
|
1400
|
-
} else logger$1.debug("HTTP Signatures are verified.", { recipient });
|
|
1376
|
+
} else logger.debug("HTTP Signatures are verified.", { recipient });
|
|
1401
1377
|
httpSigKey = key;
|
|
1402
1378
|
}
|
|
1403
1379
|
activity = await Activity.fromJsonLd(jsonWithoutSig, ctx);
|
|
@@ -1412,7 +1388,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1412
1388
|
"http_signatures.key_id": httpSigKey?.id?.href ?? ""
|
|
1413
1389
|
});
|
|
1414
1390
|
if (httpSigKey != null && !await doesActorOwnKey(activity, httpSigKey, ctx)) {
|
|
1415
|
-
logger
|
|
1391
|
+
logger.error("The signer ({keyId}) and the actor ({actorId}) do not match.", {
|
|
1416
1392
|
activity: json,
|
|
1417
1393
|
recipient,
|
|
1418
1394
|
keyId: httpSigKey.id?.href,
|
|
@@ -1479,11 +1455,11 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1479
1455
|
* @since 1.8.0
|
|
1480
1456
|
*/
|
|
1481
1457
|
const handleCustomCollection = exceptWrapper(_handleCustomCollection);
|
|
1482
|
-
async function _handleCustomCollection(request, { name, values, context
|
|
1458
|
+
async function _handleCustomCollection(request, { name, values, context, tracerProvider, collectionCallbacks: callbacks, filterPredicate }) {
|
|
1483
1459
|
verifyDefined(callbacks);
|
|
1484
|
-
await authIfNeeded(context
|
|
1460
|
+
await authIfNeeded(context, values, callbacks);
|
|
1485
1461
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
1486
|
-
return await new CustomCollectionHandler(name, values, context
|
|
1462
|
+
return await new CustomCollectionHandler(name, values, context, callbacks, tracerProvider, Collection, CollectionPage, filterPredicate).fetchCollection(cursor).toJsonLd().then(respondAsActivity);
|
|
1487
1463
|
}
|
|
1488
1464
|
/**
|
|
1489
1465
|
* Handles an ordered collection request.
|
|
@@ -1497,11 +1473,11 @@ async function _handleCustomCollection(request, { name, values, context: context
|
|
|
1497
1473
|
* @since 1.8.0
|
|
1498
1474
|
*/
|
|
1499
1475
|
const handleOrderedCollection = exceptWrapper(_handleOrderedCollection);
|
|
1500
|
-
async function _handleOrderedCollection(request, { name, values, context
|
|
1476
|
+
async function _handleOrderedCollection(request, { name, values, context, tracerProvider, collectionCallbacks: callbacks, filterPredicate }) {
|
|
1501
1477
|
verifyDefined(callbacks);
|
|
1502
|
-
await authIfNeeded(context
|
|
1478
|
+
await authIfNeeded(context, values, callbacks);
|
|
1503
1479
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
1504
|
-
return await new CustomCollectionHandler(name, values, context
|
|
1480
|
+
return await new CustomCollectionHandler(name, values, context, callbacks, tracerProvider, OrderedCollection, OrderedCollectionPage, filterPredicate).fetchCollection(cursor).toJsonLd().then(respondAsActivity);
|
|
1505
1481
|
}
|
|
1506
1482
|
/**
|
|
1507
1483
|
* Handling custom collections with support for pagination and filtering.
|
|
@@ -1551,17 +1527,17 @@ var CustomCollectionHandler = class {
|
|
|
1551
1527
|
* @param CollectionPage The CollectionPage constructor.
|
|
1552
1528
|
* @param filterPredicate Optional filter predicate for items.
|
|
1553
1529
|
*/
|
|
1554
|
-
constructor(name, values, context
|
|
1555
|
-
this.name = name;
|
|
1530
|
+
constructor(name$2, values, context, callbacks, tracerProvider = trace.getTracerProvider(), Collection, CollectionPage, filterPredicate) {
|
|
1531
|
+
this.name = name$2;
|
|
1556
1532
|
this.values = values;
|
|
1557
|
-
this.context = context
|
|
1533
|
+
this.context = context;
|
|
1558
1534
|
this.callbacks = callbacks;
|
|
1559
1535
|
this.tracerProvider = tracerProvider;
|
|
1560
|
-
this.Collection = Collection
|
|
1561
|
-
this.CollectionPage = CollectionPage
|
|
1536
|
+
this.Collection = Collection;
|
|
1537
|
+
this.CollectionPage = CollectionPage;
|
|
1562
1538
|
this.filterPredicate = filterPredicate;
|
|
1563
1539
|
this.name = this.name.trim().replace(/\s+/g, "_");
|
|
1564
|
-
this.#tracer = this.tracerProvider.getTracer(
|
|
1540
|
+
this.#tracer = this.tracerProvider.getTracer(name, version);
|
|
1565
1541
|
this.#id = new URL(this.context.url);
|
|
1566
1542
|
this.#dispatcher = callbacks.dispatcher.bind(callbacks);
|
|
1567
1543
|
}
|
|
@@ -1590,8 +1566,8 @@ var CustomCollectionHandler = class {
|
|
|
1590
1566
|
*/
|
|
1591
1567
|
async getCollection(cursor = null) {
|
|
1592
1568
|
if (cursor !== null) {
|
|
1593
|
-
const props
|
|
1594
|
-
return new this.CollectionPage(props
|
|
1569
|
+
const props = await this.getPageProps(cursor);
|
|
1570
|
+
return new this.CollectionPage(props);
|
|
1595
1571
|
}
|
|
1596
1572
|
const firstCursor = await this.firstCursor;
|
|
1597
1573
|
const props = typeof firstCursor === "string" ? await this.getProps(firstCursor) : await this.getPropsWithoutCursor();
|
|
@@ -1739,7 +1715,7 @@ var CustomCollectionHandler = class {
|
|
|
1739
1715
|
* @param value The total items count or a promise that resolves to it.
|
|
1740
1716
|
*/
|
|
1741
1717
|
set totalItems(value) {
|
|
1742
|
-
const toNumber = (value
|
|
1718
|
+
const toNumber = (value) => value == null ? null : Number(value);
|
|
1743
1719
|
this.#totalItems = value instanceof Promise ? value.then(toNumber) : Promise.resolve(toNumber(value));
|
|
1744
1720
|
}
|
|
1745
1721
|
/**
|
|
@@ -1803,9 +1779,9 @@ const verifyDefined = (callbacks) => {
|
|
|
1803
1779
|
* @throws {UnauthorizedError} If authorization fails.
|
|
1804
1780
|
* @since 1.8.0
|
|
1805
1781
|
*/
|
|
1806
|
-
const authIfNeeded = async (context
|
|
1782
|
+
const authIfNeeded = async (context, values, { authorizePredicate: authorize = void 0 }) => {
|
|
1807
1783
|
if (authorize === void 0) return;
|
|
1808
|
-
if (!await authorize(context
|
|
1784
|
+
if (!await authorize(context, values)) throw new UnauthorizedError();
|
|
1809
1785
|
};
|
|
1810
1786
|
/**
|
|
1811
1787
|
* Appends a cursor parameter to a URL if the cursor exists.
|
|
@@ -1891,7 +1867,6 @@ async function respondWithObjectIfAcceptable(object, request, options) {
|
|
|
1891
1867
|
response.headers.set("Vary", "Accept");
|
|
1892
1868
|
return response;
|
|
1893
1869
|
}
|
|
1894
|
-
|
|
1895
1870
|
//#endregion
|
|
1896
1871
|
//#region src/nodeinfo/handler.ts
|
|
1897
1872
|
/**
|
|
@@ -1901,10 +1876,9 @@ async function respondWithObjectIfAcceptable(object, request, options) {
|
|
|
1901
1876
|
* @param parameters The parameters for handling the request.
|
|
1902
1877
|
* @returns The response to the request.
|
|
1903
1878
|
*/
|
|
1904
|
-
async function handleNodeInfo(_request, { context
|
|
1905
|
-
const promise = nodeInfoDispatcher(context
|
|
1906
|
-
const
|
|
1907
|
-
const json = nodeInfoToJson(nodeInfo);
|
|
1879
|
+
async function handleNodeInfo(_request, { context, nodeInfoDispatcher }) {
|
|
1880
|
+
const promise = nodeInfoDispatcher(context);
|
|
1881
|
+
const json = nodeInfoToJson(promise instanceof Promise ? await promise : promise);
|
|
1908
1882
|
return new Response(JSON.stringify(json), { headers: { "Content-Type": "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\"" } });
|
|
1909
1883
|
}
|
|
1910
1884
|
/**
|
|
@@ -1914,22 +1888,20 @@ async function handleNodeInfo(_request, { context: context$1, nodeInfoDispatcher
|
|
|
1914
1888
|
* @param context The request context.
|
|
1915
1889
|
* @returns The response to the request.
|
|
1916
1890
|
*/
|
|
1917
|
-
function handleNodeInfoJrd(_request, context
|
|
1891
|
+
function handleNodeInfoJrd(_request, context) {
|
|
1918
1892
|
const links = [];
|
|
1919
1893
|
try {
|
|
1920
1894
|
links.push({
|
|
1921
1895
|
rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
|
|
1922
|
-
href: context
|
|
1896
|
+
href: context.getNodeInfoUri().href,
|
|
1923
1897
|
type: "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\""
|
|
1924
1898
|
});
|
|
1925
1899
|
} catch (e) {
|
|
1926
1900
|
if (!(e instanceof RouterError)) throw e;
|
|
1927
1901
|
}
|
|
1928
|
-
const
|
|
1929
|
-
const response = new Response(JSON.stringify(jrd), { headers: { "Content-Type": "application/jrd+json" } });
|
|
1902
|
+
const response = new Response(JSON.stringify({ links }), { headers: { "Content-Type": "application/jrd+json" } });
|
|
1930
1903
|
return Promise.resolve(response);
|
|
1931
1904
|
}
|
|
1932
|
-
|
|
1933
1905
|
//#endregion
|
|
1934
1906
|
//#region src/federation/retry.ts
|
|
1935
1907
|
/**
|
|
@@ -1960,7 +1932,6 @@ function createExponentialBackoffPolicy(options = {}) {
|
|
|
1960
1932
|
return Temporal.Duration.compare(delay, maxDelay) > 0 ? maxDelay : delay;
|
|
1961
1933
|
};
|
|
1962
1934
|
}
|
|
1963
|
-
|
|
1964
1935
|
//#endregion
|
|
1965
1936
|
//#region src/federation/send.ts
|
|
1966
1937
|
/**
|
|
@@ -1998,8 +1969,7 @@ function extractInboxes({ recipients, preferSharedInbox, excludeBaseUris }) {
|
|
|
1998
1969
|
*/
|
|
1999
1970
|
function sendActivity(options) {
|
|
2000
1971
|
const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
|
|
2001
|
-
|
|
2002
|
-
return tracer.startActiveSpan("activitypub.send_activity", {
|
|
1972
|
+
return tracerProvider.getTracer(name, version).startActiveSpan("activitypub.send_activity", {
|
|
2003
1973
|
kind: SpanKind.CLIENT,
|
|
2004
1974
|
attributes: { "activitypub.shared_inbox": options.sharedInbox ?? false }
|
|
2005
1975
|
}, async (span) => {
|
|
@@ -2050,7 +2020,7 @@ async function readLimitedResponseBody(response, maxBytes) {
|
|
|
2050
2020
|
return result;
|
|
2051
2021
|
}
|
|
2052
2022
|
async function sendActivityInternal({ activity, activityId, keys, inbox, headers, specDeterminer, tracerProvider }, span) {
|
|
2053
|
-
const logger
|
|
2023
|
+
const logger = getLogger([
|
|
2054
2024
|
"fedify",
|
|
2055
2025
|
"federation",
|
|
2056
2026
|
"outbox"
|
|
@@ -2067,7 +2037,7 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
|
|
|
2067
2037
|
rsaKey = key;
|
|
2068
2038
|
break;
|
|
2069
2039
|
}
|
|
2070
|
-
if (rsaKey == null) logger
|
|
2040
|
+
if (rsaKey == null) logger.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.", {
|
|
2071
2041
|
inbox: inbox.href,
|
|
2072
2042
|
keys: keys.map((pair) => ({
|
|
2073
2043
|
keyId: pair.keyId.href,
|
|
@@ -2081,7 +2051,7 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
|
|
|
2081
2051
|
specDeterminer
|
|
2082
2052
|
});
|
|
2083
2053
|
} catch (error) {
|
|
2084
|
-
logger
|
|
2054
|
+
logger.error("Failed to send activity {activityId} to {inbox}:\n{error}", {
|
|
2085
2055
|
activityId,
|
|
2086
2056
|
inbox: inbox.href,
|
|
2087
2057
|
error
|
|
@@ -2095,7 +2065,7 @@ async function sendActivityInternal({ activity, activityId, keys, inbox, headers
|
|
|
2095
2065
|
} catch (_) {
|
|
2096
2066
|
error = "";
|
|
2097
2067
|
}
|
|
2098
|
-
logger
|
|
2068
|
+
logger.error("Failed to send activity {activityId} to {inbox} ({status} {statusText}):\n{error}", {
|
|
2099
2069
|
activityId,
|
|
2100
2070
|
inbox: inbox.href,
|
|
2101
2071
|
status: response.status,
|
|
@@ -2147,7 +2117,6 @@ var SendActivityError = class extends Error {
|
|
|
2147
2117
|
this.responseBody = responseBody;
|
|
2148
2118
|
}
|
|
2149
2119
|
};
|
|
2150
|
-
|
|
2151
2120
|
//#endregion
|
|
2152
2121
|
//#region src/federation/webfinger.ts
|
|
2153
2122
|
const logger = getLogger([
|
|
@@ -2180,12 +2149,12 @@ async function handleWebFinger(request, options) {
|
|
|
2180
2149
|
}
|
|
2181
2150
|
});
|
|
2182
2151
|
}
|
|
2183
|
-
async function handleWebFingerInternal(request, { context
|
|
2152
|
+
async function handleWebFingerInternal(request, { context, host, actorDispatcher, actorHandleMapper, actorAliasMapper, onNotFound, span, webFingerLinksDispatcher }) {
|
|
2184
2153
|
if (actorDispatcher == null) {
|
|
2185
2154
|
logger.error("Actor dispatcher is not set.");
|
|
2186
2155
|
return await onNotFound(request);
|
|
2187
2156
|
}
|
|
2188
|
-
const resource = context
|
|
2157
|
+
const resource = context.url.searchParams.get("resource");
|
|
2189
2158
|
if (resource == null) return new Response("Missing resource parameter.", { status: 400 });
|
|
2190
2159
|
span?.setAttribute("webfinger.resource", resource);
|
|
2191
2160
|
let resourceUrl;
|
|
@@ -2201,26 +2170,26 @@ async function handleWebFingerInternal(request, { context: context$1, host, acto
|
|
|
2201
2170
|
logger.error("No actor handle mapper is set; use the WebFinger username {username} as the actor's internal identifier.", { username });
|
|
2202
2171
|
return username;
|
|
2203
2172
|
}
|
|
2204
|
-
const identifier
|
|
2205
|
-
if (identifier
|
|
2173
|
+
const identifier = await actorHandleMapper(context, username);
|
|
2174
|
+
if (identifier == null) {
|
|
2206
2175
|
logger.error("Actor {username} not found.", { username });
|
|
2207
2176
|
return null;
|
|
2208
2177
|
}
|
|
2209
|
-
return identifier
|
|
2178
|
+
return identifier;
|
|
2210
2179
|
}
|
|
2211
2180
|
let identifier = null;
|
|
2212
|
-
const uriParsed = context
|
|
2181
|
+
const uriParsed = context.parseUri(resourceUrl);
|
|
2213
2182
|
if (uriParsed?.type != "actor") {
|
|
2214
2183
|
const match = /^acct:([^@]+)@([^@]+)$/.exec(resource);
|
|
2215
2184
|
if (match == null) {
|
|
2216
|
-
const result = await actorAliasMapper?.(context
|
|
2185
|
+
const result = await actorAliasMapper?.(context, resourceUrl);
|
|
2217
2186
|
if (result == null) return await onNotFound(request);
|
|
2218
2187
|
if ("identifier" in result) identifier = result.identifier;
|
|
2219
2188
|
else identifier = await mapUsernameToIdentifier(result.username);
|
|
2220
2189
|
} else {
|
|
2221
2190
|
const portMatch = /:\d+$/.exec(match[2]);
|
|
2222
2191
|
const normalizedHost = portMatch == null ? domainToASCII(match[2].toLowerCase()) : domainToASCII(match[2].substring(0, portMatch.index).toLowerCase()) + portMatch[0];
|
|
2223
|
-
if (normalizedHost != context
|
|
2192
|
+
if (normalizedHost != context.url.host && normalizedHost != host) return await onNotFound(request);
|
|
2224
2193
|
else {
|
|
2225
2194
|
identifier = await mapUsernameToIdentifier(match[1]);
|
|
2226
2195
|
resourceUrl = new URL(`acct:${match[1]}@${normalizedHost}`);
|
|
@@ -2228,14 +2197,14 @@ async function handleWebFingerInternal(request, { context: context$1, host, acto
|
|
|
2228
2197
|
}
|
|
2229
2198
|
} else identifier = uriParsed.identifier;
|
|
2230
2199
|
if (identifier == null) return await onNotFound(request);
|
|
2231
|
-
const actor = await actorDispatcher(context
|
|
2200
|
+
const actor = await actorDispatcher(context, identifier);
|
|
2232
2201
|
if (actor == null) {
|
|
2233
2202
|
logger.error("Actor {identifier} not found.", { identifier });
|
|
2234
2203
|
return await onNotFound(request);
|
|
2235
2204
|
}
|
|
2236
2205
|
const links = [{
|
|
2237
2206
|
rel: "self",
|
|
2238
|
-
href: context
|
|
2207
|
+
href: context.getActorUri(identifier).href,
|
|
2239
2208
|
type: "application/activity+json"
|
|
2240
2209
|
}];
|
|
2241
2210
|
for (const url of actor.urls) if (url instanceof Link && url.href != null) links.push({
|
|
@@ -2256,16 +2225,16 @@ async function handleWebFingerInternal(request, { context: context$1, host, acto
|
|
|
2256
2225
|
});
|
|
2257
2226
|
}
|
|
2258
2227
|
if (webFingerLinksDispatcher != null) {
|
|
2259
|
-
const customLinks = await webFingerLinksDispatcher(context
|
|
2228
|
+
const customLinks = await webFingerLinksDispatcher(context, resourceUrl);
|
|
2260
2229
|
if (customLinks != null) for (const link of customLinks) links.push(link);
|
|
2261
2230
|
}
|
|
2262
2231
|
const aliases = [];
|
|
2263
2232
|
if (resourceUrl.protocol != "acct:" && actor.preferredUsername != null) {
|
|
2264
|
-
aliases.push(`acct:${actor.preferredUsername}@${host ?? context
|
|
2265
|
-
if (host != null && host !== context
|
|
2233
|
+
aliases.push(`acct:${actor.preferredUsername}@${host ?? context.url.host}`);
|
|
2234
|
+
if (host != null && host !== context.url.host) aliases.push(`acct:${actor.preferredUsername}@${context.url.host}`);
|
|
2266
2235
|
}
|
|
2267
|
-
if (resourceUrl.href !== context
|
|
2268
|
-
if (resourceUrl.protocol === "acct:" && host != null && host !== context
|
|
2236
|
+
if (resourceUrl.href !== context.getActorUri(identifier).href) aliases.push(context.getActorUri(identifier).href);
|
|
2237
|
+
if (resourceUrl.protocol === "acct:" && host != null && host !== context.url.host && !resourceUrl.href.endsWith(`@${host}`)) {
|
|
2269
2238
|
const username = resourceUrl.href.replace(/^acct:/, "").replace(/@.*$/, "");
|
|
2270
2239
|
aliases.push(`acct:${username}@${host}`);
|
|
2271
2240
|
}
|
|
@@ -2279,9 +2248,15 @@ async function handleWebFingerInternal(request, { context: context$1, host, acto
|
|
|
2279
2248
|
"Access-Control-Allow-Origin": "*"
|
|
2280
2249
|
} });
|
|
2281
2250
|
}
|
|
2282
|
-
|
|
2283
2251
|
//#endregion
|
|
2284
2252
|
//#region src/federation/middleware.ts
|
|
2253
|
+
var middleware_exports = /* @__PURE__ */ __exportAll({
|
|
2254
|
+
ContextImpl: () => ContextImpl,
|
|
2255
|
+
FederationImpl: () => FederationImpl,
|
|
2256
|
+
InboxContextImpl: () => InboxContextImpl,
|
|
2257
|
+
KvSpecDeterminer: () => KvSpecDeterminer,
|
|
2258
|
+
createFederation: () => createFederation
|
|
2259
|
+
});
|
|
2285
2260
|
/**
|
|
2286
2261
|
* Create a new {@link Federation} instance.
|
|
2287
2262
|
* @param parameters Parameters for initializing the instance.
|
|
@@ -2407,28 +2382,28 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2407
2382
|
this.router.add("/.well-known/nodeinfo", "nodeInfoJrd");
|
|
2408
2383
|
}
|
|
2409
2384
|
_getTracer() {
|
|
2410
|
-
return this.tracerProvider.getTracer(
|
|
2385
|
+
return this.tracerProvider.getTracer(name, version);
|
|
2411
2386
|
}
|
|
2412
2387
|
async _startQueueInternal(ctxData, signal, queue) {
|
|
2413
2388
|
if (this.inboxQueue == null && this.outboxQueue == null) return;
|
|
2414
|
-
const logger
|
|
2389
|
+
const logger = getLogger([
|
|
2415
2390
|
"fedify",
|
|
2416
2391
|
"federation",
|
|
2417
2392
|
"queue"
|
|
2418
2393
|
]);
|
|
2419
2394
|
const promises = [];
|
|
2420
2395
|
if (this.inboxQueue != null && (queue == null || queue === "inbox") && !this.inboxQueueStarted) {
|
|
2421
|
-
logger
|
|
2396
|
+
logger.debug("Starting an inbox task worker.");
|
|
2422
2397
|
this.inboxQueueStarted = true;
|
|
2423
2398
|
promises.push(this.inboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
|
|
2424
2399
|
}
|
|
2425
2400
|
if (this.outboxQueue != null && this.outboxQueue !== this.inboxQueue && (queue == null || queue === "outbox") && !this.outboxQueueStarted) {
|
|
2426
|
-
logger
|
|
2401
|
+
logger.debug("Starting an outbox task worker.");
|
|
2427
2402
|
this.outboxQueueStarted = true;
|
|
2428
2403
|
promises.push(this.outboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
|
|
2429
2404
|
}
|
|
2430
2405
|
if (this.fanoutQueue != null && this.fanoutQueue !== this.inboxQueue && this.fanoutQueue !== this.outboxQueue && (queue == null || queue === "fanout") && !this.fanoutQueueStarted) {
|
|
2431
|
-
logger
|
|
2406
|
+
logger.debug("Starting a fanout task worker.");
|
|
2432
2407
|
this.fanoutQueueStarted = true;
|
|
2433
2408
|
promises.push(this.fanoutQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
|
|
2434
2409
|
}
|
|
@@ -2512,12 +2487,11 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2512
2487
|
});
|
|
2513
2488
|
}
|
|
2514
2489
|
async #listenFanoutMessage(data, message) {
|
|
2515
|
-
|
|
2490
|
+
getLogger([
|
|
2516
2491
|
"fedify",
|
|
2517
2492
|
"federation",
|
|
2518
2493
|
"fanout"
|
|
2519
|
-
])
|
|
2520
|
-
logger$1.debug("Fanning out activity {activityId} to {inboxes} inbox(es)...", {
|
|
2494
|
+
]).debug("Fanning out activity {activityId} to {inboxes} inbox(es)...", {
|
|
2521
2495
|
activityId: message.activityId,
|
|
2522
2496
|
inboxes: globalThis.Object.keys(message.inboxes).length
|
|
2523
2497
|
});
|
|
@@ -2536,18 +2510,18 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2536
2510
|
}),
|
|
2537
2511
|
tracerProvider: this.tracerProvider
|
|
2538
2512
|
});
|
|
2539
|
-
const context
|
|
2513
|
+
const context = this.#createContext(new URL(message.baseUrl), data, { documentLoader: this.documentLoaderFactory({
|
|
2540
2514
|
allowPrivateAddress: this.allowPrivateAddress,
|
|
2541
2515
|
userAgent: this.userAgent
|
|
2542
2516
|
}) });
|
|
2543
2517
|
await this.sendActivity(keys, message.inboxes, activity, {
|
|
2544
2518
|
collectionSync: message.collectionSync,
|
|
2545
2519
|
orderingKey: message.orderingKey,
|
|
2546
|
-
context
|
|
2520
|
+
context
|
|
2547
2521
|
});
|
|
2548
2522
|
}
|
|
2549
2523
|
async #listenOutboxMessage(_, message, span) {
|
|
2550
|
-
const logger
|
|
2524
|
+
const logger = getLogger([
|
|
2551
2525
|
"fedify",
|
|
2552
2526
|
"federation",
|
|
2553
2527
|
"outbox"
|
|
@@ -2595,14 +2569,14 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2595
2569
|
});
|
|
2596
2570
|
try {
|
|
2597
2571
|
await this.onOutboxError?.(error, activity);
|
|
2598
|
-
} catch (error
|
|
2599
|
-
logger
|
|
2572
|
+
} catch (error) {
|
|
2573
|
+
logger.error("An unexpected error occurred in onError handler:\n{error}", {
|
|
2600
2574
|
...logData,
|
|
2601
|
-
error
|
|
2575
|
+
error
|
|
2602
2576
|
});
|
|
2603
2577
|
}
|
|
2604
2578
|
if (error instanceof SendActivityError && this.permanentFailureStatusCodes.includes(error.statusCode)) {
|
|
2605
|
-
logger
|
|
2579
|
+
logger.warn("Permanent delivery failure for activity {activityId} to {inbox} ({status}); not retrying.", {
|
|
2606
2580
|
...logData,
|
|
2607
2581
|
status: error.statusCode
|
|
2608
2582
|
});
|
|
@@ -2618,13 +2592,13 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2618
2592
|
try {
|
|
2619
2593
|
return [new URL(id)];
|
|
2620
2594
|
} catch {
|
|
2621
|
-
logger
|
|
2595
|
+
logger.warn("Invalid actorId URL in OutboxMessage: {id}", { id });
|
|
2622
2596
|
return [];
|
|
2623
2597
|
}
|
|
2624
2598
|
})
|
|
2625
2599
|
});
|
|
2626
2600
|
} catch (handlerError) {
|
|
2627
|
-
logger
|
|
2601
|
+
logger.error("An unexpected error occurred in outboxPermanentFailureHandler:\n{error}", {
|
|
2628
2602
|
...logData,
|
|
2629
2603
|
error: handlerError
|
|
2630
2604
|
});
|
|
@@ -2633,7 +2607,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2633
2607
|
return;
|
|
2634
2608
|
}
|
|
2635
2609
|
if (this.outboxQueue?.nativeRetrial) {
|
|
2636
|
-
logger
|
|
2610
|
+
logger.error("Failed to send activity {activityId} to {inbox}; backend will handle retry:\n{error}", {
|
|
2637
2611
|
...logData,
|
|
2638
2612
|
error
|
|
2639
2613
|
});
|
|
@@ -2644,7 +2618,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2644
2618
|
attempts: message.attempt
|
|
2645
2619
|
});
|
|
2646
2620
|
if (delay != null) {
|
|
2647
|
-
logger
|
|
2621
|
+
logger.error("Failed to send activity {activityId} to {inbox} (attempt #{attempt}); retry...:\n{error}", {
|
|
2648
2622
|
...logData,
|
|
2649
2623
|
error
|
|
2650
2624
|
});
|
|
@@ -2652,39 +2626,38 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2652
2626
|
...message,
|
|
2653
2627
|
attempt: message.attempt + 1
|
|
2654
2628
|
}, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
|
|
2655
|
-
} else logger
|
|
2629
|
+
} else logger.error("Failed to send activity {activityId} to {inbox} after {attempt} attempts; giving up:\n{error}", {
|
|
2656
2630
|
...logData,
|
|
2657
2631
|
error
|
|
2658
2632
|
});
|
|
2659
2633
|
return;
|
|
2660
2634
|
}
|
|
2661
|
-
logger
|
|
2635
|
+
logger.info("Successfully sent activity {activityId} to {inbox}.", { ...logData });
|
|
2662
2636
|
}
|
|
2663
2637
|
async #listenInboxMessage(ctxData, message, span) {
|
|
2664
|
-
const logger
|
|
2638
|
+
const logger = getLogger([
|
|
2665
2639
|
"fedify",
|
|
2666
2640
|
"federation",
|
|
2667
2641
|
"inbox"
|
|
2668
2642
|
]);
|
|
2669
2643
|
const baseUrl = new URL(message.baseUrl);
|
|
2670
|
-
let context
|
|
2671
|
-
if (message.identifier != null) context
|
|
2644
|
+
let context = this.#createContext(baseUrl, ctxData);
|
|
2645
|
+
if (message.identifier != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: await context.getDocumentLoader({ identifier: message.identifier }) });
|
|
2672
2646
|
else if (this.sharedInboxKeyDispatcher != null) {
|
|
2673
|
-
const identity = await this.sharedInboxKeyDispatcher(context
|
|
2674
|
-
if (identity != null) context
|
|
2647
|
+
const identity = await this.sharedInboxKeyDispatcher(context);
|
|
2648
|
+
if (identity != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
2675
2649
|
}
|
|
2676
|
-
const activity = await Activity.fromJsonLd(message.activity, context
|
|
2650
|
+
const activity = await Activity.fromJsonLd(message.activity, context);
|
|
2677
2651
|
span.setAttribute("activitypub.activity.type", getTypeId(activity).href);
|
|
2678
2652
|
if (activity.id != null) span.setAttribute("activitypub.activity.id", activity.id.href);
|
|
2679
2653
|
const cacheKey = activity.id == null ? null : [
|
|
2680
2654
|
...this.kvPrefixes.activityIdempotence,
|
|
2681
|
-
context
|
|
2655
|
+
context.origin,
|
|
2682
2656
|
activity.id.href
|
|
2683
2657
|
];
|
|
2684
2658
|
if (cacheKey != null) {
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
logger$1.debug("Activity {activityId} has already been processed.", {
|
|
2659
|
+
if (await this.kv.get(cacheKey) === true) {
|
|
2660
|
+
logger.debug("Activity {activityId} has already been processed.", {
|
|
2688
2661
|
activityId: activity.id?.href,
|
|
2689
2662
|
activity: message.activity,
|
|
2690
2663
|
recipient: message.identifier
|
|
@@ -2692,32 +2665,32 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2692
2665
|
return;
|
|
2693
2666
|
}
|
|
2694
2667
|
}
|
|
2695
|
-
await this._getTracer().startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span
|
|
2668
|
+
await this._getTracer().startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span) => {
|
|
2696
2669
|
const dispatched = this.inboxListeners?.dispatchWithClass(activity);
|
|
2697
2670
|
if (dispatched == null) {
|
|
2698
|
-
logger
|
|
2671
|
+
logger.error("Unsupported activity type:\n{activity}", {
|
|
2699
2672
|
activityId: activity.id?.href,
|
|
2700
2673
|
activity: message.activity,
|
|
2701
2674
|
recipient: message.identifier,
|
|
2702
2675
|
trial: message.attempt
|
|
2703
2676
|
});
|
|
2704
|
-
span
|
|
2677
|
+
span.setStatus({
|
|
2705
2678
|
code: SpanStatusCode.ERROR,
|
|
2706
2679
|
message: `Unsupported activity type: ${getTypeId(activity).href}`
|
|
2707
2680
|
});
|
|
2708
|
-
span
|
|
2681
|
+
span.end();
|
|
2709
2682
|
return;
|
|
2710
2683
|
}
|
|
2711
2684
|
const { class: cls, listener } = dispatched;
|
|
2712
|
-
span
|
|
2685
|
+
span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
|
|
2713
2686
|
try {
|
|
2714
|
-
await listener(context
|
|
2687
|
+
await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, getTypeId(activity).href), activity);
|
|
2715
2688
|
} catch (error) {
|
|
2716
2689
|
try {
|
|
2717
|
-
await this.inboxErrorHandler?.(context
|
|
2718
|
-
} catch (error
|
|
2719
|
-
logger
|
|
2720
|
-
error
|
|
2690
|
+
await this.inboxErrorHandler?.(context, error);
|
|
2691
|
+
} catch (error) {
|
|
2692
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
2693
|
+
error,
|
|
2721
2694
|
trial: message.attempt,
|
|
2722
2695
|
activityId: activity.id?.href,
|
|
2723
2696
|
activity: message.activity,
|
|
@@ -2725,17 +2698,17 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2725
2698
|
});
|
|
2726
2699
|
}
|
|
2727
2700
|
if (this.inboxQueue?.nativeRetrial) {
|
|
2728
|
-
logger
|
|
2701
|
+
logger.error("Failed to process the incoming activity {activityId}; backend will handle retry:\n{error}", {
|
|
2729
2702
|
error,
|
|
2730
2703
|
activityId: activity.id?.href,
|
|
2731
2704
|
activity: message.activity,
|
|
2732
2705
|
recipient: message.identifier
|
|
2733
2706
|
});
|
|
2734
|
-
span
|
|
2707
|
+
span.setStatus({
|
|
2735
2708
|
code: SpanStatusCode.ERROR,
|
|
2736
2709
|
message: String(error)
|
|
2737
2710
|
});
|
|
2738
|
-
span
|
|
2711
|
+
span.end();
|
|
2739
2712
|
throw error;
|
|
2740
2713
|
}
|
|
2741
2714
|
const delay = this.inboxRetryPolicy({
|
|
@@ -2743,7 +2716,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2743
2716
|
attempts: message.attempt
|
|
2744
2717
|
});
|
|
2745
2718
|
if (delay != null) {
|
|
2746
|
-
logger
|
|
2719
|
+
logger.error("Failed to process the incoming activity {activityId} (attempt #{attempt}); retry...:\n{error}", {
|
|
2747
2720
|
error,
|
|
2748
2721
|
attempt: message.attempt,
|
|
2749
2722
|
activityId: activity.id?.href,
|
|
@@ -2754,26 +2727,26 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2754
2727
|
...message,
|
|
2755
2728
|
attempt: message.attempt + 1
|
|
2756
2729
|
}, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
|
|
2757
|
-
} else logger
|
|
2730
|
+
} else logger.error("Failed to process the incoming activity {activityId} after {trial} attempts; giving up:\n{error}", {
|
|
2758
2731
|
error,
|
|
2759
2732
|
activityId: activity.id?.href,
|
|
2760
2733
|
activity: message.activity,
|
|
2761
2734
|
recipient: message.identifier
|
|
2762
2735
|
});
|
|
2763
|
-
span
|
|
2736
|
+
span.setStatus({
|
|
2764
2737
|
code: SpanStatusCode.ERROR,
|
|
2765
2738
|
message: String(error)
|
|
2766
2739
|
});
|
|
2767
|
-
span
|
|
2740
|
+
span.end();
|
|
2768
2741
|
return;
|
|
2769
2742
|
}
|
|
2770
2743
|
if (cacheKey != null) await this.kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
|
|
2771
|
-
logger
|
|
2744
|
+
logger.info("Activity {activityId} has been processed.", {
|
|
2772
2745
|
activityId: activity.id?.href,
|
|
2773
2746
|
activity: message.activity,
|
|
2774
2747
|
recipient: message.identifier
|
|
2775
2748
|
});
|
|
2776
|
-
span
|
|
2749
|
+
span.end();
|
|
2777
2750
|
});
|
|
2778
2751
|
}
|
|
2779
2752
|
startQueue(contextData, options = {}) {
|
|
@@ -2817,7 +2790,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2817
2790
|
};
|
|
2818
2791
|
}
|
|
2819
2792
|
async sendActivity(keys, inboxes, activity, options) {
|
|
2820
|
-
const logger
|
|
2793
|
+
const logger = getLogger([
|
|
2821
2794
|
"fedify",
|
|
2822
2795
|
"federation",
|
|
2823
2796
|
"outbox"
|
|
@@ -2851,7 +2824,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2851
2824
|
format: "compact",
|
|
2852
2825
|
contextLoader
|
|
2853
2826
|
});
|
|
2854
|
-
if (rsaKey == null) logger
|
|
2827
|
+
if (rsaKey == null) logger.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.", {
|
|
2855
2828
|
activityId,
|
|
2856
2829
|
keys: keys.map((pair) => ({
|
|
2857
2830
|
keyId: pair.keyId.href,
|
|
@@ -2862,7 +2835,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2862
2835
|
contextLoader,
|
|
2863
2836
|
tracerProvider: this.tracerProvider
|
|
2864
2837
|
});
|
|
2865
|
-
if (!proofCreated) logger
|
|
2838
|
+
if (!proofCreated) logger.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.", {
|
|
2866
2839
|
activityId,
|
|
2867
2840
|
keys: keys.map((pair) => ({
|
|
2868
2841
|
keyId: pair.keyId.href,
|
|
@@ -2870,11 +2843,11 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2870
2843
|
}))
|
|
2871
2844
|
});
|
|
2872
2845
|
if (immediate || this.outboxQueue == null) {
|
|
2873
|
-
if (immediate) logger
|
|
2846
|
+
if (immediate) logger.debug("Sending activity immediately without queue since immediate option is set.", {
|
|
2874
2847
|
activityId: activity.id.href,
|
|
2875
2848
|
activity: jsonLd
|
|
2876
2849
|
});
|
|
2877
|
-
else logger
|
|
2850
|
+
else logger.debug("Sending activity immediately without queue since queue is not set.", {
|
|
2878
2851
|
activityId: activity.id.href,
|
|
2879
2852
|
activity: jsonLd
|
|
2880
2853
|
});
|
|
@@ -2893,7 +2866,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2893
2866
|
await Promise.all(promises);
|
|
2894
2867
|
return;
|
|
2895
2868
|
}
|
|
2896
|
-
logger
|
|
2869
|
+
logger.debug("Enqueuing activity {activityId} to send later.", {
|
|
2897
2870
|
activityId: activity.id.href,
|
|
2898
2871
|
activity: jsonLd
|
|
2899
2872
|
});
|
|
@@ -2937,10 +2910,9 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2937
2910
|
const { outboxQueue } = this;
|
|
2938
2911
|
if (outboxQueue.enqueueMany == null) {
|
|
2939
2912
|
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
2940
|
-
const
|
|
2941
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2913
|
+
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2942
2914
|
if (errors.length > 0) {
|
|
2943
|
-
logger
|
|
2915
|
+
logger.error("Failed to enqueue activity {activityId} to send later: {errors}", {
|
|
2944
2916
|
activityId: activity.id.href,
|
|
2945
2917
|
errors
|
|
2946
2918
|
});
|
|
@@ -2949,10 +2921,9 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2949
2921
|
}
|
|
2950
2922
|
} else if (orderingKey != null) {
|
|
2951
2923
|
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
2952
|
-
const
|
|
2953
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2924
|
+
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2954
2925
|
if (errors.length > 0) {
|
|
2955
|
-
logger
|
|
2926
|
+
logger.error("Failed to enqueue activity {activityId} to send later: {errors}", {
|
|
2956
2927
|
activityId: activity.id.href,
|
|
2957
2928
|
errors
|
|
2958
2929
|
});
|
|
@@ -2962,7 +2933,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2962
2933
|
} else try {
|
|
2963
2934
|
await outboxQueue.enqueueMany(messages.map((m) => m.message));
|
|
2964
2935
|
} catch (error) {
|
|
2965
|
-
logger
|
|
2936
|
+
logger.error("Failed to enqueue activity {activityId} to send later: {error}", {
|
|
2966
2937
|
activityId: activity.id.href,
|
|
2967
2938
|
error
|
|
2968
2939
|
});
|
|
@@ -2970,8 +2941,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2970
2941
|
}
|
|
2971
2942
|
}
|
|
2972
2943
|
fetch(request, options) {
|
|
2973
|
-
|
|
2974
|
-
return withContext({ requestId }, async () => {
|
|
2944
|
+
return withContext({ requestId: getRequestId(request) }, async () => {
|
|
2975
2945
|
const tracer = this._getTracer();
|
|
2976
2946
|
return await tracer.startActiveSpan(request.method, {
|
|
2977
2947
|
kind: SpanKind.SERVER,
|
|
@@ -2985,7 +2955,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2985
2955
|
traceId: spanCtx.traceId,
|
|
2986
2956
|
spanId: spanCtx.spanId
|
|
2987
2957
|
}, async () => {
|
|
2988
|
-
const logger
|
|
2958
|
+
const logger = getLogger([
|
|
2989
2959
|
"fedify",
|
|
2990
2960
|
"federation",
|
|
2991
2961
|
"http"
|
|
@@ -3005,7 +2975,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3005
2975
|
message: `${error}`
|
|
3006
2976
|
});
|
|
3007
2977
|
span.end();
|
|
3008
|
-
logger
|
|
2978
|
+
logger.error("An error occurred while serving request {method} {url}: {error}", {
|
|
3009
2979
|
method: request.method,
|
|
3010
2980
|
url: request.url,
|
|
3011
2981
|
error
|
|
@@ -3029,9 +2999,9 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3029
2999
|
url: request.url,
|
|
3030
3000
|
status: response.status
|
|
3031
3001
|
};
|
|
3032
|
-
if (response.status >= 500) logger
|
|
3033
|
-
else if (response.status >= 400) logger
|
|
3034
|
-
else logger
|
|
3002
|
+
if (response.status >= 500) logger.error(logTpl, values);
|
|
3003
|
+
else if (response.status >= 400) logger.warn(logTpl, values);
|
|
3004
|
+
else logger.info(logTpl, values);
|
|
3035
3005
|
return response;
|
|
3036
3006
|
});
|
|
3037
3007
|
});
|
|
@@ -3045,11 +3015,11 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3045
3015
|
const route = this.router.route(url.pathname);
|
|
3046
3016
|
if (route == null) return await onNotFound(request);
|
|
3047
3017
|
span.updateName(`${request.method} ${route.template}`);
|
|
3048
|
-
let context
|
|
3018
|
+
let context = this.#createContext(request, contextData);
|
|
3049
3019
|
const routeName = route.name.replace(/:.*$/, "");
|
|
3050
3020
|
switch (routeName) {
|
|
3051
3021
|
case "webfinger": return await handleWebFinger(request, {
|
|
3052
|
-
context
|
|
3022
|
+
context,
|
|
3053
3023
|
host: this.origin?.handleHost,
|
|
3054
3024
|
actorDispatcher: this.actorCallbacks?.dispatcher,
|
|
3055
3025
|
actorHandleMapper: this.actorCallbacks?.handleMapper,
|
|
@@ -3058,19 +3028,19 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3058
3028
|
onNotFound,
|
|
3059
3029
|
tracer
|
|
3060
3030
|
});
|
|
3061
|
-
case "nodeInfoJrd": return await handleNodeInfoJrd(request, context
|
|
3031
|
+
case "nodeInfoJrd": return await handleNodeInfoJrd(request, context);
|
|
3062
3032
|
case "nodeInfo": return await handleNodeInfo(request, {
|
|
3063
|
-
context
|
|
3033
|
+
context,
|
|
3064
3034
|
nodeInfoDispatcher: this.nodeInfoDispatcher
|
|
3065
3035
|
});
|
|
3066
3036
|
}
|
|
3067
3037
|
if (request.method !== "POST" && !acceptsJsonLd(request)) return await onNotAcceptable(request);
|
|
3068
3038
|
switch (routeName) {
|
|
3069
3039
|
case "actor":
|
|
3070
|
-
context
|
|
3040
|
+
context = this.#createContext(request, contextData, { invokedFromActorDispatcher: { identifier: route.values.identifier } });
|
|
3071
3041
|
return await handleActor(request, {
|
|
3072
3042
|
identifier: route.values.identifier,
|
|
3073
|
-
context
|
|
3043
|
+
context,
|
|
3074
3044
|
actorDispatcher: this.actorCallbacks?.dispatcher,
|
|
3075
3045
|
authorizePredicate: this.actorCallbacks?.authorizePredicate,
|
|
3076
3046
|
onUnauthorized,
|
|
@@ -3080,13 +3050,13 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3080
3050
|
const typeId = route.name.replace(/^object:/, "");
|
|
3081
3051
|
const callbacks = this.objectCallbacks[typeId];
|
|
3082
3052
|
const cls = this.objectTypeIds[typeId];
|
|
3083
|
-
context
|
|
3053
|
+
context = this.#createContext(request, contextData, { invokedFromObjectDispatcher: {
|
|
3084
3054
|
cls,
|
|
3085
3055
|
values: route.values
|
|
3086
3056
|
} });
|
|
3087
3057
|
return await handleObject(request, {
|
|
3088
3058
|
values: route.values,
|
|
3089
|
-
context
|
|
3059
|
+
context,
|
|
3090
3060
|
objectDispatcher: callbacks?.dispatcher,
|
|
3091
3061
|
authorizePredicate: callbacks?.authorizePredicate,
|
|
3092
3062
|
onUnauthorized,
|
|
@@ -3096,8 +3066,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3096
3066
|
case "outbox": return await handleCollection(request, {
|
|
3097
3067
|
name: "outbox",
|
|
3098
3068
|
identifier: route.values.identifier,
|
|
3099
|
-
uriGetter: context
|
|
3100
|
-
context
|
|
3069
|
+
uriGetter: context.getOutboxUri.bind(context),
|
|
3070
|
+
context,
|
|
3101
3071
|
collectionCallbacks: this.outboxCallbacks,
|
|
3102
3072
|
tracerProvider: this.tracerProvider,
|
|
3103
3073
|
onUnauthorized,
|
|
@@ -3107,24 +3077,24 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3107
3077
|
if (request.method !== "POST") return await handleCollection(request, {
|
|
3108
3078
|
name: "inbox",
|
|
3109
3079
|
identifier: route.values.identifier,
|
|
3110
|
-
uriGetter: context
|
|
3111
|
-
context
|
|
3080
|
+
uriGetter: context.getInboxUri.bind(context),
|
|
3081
|
+
context,
|
|
3112
3082
|
collectionCallbacks: this.inboxCallbacks,
|
|
3113
3083
|
tracerProvider: this.tracerProvider,
|
|
3114
3084
|
onUnauthorized,
|
|
3115
3085
|
onNotFound
|
|
3116
3086
|
});
|
|
3117
|
-
context
|
|
3087
|
+
context = this.#createContext(request, contextData, { documentLoader: await context.getDocumentLoader({ identifier: route.values.identifier }) });
|
|
3118
3088
|
case "sharedInbox":
|
|
3119
3089
|
if (routeName !== "inbox" && this.sharedInboxKeyDispatcher != null) {
|
|
3120
|
-
const identity = await this.sharedInboxKeyDispatcher(context
|
|
3121
|
-
if (identity != null) context
|
|
3090
|
+
const identity = await this.sharedInboxKeyDispatcher(context);
|
|
3091
|
+
if (identity != null) context = this.#createContext(request, contextData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
3122
3092
|
}
|
|
3123
3093
|
if (!this.manuallyStartQueue) this._startQueueInternal(contextData);
|
|
3124
3094
|
return await handleInbox(request, {
|
|
3125
3095
|
recipient: route.values.identifier ?? null,
|
|
3126
|
-
context
|
|
3127
|
-
inboxContextFactory: context
|
|
3096
|
+
context,
|
|
3097
|
+
inboxContextFactory: context.toInboxContext.bind(context),
|
|
3128
3098
|
kv: this.kv,
|
|
3129
3099
|
kvPrefixes: this.kvPrefixes,
|
|
3130
3100
|
queue: this.inboxQueue,
|
|
@@ -3140,8 +3110,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3140
3110
|
case "following": return await handleCollection(request, {
|
|
3141
3111
|
name: "following",
|
|
3142
3112
|
identifier: route.values.identifier,
|
|
3143
|
-
uriGetter: context
|
|
3144
|
-
context
|
|
3113
|
+
uriGetter: context.getFollowingUri.bind(context),
|
|
3114
|
+
context,
|
|
3145
3115
|
collectionCallbacks: this.followingCallbacks,
|
|
3146
3116
|
tracerProvider: this.tracerProvider,
|
|
3147
3117
|
onUnauthorized,
|
|
@@ -3157,14 +3127,14 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3157
3127
|
return await handleCollection(request, {
|
|
3158
3128
|
name: "followers",
|
|
3159
3129
|
identifier: route.values.identifier,
|
|
3160
|
-
uriGetter: baseUrl == null ? context
|
|
3161
|
-
const uri = context
|
|
3130
|
+
uriGetter: baseUrl == null ? context.getFollowersUri.bind(context) : (identifier) => {
|
|
3131
|
+
const uri = context.getFollowersUri(identifier);
|
|
3162
3132
|
uri.searchParams.set("base-url", baseUrl);
|
|
3163
3133
|
return uri;
|
|
3164
3134
|
},
|
|
3165
|
-
context
|
|
3135
|
+
context,
|
|
3166
3136
|
filter: baseUrl != null ? new URL(baseUrl) : void 0,
|
|
3167
|
-
filterPredicate: baseUrl != null ? (i) => (i instanceof URL ? i.href : i.id?.href ?? "").startsWith(baseUrl) : void 0,
|
|
3137
|
+
filterPredicate: baseUrl != null ? ((i) => (i instanceof URL ? i.href : i.id?.href ?? "").startsWith(baseUrl)) : void 0,
|
|
3168
3138
|
collectionCallbacks: this.followersCallbacks,
|
|
3169
3139
|
tracerProvider: this.tracerProvider,
|
|
3170
3140
|
onUnauthorized,
|
|
@@ -3174,8 +3144,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3174
3144
|
case "liked": return await handleCollection(request, {
|
|
3175
3145
|
name: "liked",
|
|
3176
3146
|
identifier: route.values.identifier,
|
|
3177
|
-
uriGetter: context
|
|
3178
|
-
context
|
|
3147
|
+
uriGetter: context.getLikedUri.bind(context),
|
|
3148
|
+
context,
|
|
3179
3149
|
collectionCallbacks: this.likedCallbacks,
|
|
3180
3150
|
tracerProvider: this.tracerProvider,
|
|
3181
3151
|
onUnauthorized,
|
|
@@ -3184,8 +3154,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3184
3154
|
case "featured": return await handleCollection(request, {
|
|
3185
3155
|
name: "featured",
|
|
3186
3156
|
identifier: route.values.identifier,
|
|
3187
|
-
uriGetter: context
|
|
3188
|
-
context
|
|
3157
|
+
uriGetter: context.getFeaturedUri.bind(context),
|
|
3158
|
+
context,
|
|
3189
3159
|
collectionCallbacks: this.featuredCallbacks,
|
|
3190
3160
|
tracerProvider: this.tracerProvider,
|
|
3191
3161
|
onUnauthorized,
|
|
@@ -3194,8 +3164,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3194
3164
|
case "featuredTags": return await handleCollection(request, {
|
|
3195
3165
|
name: "featured tags",
|
|
3196
3166
|
identifier: route.values.identifier,
|
|
3197
|
-
uriGetter: context
|
|
3198
|
-
context
|
|
3167
|
+
uriGetter: context.getFeaturedTagsUri.bind(context),
|
|
3168
|
+
context,
|
|
3199
3169
|
collectionCallbacks: this.featuredTagsCallbacks,
|
|
3200
3170
|
tracerProvider: this.tracerProvider,
|
|
3201
3171
|
onUnauthorized,
|
|
@@ -3206,7 +3176,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3206
3176
|
const callbacks = this.collectionCallbacks[name];
|
|
3207
3177
|
return await handleCustomCollection(request, {
|
|
3208
3178
|
name,
|
|
3209
|
-
context
|
|
3179
|
+
context,
|
|
3210
3180
|
values: route.values,
|
|
3211
3181
|
collectionCallbacks: callbacks,
|
|
3212
3182
|
tracerProvider: this.tracerProvider,
|
|
@@ -3219,7 +3189,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3219
3189
|
const callbacks = this.collectionCallbacks[name];
|
|
3220
3190
|
return await handleOrderedCollection(request, {
|
|
3221
3191
|
name,
|
|
3222
|
-
context
|
|
3192
|
+
context,
|
|
3223
3193
|
values: route.values,
|
|
3224
3194
|
collectionCallbacks: callbacks,
|
|
3225
3195
|
tracerProvider: this.tracerProvider,
|
|
@@ -3310,9 +3280,9 @@ var ContextImpl = class ContextImpl {
|
|
|
3310
3280
|
}
|
|
3311
3281
|
getInboxUri(identifier) {
|
|
3312
3282
|
if (identifier == null) {
|
|
3313
|
-
const path
|
|
3314
|
-
if (path
|
|
3315
|
-
return new URL(path
|
|
3283
|
+
const path = this.federation.router.build("sharedInbox", {});
|
|
3284
|
+
if (path == null) throw new RouterError("No shared inbox path registered.");
|
|
3285
|
+
return new URL(path, this.canonicalOrigin);
|
|
3316
3286
|
}
|
|
3317
3287
|
const path = this.federation.router.build("inbox", { identifier });
|
|
3318
3288
|
if (path == null) throw new RouterError("No inbox path registered.");
|
|
@@ -3398,8 +3368,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3398
3368
|
type: "featuredTags",
|
|
3399
3369
|
identifier
|
|
3400
3370
|
};
|
|
3401
|
-
const
|
|
3402
|
-
const collectionRegex = /* @__PURE__ */ new RegExp(`^(${collectionTypes.join("|")}):(.*)$`);
|
|
3371
|
+
const collectionRegex = new RegExp(`^(${["collection", "orderedCollection"].join("|")}):(.*)$`);
|
|
3403
3372
|
const match = route.name.match(collectionRegex);
|
|
3404
3373
|
if (match !== null) {
|
|
3405
3374
|
const [, type, name] = match;
|
|
@@ -3415,12 +3384,12 @@ var ContextImpl = class ContextImpl {
|
|
|
3415
3384
|
return null;
|
|
3416
3385
|
}
|
|
3417
3386
|
async getActorKeyPairs(identifier) {
|
|
3418
|
-
const logger
|
|
3387
|
+
const logger = getLogger([
|
|
3419
3388
|
"fedify",
|
|
3420
3389
|
"federation",
|
|
3421
3390
|
"actor"
|
|
3422
3391
|
]);
|
|
3423
|
-
if (this.invokedFromActorKeyPairsDispatcher != null) logger
|
|
3392
|
+
if (this.invokedFromActorKeyPairsDispatcher != null) logger.warn("Context.getActorKeyPairs({getActorKeyPairsIdentifier}) method is invoked from the actor key pairs dispatcher ({actorKeyPairsDispatcherIdentifier}); this may cause an infinite loop.", {
|
|
3424
3393
|
getActorKeyPairsIdentifier: identifier,
|
|
3425
3394
|
actorKeyPairsDispatcherIdentifier: this.invokedFromActorKeyPairsDispatcher.identifier
|
|
3426
3395
|
});
|
|
@@ -3428,7 +3397,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3428
3397
|
try {
|
|
3429
3398
|
keyPairs = await this.getKeyPairsFromIdentifier(identifier);
|
|
3430
3399
|
} catch (_) {
|
|
3431
|
-
logger
|
|
3400
|
+
logger.warn("No actor key pairs dispatcher registered.");
|
|
3432
3401
|
return [];
|
|
3433
3402
|
}
|
|
3434
3403
|
const owner = this.getActorUri(identifier);
|
|
@@ -3452,7 +3421,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3452
3421
|
return result;
|
|
3453
3422
|
}
|
|
3454
3423
|
async getKeyPairsFromIdentifier(identifier) {
|
|
3455
|
-
const logger
|
|
3424
|
+
const logger = getLogger([
|
|
3456
3425
|
"fedify",
|
|
3457
3426
|
"federation",
|
|
3458
3427
|
"actor"
|
|
@@ -3463,7 +3432,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3463
3432
|
actorUri = this.getActorUri(identifier);
|
|
3464
3433
|
} catch (error) {
|
|
3465
3434
|
if (error instanceof RouterError) {
|
|
3466
|
-
logger
|
|
3435
|
+
logger.warn(error.message);
|
|
3467
3436
|
return [];
|
|
3468
3437
|
}
|
|
3469
3438
|
throw error;
|
|
@@ -3472,7 +3441,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3472
3441
|
...this,
|
|
3473
3442
|
invokedFromActorKeyPairsDispatcher: { identifier }
|
|
3474
3443
|
}), identifier);
|
|
3475
|
-
if (keyPairs.length < 1) logger
|
|
3444
|
+
if (keyPairs.length < 1) logger.warn("No key pairs found for actor {identifier}.", { identifier });
|
|
3476
3445
|
let i = 0;
|
|
3477
3446
|
const result = [];
|
|
3478
3447
|
for (const keyPair of keyPairs) {
|
|
@@ -3511,8 +3480,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3511
3480
|
} else identifierPromise = Promise.resolve(identity.identifier);
|
|
3512
3481
|
return identifierPromise.then((identifier) => {
|
|
3513
3482
|
if (identifier == null) return this.documentLoader;
|
|
3514
|
-
|
|
3515
|
-
return keyPair.then((pair) => pair == null ? this.documentLoader : this.federation.authenticatedDocumentLoaderFactory(pair));
|
|
3483
|
+
return this.getRsaKeyPairFromIdentifier(identifier).then((pair) => pair == null ? this.documentLoader : this.federation.authenticatedDocumentLoaderFactory(pair));
|
|
3516
3484
|
});
|
|
3517
3485
|
}
|
|
3518
3486
|
return this.federation.authenticatedDocumentLoaderFactory(identity);
|
|
@@ -3554,8 +3522,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3554
3522
|
});
|
|
3555
3523
|
}
|
|
3556
3524
|
sendActivity(sender, recipients, activity, options = {}) {
|
|
3557
|
-
|
|
3558
|
-
return tracer.startActiveSpan(this.federation.outboxQueue == null || options.immediate ? "activitypub.outbox" : "activitypub.fanout", {
|
|
3525
|
+
return this.tracerProvider.getTracer(name, version).startActiveSpan(this.federation.outboxQueue == null || options.immediate ? "activitypub.outbox" : "activitypub.fanout", {
|
|
3559
3526
|
kind: this.federation.outboxQueue == null || options.immediate ? SpanKind.CLIENT : SpanKind.PRODUCER,
|
|
3560
3527
|
attributes: {
|
|
3561
3528
|
"activitypub.activity.type": getTypeId(activity).href,
|
|
@@ -3580,7 +3547,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3580
3547
|
});
|
|
3581
3548
|
}
|
|
3582
3549
|
async sendActivityInternal(sender, recipients, activity, options, span) {
|
|
3583
|
-
const logger
|
|
3550
|
+
const logger = getLogger([
|
|
3584
3551
|
"fedify",
|
|
3585
3552
|
"federation",
|
|
3586
3553
|
"outbox"
|
|
@@ -3630,7 +3597,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3630
3597
|
for (const activityTransformer of this.federation.activityTransformers) activity = activityTransformer(activity, this);
|
|
3631
3598
|
span?.setAttribute("activitypub.activity.id", activity?.id?.href ?? "");
|
|
3632
3599
|
if (activity.actorId == null) {
|
|
3633
|
-
logger
|
|
3600
|
+
logger.error("Activity {activityId} to send does not have an actor.", {
|
|
3634
3601
|
activity,
|
|
3635
3602
|
activityId: activity?.id?.href
|
|
3636
3603
|
});
|
|
@@ -3641,7 +3608,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3641
3608
|
preferSharedInbox: options.preferSharedInbox,
|
|
3642
3609
|
excludeBaseUris: options.excludeBaseUris
|
|
3643
3610
|
});
|
|
3644
|
-
logger
|
|
3611
|
+
logger.debug("Sending activity {activityId} to inboxes:\n{inboxes}", {
|
|
3645
3612
|
inboxes: globalThis.Object.keys(inboxes),
|
|
3646
3613
|
activityId: activity.id?.href,
|
|
3647
3614
|
activity
|
|
@@ -3693,16 +3660,14 @@ var ContextImpl = class ContextImpl {
|
|
|
3693
3660
|
"outbox"
|
|
3694
3661
|
]).warn("Since the followers collection dispatcher returned null for no cursor (i.e., one-shot dispatcher), the pagination is used to fetch \"followers\". However, it is recommended to implement the one-shot dispatcher for better performance.", { identifier });
|
|
3695
3662
|
while (cursor != null) {
|
|
3696
|
-
const result
|
|
3697
|
-
if (result
|
|
3698
|
-
for (const recipient of result
|
|
3699
|
-
cursor = result
|
|
3663
|
+
const result = await this.federation.followersCallbacks.dispatcher(this, identifier, cursor);
|
|
3664
|
+
if (result == null) break;
|
|
3665
|
+
for (const recipient of result.items) yield recipient;
|
|
3666
|
+
cursor = result.nextCursor ?? null;
|
|
3700
3667
|
}
|
|
3701
3668
|
}
|
|
3702
3669
|
routeActivity(recipient, activity, options = {}) {
|
|
3703
|
-
|
|
3704
|
-
const tracer = tracerProvider.getTracer(deno_default.name, deno_default.version);
|
|
3705
|
-
return tracer.startActiveSpan("activitypub.inbox", {
|
|
3670
|
+
return (this.tracerProvider ?? this.tracerProvider).getTracer(name, version).startActiveSpan("activitypub.inbox", {
|
|
3706
3671
|
kind: this.federation.inboxQueue == null || options.immediate ? SpanKind.INTERNAL : SpanKind.PRODUCER,
|
|
3707
3672
|
attributes: { "activitypub.activity.type": getTypeId(activity).href }
|
|
3708
3673
|
}, async (span) => {
|
|
@@ -3730,7 +3695,7 @@ var ContextImpl = class ContextImpl {
|
|
|
3730
3695
|
});
|
|
3731
3696
|
}
|
|
3732
3697
|
async routeActivityInternal(recipient, activity, options = {}, span) {
|
|
3733
|
-
const logger
|
|
3698
|
+
const logger = getLogger([
|
|
3734
3699
|
"fedify",
|
|
3735
3700
|
"federation",
|
|
3736
3701
|
"inbox"
|
|
@@ -3738,19 +3703,18 @@ var ContextImpl = class ContextImpl {
|
|
|
3738
3703
|
const contextLoader = options.contextLoader ?? this.contextLoader;
|
|
3739
3704
|
const json = await activity.toJsonLd({ contextLoader });
|
|
3740
3705
|
const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, this);
|
|
3741
|
-
|
|
3706
|
+
if (await verifyObject(Activity, json, {
|
|
3742
3707
|
contextLoader,
|
|
3743
3708
|
documentLoader: options.documentLoader ?? this.documentLoader,
|
|
3744
3709
|
tracerProvider: options.tracerProvider ?? this.tracerProvider,
|
|
3745
3710
|
keyCache
|
|
3746
|
-
})
|
|
3747
|
-
|
|
3748
|
-
logger$1.debug("Object Integrity Proofs are not verified.", {
|
|
3711
|
+
}) == null) {
|
|
3712
|
+
logger.debug("Object Integrity Proofs are not verified.", {
|
|
3749
3713
|
recipient,
|
|
3750
3714
|
activity: json
|
|
3751
3715
|
});
|
|
3752
3716
|
if (activity.id == null) {
|
|
3753
|
-
logger
|
|
3717
|
+
logger.debug("Activity is missing an ID; unable to fetch.", {
|
|
3754
3718
|
recipient,
|
|
3755
3719
|
activity: json
|
|
3756
3720
|
});
|
|
@@ -3758,26 +3722,26 @@ var ContextImpl = class ContextImpl {
|
|
|
3758
3722
|
}
|
|
3759
3723
|
const fetched = await this.lookupObject(activity.id, options);
|
|
3760
3724
|
if (fetched == null) {
|
|
3761
|
-
logger
|
|
3725
|
+
logger.debug("Failed to fetch the remote activity object {activityId}.", {
|
|
3762
3726
|
recipient,
|
|
3763
3727
|
activity: json,
|
|
3764
3728
|
activityId: activity.id.href
|
|
3765
3729
|
});
|
|
3766
3730
|
return false;
|
|
3767
3731
|
} else if (!(fetched instanceof Activity)) {
|
|
3768
|
-
logger
|
|
3732
|
+
logger.debug("Fetched object is not an Activity.", {
|
|
3769
3733
|
recipient,
|
|
3770
3734
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
3771
3735
|
});
|
|
3772
3736
|
return false;
|
|
3773
3737
|
} else if (fetched.id?.href !== activity.id.href) {
|
|
3774
|
-
logger
|
|
3738
|
+
logger.debug("Fetched activity object has a different ID; failed to verify.", {
|
|
3775
3739
|
recipient,
|
|
3776
3740
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
3777
3741
|
});
|
|
3778
3742
|
return false;
|
|
3779
3743
|
} else if (fetched.actorIds.length < 1) {
|
|
3780
|
-
logger
|
|
3744
|
+
logger.debug("Fetched activity object is missing an actor; unable to verify.", {
|
|
3781
3745
|
recipient,
|
|
3782
3746
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
3783
3747
|
});
|
|
@@ -3785,15 +3749,15 @@ var ContextImpl = class ContextImpl {
|
|
|
3785
3749
|
}
|
|
3786
3750
|
const activityId = fetched.id;
|
|
3787
3751
|
if (!fetched.actorIds.every((actor) => actor.origin === activityId.origin)) {
|
|
3788
|
-
logger
|
|
3752
|
+
logger.debug("Fetched activity object has actors from different origins; unable to verify.", {
|
|
3789
3753
|
recipient,
|
|
3790
3754
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
3791
3755
|
});
|
|
3792
3756
|
return false;
|
|
3793
3757
|
}
|
|
3794
|
-
logger
|
|
3758
|
+
logger.debug("Successfully fetched the remote activity object {activityId}; ignore the original activity and use the fetched one, which is trustworthy.");
|
|
3795
3759
|
activity = fetched;
|
|
3796
|
-
} else logger
|
|
3760
|
+
} else logger.debug("Object Integrity Proofs are verified.", {
|
|
3797
3761
|
recipient,
|
|
3798
3762
|
activity: json
|
|
3799
3763
|
});
|
|
@@ -3919,8 +3883,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3919
3883
|
});
|
|
3920
3884
|
}
|
|
3921
3885
|
forwardActivity(forwarder, recipients, options) {
|
|
3922
|
-
|
|
3923
|
-
return tracer.startActiveSpan("activitypub.outbox", {
|
|
3886
|
+
return this.tracerProvider.getTracer(name, version).startActiveSpan("activitypub.outbox", {
|
|
3924
3887
|
kind: this.federation.outboxQueue == null || options?.immediate ? SpanKind.CLIENT : SpanKind.PRODUCER,
|
|
3925
3888
|
attributes: { "activitypub.activity.type": this.activityType }
|
|
3926
3889
|
}, async (span) => {
|
|
@@ -3939,7 +3902,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3939
3902
|
});
|
|
3940
3903
|
}
|
|
3941
3904
|
async forwardActivityInternal(forwarder, recipients, options) {
|
|
3942
|
-
const logger
|
|
3905
|
+
const logger = getLogger([
|
|
3943
3906
|
"fedify",
|
|
3944
3907
|
"federation",
|
|
3945
3908
|
"inbox"
|
|
@@ -3966,14 +3929,13 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3966
3929
|
if (!hasSignature(this.activity)) {
|
|
3967
3930
|
let hasProof;
|
|
3968
3931
|
try {
|
|
3969
|
-
|
|
3970
|
-
hasProof = await activity.getProof() != null;
|
|
3932
|
+
hasProof = await (await Activity.fromJsonLd(this.activity, this)).getProof() != null;
|
|
3971
3933
|
} catch {
|
|
3972
3934
|
hasProof = false;
|
|
3973
3935
|
}
|
|
3974
3936
|
if (!hasProof) {
|
|
3975
3937
|
if (options?.skipIfUnsigned) return;
|
|
3976
|
-
logger
|
|
3938
|
+
logger.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.");
|
|
3977
3939
|
}
|
|
3978
3940
|
}
|
|
3979
3941
|
if (recipients === "followers") {
|
|
@@ -3987,14 +3949,14 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3987
3949
|
preferSharedInbox: options?.preferSharedInbox,
|
|
3988
3950
|
excludeBaseUris: options?.excludeBaseUris
|
|
3989
3951
|
});
|
|
3990
|
-
logger
|
|
3952
|
+
logger.debug("Forwarding activity {activityId} to inboxes:\n{inboxes}", {
|
|
3991
3953
|
inboxes: globalThis.Object.keys(inboxes),
|
|
3992
3954
|
activityId: this.activityId,
|
|
3993
3955
|
activity: this.activity
|
|
3994
3956
|
});
|
|
3995
3957
|
if (options?.immediate || this.federation.outboxQueue == null) {
|
|
3996
|
-
if (options?.immediate) logger
|
|
3997
|
-
else logger
|
|
3958
|
+
if (options?.immediate) logger.debug("Forwarding activity immediately without queue since immediate option is set.");
|
|
3959
|
+
else logger.debug("Forwarding activity immediately without queue since queue is not set.");
|
|
3998
3960
|
const promises = [];
|
|
3999
3961
|
for (const inbox in inboxes) promises.push(sendActivity({
|
|
4000
3962
|
keys,
|
|
@@ -4009,7 +3971,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
4009
3971
|
await Promise.all(promises);
|
|
4010
3972
|
return;
|
|
4011
3973
|
}
|
|
4012
|
-
logger
|
|
3974
|
+
logger.debug("Enqueuing activity {activityId} to forward later.", {
|
|
4013
3975
|
activityId: this.activityId,
|
|
4014
3976
|
activity: this.activity
|
|
4015
3977
|
});
|
|
@@ -4051,10 +4013,9 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
4051
4013
|
const { outboxQueue } = this.federation;
|
|
4052
4014
|
if (outboxQueue.enqueueMany == null) {
|
|
4053
4015
|
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
4054
|
-
const
|
|
4055
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
4016
|
+
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
4056
4017
|
if (errors.length > 0) {
|
|
4057
|
-
logger
|
|
4018
|
+
logger.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
|
|
4058
4019
|
activityId: this.activityId,
|
|
4059
4020
|
errors
|
|
4060
4021
|
});
|
|
@@ -4063,10 +4024,9 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
4063
4024
|
}
|
|
4064
4025
|
} else if (orderingKey != null) {
|
|
4065
4026
|
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
4066
|
-
const
|
|
4067
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
4027
|
+
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
4068
4028
|
if (errors.length > 0) {
|
|
4069
|
-
logger
|
|
4029
|
+
logger.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
|
|
4070
4030
|
activityId: this.activityId,
|
|
4071
4031
|
errors
|
|
4072
4032
|
});
|
|
@@ -4076,7 +4036,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
4076
4036
|
} else try {
|
|
4077
4037
|
await outboxQueue.enqueueMany(messages.map((m) => m.message));
|
|
4078
4038
|
} catch (error) {
|
|
4079
|
-
logger
|
|
4039
|
+
logger.error("Failed to enqueue activity {activityId} to forward later:\n{error}", {
|
|
4080
4040
|
activityId: this.activityId,
|
|
4081
4041
|
error
|
|
4082
4042
|
});
|
|
@@ -4131,10 +4091,7 @@ function unauthorized(_request) {
|
|
|
4131
4091
|
function getRequestId(request) {
|
|
4132
4092
|
const traceId = request.headers.get("X-Request-Id") || request.headers.get("X-Correlation-Id") || request.headers.get("Traceparent")?.split("-")[1];
|
|
4133
4093
|
if (traceId != null) return traceId;
|
|
4134
|
-
|
|
4135
|
-
const random = Math.random().toString(36).slice(2, 8);
|
|
4136
|
-
return `req_${timestamp}${random}`;
|
|
4094
|
+
return `req_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
|
|
4137
4095
|
}
|
|
4138
|
-
|
|
4139
4096
|
//#endregion
|
|
4140
|
-
export {
|
|
4097
|
+
export { createExponentialBackoffPolicy as a, buildCollectionSynchronizationHeader as c, Router$1 as d, RouterError as f, SendActivityError as i, digest as l, middleware_exports as n, respondWithObject as o, handleWebFinger as r, respondWithObjectIfAcceptable as s, createFederation as t, createFederationBuilder as u };
|