@fedify/fedify 2.1.0 → 2.1.2
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/{accept-D7sAxyNa.js → accept-Dd__NiUL.mjs} +10 -8
- 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-f3m3epl3.js → assert_not_equals--wG9hV7u.mjs} +6 -13
- package/dist/{assert_rejects-0h7I2Esa.js → assert_rejects-B-qJtC9Z.mjs} +6 -11
- package/dist/{assert_throws-rjdMBf31.js → assert_throws-4NwKEy2q.mjs} +5 -10
- package/dist/{builder-WiHhZvjW.js → builder-DkJDAzes.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-BxMZiQaD.d.ts → client-AtlibPOU.d.ts} +1 -1
- package/dist/{client-CoCIaTNO.js → client-DEpOVgY1.mjs} +9 -13
- package/dist/{client-C97KOq3x.d.cts → client-z-8dc-e1.d.cts} +1 -1
- package/dist/{collection-CSzG2j1P.js → collection-BD6-SZ6O.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-DyJjQQ_H.d.ts → context-BOiMZBu5.d.ts} +9 -18
- package/dist/{context-BcqA-0BL.d.cts → context-BhZVy7RB.d.cts} +9 -18
- package/dist/{context-Aqenou7c.js → context-Juj6bdHC.mjs} +7 -11
- package/dist/deno-C5VMwnFV.mjs +8 -0
- package/dist/{docloader-bVO2EvL9.js → docloader-X9mcJ9Tz.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} +21 -44
- 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} +69 -131
- package/dist/federation/idempotency.test.d.mts +2 -0
- package/dist/federation/{idempotency.test.js → idempotency.test.mjs} +31 -63
- 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} +13 -19
- 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} +173 -262
- 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 -30
- package/dist/federation/webfinger.test.d.mts +2 -0
- package/dist/federation/{webfinger.test.js → webfinger.test.mjs} +22 -56
- package/dist/{http-DhH623ma.js → http-BLZWcpzg.js} +67 -187
- package/dist/{http-CKDim8Tw.js → http-BTLPIzFa.mjs} +37 -45
- package/dist/{http-BudnHZE2.d.cts → http-CrGuipxe.d.cts} +1 -6
- package/dist/{http-gvnJbMS1.cjs → http-CxodXLwi.cjs} +186 -300
- package/dist/{http-Dax_FIBo.d.ts → http-aQzN9Ayi.d.ts} +1 -6
- package/dist/{inbox-CA9AUEGa.js → inbox-mcbmhjTW.mjs} +18 -26
- package/dist/{key-BsSCz8Z_.js → key-1MaItIGc.mjs} +29 -37
- package/dist/{keycache-CpGWAUbj.js → keycache-CCSwkQcY.mjs} +5 -10
- package/dist/{keys-BFve7QQv.js → keys-BAK-tUlf.mjs} +5 -9
- 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-Bw2F2ABq.js → kv-cache-B01V7s3h.mjs} +4 -8
- package/dist/{kv-cache-DK4GFVWx.cjs → kv-cache-DjC82_4n.cjs} +27 -34
- package/dist/{kv-cache-CxoHCR44.js → kv-cache-GIDK1oLs.js} +6 -13
- package/dist/{kv-QzKcOQgP.js → kv-tL2TOE9X.mjs} +6 -10
- package/dist/{ld-Bo_Rx0Fc.js → ld-94uHZ1eO.mjs} +17 -31
- package/dist/{middleware-BkrUA3da.js → middleware-B5Er10wE.js} +336 -383
- package/dist/middleware-CDuHbSVE.mjs +5 -0
- package/dist/middleware-CTyq5KB0.cjs +4 -0
- package/dist/{middleware-CpAnWzjC.cjs → middleware-CqDJSLoG.cjs} +532 -587
- package/dist/{middleware-CZ8jOOa3.js → middleware-DMZGXHm3.mjs} +282 -317
- package/dist/{mod-Bx9jcLB8.d.cts → mod-B505FZBC.d.cts} +3 -3
- package/dist/{mod-em2Il1eD.d.cts → mod-Bp_CzKd4.d.cts} +2 -2
- package/dist/{mod-Cs2dYEwI.d.ts → mod-D7PAuO6k.d.ts} +3 -3
- package/dist/{mod-D6MdymW7.d.ts → mod-DKOAow7a.d.ts} +2 -2
- package/dist/{mod-Coe7KEgX.d.cts → mod-DoJBjjnO.d.cts} +2 -2
- package/dist/{mod-D6dOd--H.d.ts → mod-DvxszxXC.d.ts} +2 -2
- package/dist/mod.cjs +29 -74
- package/dist/mod.d.cts +11 -14
- package/dist/mod.d.ts +11 -15
- package/dist/mod.js +17 -71
- package/dist/{negotiation-BlAuS_nr.js → negotiation-DnsfFF8I.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 -43
- 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} +124 -178
- 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-Bj_IbwIT.js → owner-B4aIDhg_.mjs} +11 -16
- package/dist/{owner-1AbPBOOZ.d.cts → owner-CptqhsOy.d.cts} +1 -1
- package/dist/{proof-u6Y358J-.js → proof-DYZWMWOC.mjs} +21 -33
- package/dist/{proof-BhFF_JVj.cjs → proof-DqCjiFwb.cjs} +133 -157
- package/dist/{proof-D5BQTIcU.js → proof-j-of9m5W.js} +33 -59
- package/dist/{retry-mqLf4b-R.js → retry-B_E3V_Dx.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-CE8h59oe.js → send-uLjD0uAe.mjs} +8 -13
- package/dist/sig/accept.test.d.mts +2 -0
- package/dist/sig/{accept.test.js → accept.test.mjs} +35 -70
- package/dist/sig/http.test.d.mts +2 -0
- package/dist/sig/{http.test.js → http.test.mjs} +209 -280
- 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-X-_kMxKM.js → std__assert-Duiq_YC9.mjs} +12 -24
- package/dist/testing/{mod.d.ts → mod.d.mts} +26 -90
- 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-DCP0WLdt.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 -25
- 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 -88
- package/dist/compat-Bb4NuTUO.js +0 -4
- package/dist/compat-DmDDELst.cjs +0 -4
- package/dist/deno-BRMCYThi.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-BtT_mKsB.cjs +0 -12
- package/dist/middleware-CUMoHNCA.js +0 -12
- package/dist/middleware-CzeVJTA1.js +0 -27
- package/dist/mod-B7QkWzrL.d.cts +0 -80
- package/dist/mod-Bh8mqlYw.d.cts +0 -9
- package/dist/mod-D6HodEq7.d.ts +0 -7
- package/dist/mod-SMHOMNpZ.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/accept.test.d.ts +0 -3
- 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,36 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import { createExponentialBackoffPolicy } from "./retry-mqLf4b-R.js";
|
|
24
|
-
import { SendActivityError, extractInboxes, sendActivity } from "./send-CE8h59oe.js";
|
|
1
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { n as RouterError } from "./router-CrMLXoOr.mjs";
|
|
5
|
+
import { n as version, t as name } from "./deno-C5VMwnFV.mjs";
|
|
6
|
+
import { t as formatAcceptSignature } from "./accept-Dd__NiUL.mjs";
|
|
7
|
+
import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-1MaItIGc.mjs";
|
|
8
|
+
import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-BTLPIzFa.mjs";
|
|
9
|
+
import { t as getAuthenticatedDocumentLoader } from "./docloader-X9mcJ9Tz.mjs";
|
|
10
|
+
import { n as kvCache } from "./kv-cache-B01V7s3h.mjs";
|
|
11
|
+
import { a as signJsonLd, i as hasSignature, o as verifyJsonLd, r as detachSignature } from "./ld-94uHZ1eO.mjs";
|
|
12
|
+
import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-B4aIDhg_.mjs";
|
|
13
|
+
import { n as signObject, r as verifyObject } from "./proof-DYZWMWOC.mjs";
|
|
14
|
+
import { t as getNodeInfo } from "./client-DEpOVgY1.mjs";
|
|
15
|
+
import { t as nodeInfoToJson } from "./types-DCP0WLdt.mjs";
|
|
16
|
+
import { n as routeActivity } from "./inbox-mcbmhjTW.mjs";
|
|
17
|
+
import { t as FederationBuilderImpl } from "./builder-DkJDAzes.mjs";
|
|
18
|
+
import { t as buildCollectionSynchronizationHeader } from "./collection-BD6-SZ6O.mjs";
|
|
19
|
+
import { t as KvKeyCache } from "./keycache-CCSwkQcY.mjs";
|
|
20
|
+
import { t as acceptsJsonLd } from "./negotiation-DnsfFF8I.mjs";
|
|
21
|
+
import { t as createExponentialBackoffPolicy } from "./retry-B_E3V_Dx.mjs";
|
|
22
|
+
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-uLjD0uAe.mjs";
|
|
25
23
|
import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
|
|
24
|
+
import { lookupWebFinger } from "@fedify/webfinger";
|
|
25
|
+
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
26
26
|
import { uniq } from "es-toolkit";
|
|
27
27
|
import { FetchError, getDocumentLoader } from "@fedify/vocab-runtime";
|
|
28
|
-
import { lookupWebFinger } from "@fedify/webfinger";
|
|
29
28
|
import { getLogger, withContext } from "@logtape/logtape";
|
|
30
|
-
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
31
29
|
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";
|
|
32
30
|
import { domainToASCII } from "node:url";
|
|
33
|
-
|
|
34
31
|
//#region src/compat/transformers.ts
|
|
35
32
|
const logger$1 = getLogger([
|
|
36
33
|
"fedify",
|
|
@@ -55,9 +52,9 @@ const logger$1 = getLogger([
|
|
|
55
52
|
* @return The activity with an ID assigned.
|
|
56
53
|
* @since 1.4.0
|
|
57
54
|
*/
|
|
58
|
-
function autoIdAssigner(activity, context
|
|
55
|
+
function autoIdAssigner(activity, context) {
|
|
59
56
|
if (activity.id != null) return activity;
|
|
60
|
-
const id = new URL(`/#${activity.constructor.name}/${crypto.randomUUID()}`, context
|
|
57
|
+
const id = new URL(`/#${activity.constructor.name}/${crypto.randomUUID()}`, context.origin);
|
|
61
58
|
logger$1.warn("As the activity to send does not have an id, a new id {id} has been generated for it. However, it is recommended to explicitly set the id for the activity.", { id: id.href });
|
|
62
59
|
return activity.clone({ id });
|
|
63
60
|
}
|
|
@@ -120,7 +117,6 @@ function actorDehydrator(activity, _context) {
|
|
|
120
117
|
function getDefaultActivityTransformers() {
|
|
121
118
|
return [autoIdAssigner, actorDehydrator];
|
|
122
119
|
}
|
|
123
|
-
|
|
124
120
|
//#endregion
|
|
125
121
|
//#region src/nodeinfo/handler.ts
|
|
126
122
|
/**
|
|
@@ -130,10 +126,9 @@ function getDefaultActivityTransformers() {
|
|
|
130
126
|
* @param parameters The parameters for handling the request.
|
|
131
127
|
* @returns The response to the request.
|
|
132
128
|
*/
|
|
133
|
-
async function handleNodeInfo(_request, { context
|
|
134
|
-
const promise = nodeInfoDispatcher(context
|
|
135
|
-
const
|
|
136
|
-
const json = nodeInfoToJson(nodeInfo);
|
|
129
|
+
async function handleNodeInfo(_request, { context, nodeInfoDispatcher }) {
|
|
130
|
+
const promise = nodeInfoDispatcher(context);
|
|
131
|
+
const json = nodeInfoToJson(promise instanceof Promise ? await promise : promise);
|
|
137
132
|
return new Response(JSON.stringify(json), { headers: { "Content-Type": "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\"" } });
|
|
138
133
|
}
|
|
139
134
|
/**
|
|
@@ -143,22 +138,20 @@ async function handleNodeInfo(_request, { context: context$1, nodeInfoDispatcher
|
|
|
143
138
|
* @param context The request context.
|
|
144
139
|
* @returns The response to the request.
|
|
145
140
|
*/
|
|
146
|
-
function handleNodeInfoJrd(_request, context
|
|
141
|
+
function handleNodeInfoJrd(_request, context) {
|
|
147
142
|
const links = [];
|
|
148
143
|
try {
|
|
149
144
|
links.push({
|
|
150
145
|
rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
|
|
151
|
-
href: context
|
|
146
|
+
href: context.getNodeInfoUri().href,
|
|
152
147
|
type: "application/json; profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\""
|
|
153
148
|
});
|
|
154
149
|
} catch (e) {
|
|
155
150
|
if (!(e instanceof RouterError)) throw e;
|
|
156
151
|
}
|
|
157
|
-
const
|
|
158
|
-
const response = new Response(JSON.stringify(jrd), { headers: { "Content-Type": "application/jrd+json" } });
|
|
152
|
+
const response = new Response(JSON.stringify({ links }), { headers: { "Content-Type": "application/jrd+json" } });
|
|
159
153
|
return Promise.resolve(response);
|
|
160
154
|
}
|
|
161
|
-
|
|
162
155
|
//#endregion
|
|
163
156
|
//#region src/federation/handler.ts
|
|
164
157
|
/**
|
|
@@ -168,25 +161,25 @@ function handleNodeInfoJrd(_request, context$1) {
|
|
|
168
161
|
* @param parameters The parameters for handling the actor.
|
|
169
162
|
* @returns A promise that resolves to an HTTP response.
|
|
170
163
|
*/
|
|
171
|
-
async function handleActor(request, { identifier, context
|
|
172
|
-
const logger
|
|
164
|
+
async function handleActor(request, { identifier, context, actorDispatcher, authorizePredicate, onNotFound, onUnauthorized }) {
|
|
165
|
+
const logger = getLogger([
|
|
173
166
|
"fedify",
|
|
174
167
|
"federation",
|
|
175
168
|
"actor"
|
|
176
169
|
]);
|
|
177
170
|
if (actorDispatcher == null) {
|
|
178
|
-
logger
|
|
171
|
+
logger.debug("Actor dispatcher is not set.", { identifier });
|
|
179
172
|
return await onNotFound(request);
|
|
180
173
|
}
|
|
181
|
-
const actor = await actorDispatcher(context
|
|
174
|
+
const actor = await actorDispatcher(context, identifier);
|
|
182
175
|
if (actor == null) {
|
|
183
|
-
logger
|
|
176
|
+
logger.debug("Actor {identifier} not found.", { identifier });
|
|
184
177
|
return await onNotFound(request);
|
|
185
178
|
}
|
|
186
179
|
if (authorizePredicate != null) {
|
|
187
|
-
if (!await authorizePredicate(context
|
|
180
|
+
if (!await authorizePredicate(context, identifier)) return await onUnauthorized(request);
|
|
188
181
|
}
|
|
189
|
-
const jsonLd = await actor.toJsonLd(context
|
|
182
|
+
const jsonLd = await actor.toJsonLd(context);
|
|
190
183
|
return new Response(JSON.stringify(jsonLd), { headers: {
|
|
191
184
|
"Content-Type": "application/activity+json",
|
|
192
185
|
Vary: "Accept"
|
|
@@ -199,14 +192,14 @@ async function handleActor(request, { identifier, context: context$1, actorDispa
|
|
|
199
192
|
* @param parameters The parameters for handling the object.
|
|
200
193
|
* @returns A promise that resolves to an HTTP response.
|
|
201
194
|
*/
|
|
202
|
-
async function handleObject(request, { values, context
|
|
195
|
+
async function handleObject(request, { values, context, objectDispatcher, authorizePredicate, onNotFound, onUnauthorized }) {
|
|
203
196
|
if (objectDispatcher == null) return await onNotFound(request);
|
|
204
|
-
const object = await objectDispatcher(context
|
|
197
|
+
const object = await objectDispatcher(context, values);
|
|
205
198
|
if (object == null) return await onNotFound(request);
|
|
206
199
|
if (authorizePredicate != null) {
|
|
207
|
-
if (!await authorizePredicate(context
|
|
200
|
+
if (!await authorizePredicate(context, values)) return await onUnauthorized(request);
|
|
208
201
|
}
|
|
209
|
-
const jsonLd = await object.toJsonLd(context
|
|
202
|
+
const jsonLd = await object.toJsonLd(context);
|
|
210
203
|
return new Response(JSON.stringify(jsonLd), { headers: {
|
|
211
204
|
"Content-Type": "application/activity+json",
|
|
212
205
|
Vary: "Accept"
|
|
@@ -222,18 +215,17 @@ async function handleObject(request, { values, context: context$1, objectDispatc
|
|
|
222
215
|
* @param parameters The parameters for handling the collection.
|
|
223
216
|
* @returns A promise that resolves to an HTTP response.
|
|
224
217
|
*/
|
|
225
|
-
async function handleCollection(request, { name, identifier, uriGetter, filter, filterPredicate, context
|
|
226
|
-
const spanName = name.trim().replace(/\s+/g, "_");
|
|
218
|
+
async function handleCollection(request, { name: name$2, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, onUnauthorized, onNotFound }) {
|
|
219
|
+
const spanName = name$2.trim().replace(/\s+/g, "_");
|
|
227
220
|
tracerProvider = tracerProvider ?? trace.getTracerProvider();
|
|
228
|
-
const tracer = tracerProvider.getTracer(
|
|
229
|
-
const
|
|
230
|
-
const cursor = url.searchParams.get("cursor");
|
|
221
|
+
const tracer = tracerProvider.getTracer(name, version);
|
|
222
|
+
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
231
223
|
if (collectionCallbacks == null) return await onNotFound(request);
|
|
232
224
|
let collection;
|
|
233
225
|
const baseUri = uriGetter(identifier);
|
|
234
226
|
if (cursor == null) {
|
|
235
|
-
const firstCursor = await collectionCallbacks.firstCursor?.(context
|
|
236
|
-
const totalItems = filter == null ? await collectionCallbacks.counter?.(context
|
|
227
|
+
const firstCursor = await collectionCallbacks.firstCursor?.(context, identifier);
|
|
228
|
+
const totalItems = filter == null ? await collectionCallbacks.counter?.(context, identifier) : void 0;
|
|
237
229
|
if (firstCursor == null) {
|
|
238
230
|
const itemsOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection ${spanName}`, {
|
|
239
231
|
kind: SpanKind.SERVER,
|
|
@@ -244,7 +236,7 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
244
236
|
}, async (span) => {
|
|
245
237
|
if (totalItems != null) span.setAttribute("activitypub.collection.total_items", Number(totalItems));
|
|
246
238
|
try {
|
|
247
|
-
const page = await collectionCallbacks.dispatcher(context
|
|
239
|
+
const page = await collectionCallbacks.dispatcher(context, identifier, null, filter);
|
|
248
240
|
if (page == null) {
|
|
249
241
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
250
242
|
return await onNotFound(request);
|
|
@@ -266,15 +258,15 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
266
258
|
collection = new OrderedCollection({
|
|
267
259
|
id: baseUri,
|
|
268
260
|
totalItems: totalItems == null ? null : Number(totalItems),
|
|
269
|
-
items: filterCollectionItems(itemsOrResponse, name, filterPredicate)
|
|
261
|
+
items: filterCollectionItems(itemsOrResponse, name$2, filterPredicate)
|
|
270
262
|
});
|
|
271
263
|
} else {
|
|
272
|
-
const lastCursor = await collectionCallbacks.lastCursor?.(context
|
|
273
|
-
const first = new URL(context
|
|
264
|
+
const lastCursor = await collectionCallbacks.lastCursor?.(context, identifier);
|
|
265
|
+
const first = new URL(context.url);
|
|
274
266
|
first.searchParams.set("cursor", firstCursor);
|
|
275
267
|
let last = null;
|
|
276
268
|
if (lastCursor != null) {
|
|
277
|
-
last = new URL(context
|
|
269
|
+
last = new URL(context.url);
|
|
278
270
|
last.searchParams.set("cursor", lastCursor);
|
|
279
271
|
}
|
|
280
272
|
collection = new OrderedCollection({
|
|
@@ -287,7 +279,7 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
287
279
|
} else {
|
|
288
280
|
const uri = new URL(baseUri);
|
|
289
281
|
uri.searchParams.set("cursor", cursor);
|
|
290
|
-
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name}`, {
|
|
282
|
+
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$2}`, {
|
|
291
283
|
kind: SpanKind.SERVER,
|
|
292
284
|
attributes: {
|
|
293
285
|
"activitypub.collection.id": uri.href,
|
|
@@ -296,7 +288,7 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
296
288
|
}
|
|
297
289
|
}, async (span) => {
|
|
298
290
|
try {
|
|
299
|
-
const page = await collectionCallbacks.dispatcher(context
|
|
291
|
+
const page = await collectionCallbacks.dispatcher(context, identifier, cursor, filter);
|
|
300
292
|
if (page == null) {
|
|
301
293
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
302
294
|
return await onNotFound(request);
|
|
@@ -317,28 +309,28 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
317
309
|
const { items, prevCursor, nextCursor } = pageOrResponse;
|
|
318
310
|
let prev = null;
|
|
319
311
|
if (prevCursor != null) {
|
|
320
|
-
prev = new URL(context
|
|
312
|
+
prev = new URL(context.url);
|
|
321
313
|
prev.searchParams.set("cursor", prevCursor);
|
|
322
314
|
}
|
|
323
315
|
let next = null;
|
|
324
316
|
if (nextCursor != null) {
|
|
325
|
-
next = new URL(context
|
|
317
|
+
next = new URL(context.url);
|
|
326
318
|
next.searchParams.set("cursor", nextCursor);
|
|
327
319
|
}
|
|
328
|
-
const partOf = new URL(context
|
|
320
|
+
const partOf = new URL(context.url);
|
|
329
321
|
partOf.searchParams.delete("cursor");
|
|
330
322
|
collection = new OrderedCollectionPage({
|
|
331
323
|
id: uri,
|
|
332
324
|
prev,
|
|
333
325
|
next,
|
|
334
|
-
items: filterCollectionItems(items, name, filterPredicate),
|
|
326
|
+
items: filterCollectionItems(items, name$2, filterPredicate),
|
|
335
327
|
partOf
|
|
336
328
|
});
|
|
337
329
|
}
|
|
338
330
|
if (collectionCallbacks.authorizePredicate != null) {
|
|
339
|
-
if (!await collectionCallbacks.authorizePredicate(context
|
|
331
|
+
if (!await collectionCallbacks.authorizePredicate(context, identifier)) return await onUnauthorized(request);
|
|
340
332
|
}
|
|
341
|
-
const jsonLd = await collection.toJsonLd(context
|
|
333
|
+
const jsonLd = await collection.toJsonLd(context);
|
|
342
334
|
return new Response(JSON.stringify(jsonLd), { headers: {
|
|
343
335
|
"Content-Type": "application/activity+json",
|
|
344
336
|
Vary: "Accept"
|
|
@@ -383,9 +375,7 @@ function filterCollectionItems(items, collectionName, filterPredicate) {
|
|
|
383
375
|
* @returns A promise that resolves to an HTTP response.
|
|
384
376
|
*/
|
|
385
377
|
async function handleInbox(request, options) {
|
|
386
|
-
|
|
387
|
-
const tracer = tracerProvider.getTracer(deno_default.name, deno_default.version);
|
|
388
|
-
return await tracer.startActiveSpan("activitypub.inbox", {
|
|
378
|
+
return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("activitypub.inbox", {
|
|
389
379
|
kind: options.queue == null ? SpanKind.SERVER : SpanKind.PRODUCER,
|
|
390
380
|
attributes: { "activitypub.shared_inbox": options.recipient == null }
|
|
391
381
|
}, async (span) => {
|
|
@@ -413,22 +403,21 @@ async function handleInbox(request, options) {
|
|
|
413
403
|
*/
|
|
414
404
|
async function handleInboxInternal(request, parameters, span) {
|
|
415
405
|
const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, unverifiedActivityHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, inboxChallengePolicy, tracerProvider } = parameters;
|
|
416
|
-
const logger
|
|
406
|
+
const logger = getLogger([
|
|
417
407
|
"fedify",
|
|
418
408
|
"federation",
|
|
419
409
|
"inbox"
|
|
420
410
|
]);
|
|
421
411
|
if (actorDispatcher == null) {
|
|
422
|
-
logger
|
|
412
|
+
logger.error("Actor dispatcher is not set.", { recipient });
|
|
423
413
|
span.setStatus({
|
|
424
414
|
code: SpanStatusCode.ERROR,
|
|
425
415
|
message: "Actor dispatcher is not set."
|
|
426
416
|
});
|
|
427
417
|
return await onNotFound(request);
|
|
428
418
|
} else if (recipient != null) {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
logger$2.error("Actor {recipient} not found.", { recipient });
|
|
419
|
+
if (await actorDispatcher(ctx, recipient) == null) {
|
|
420
|
+
logger.error("Actor {recipient} not found.", { recipient });
|
|
432
421
|
span.setStatus({
|
|
433
422
|
code: SpanStatusCode.ERROR,
|
|
434
423
|
message: `Actor ${recipient} not found.`
|
|
@@ -437,7 +426,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
437
426
|
}
|
|
438
427
|
}
|
|
439
428
|
if (request.bodyUsed) {
|
|
440
|
-
logger
|
|
429
|
+
logger.error("Request body has already been read.", { recipient });
|
|
441
430
|
span.setStatus({
|
|
442
431
|
code: SpanStatusCode.ERROR,
|
|
443
432
|
message: "Request body has already been read."
|
|
@@ -447,7 +436,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
447
436
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
448
437
|
});
|
|
449
438
|
} else if (request.body?.locked) {
|
|
450
|
-
logger
|
|
439
|
+
logger.error("Request body is locked.", { recipient });
|
|
451
440
|
span.setStatus({
|
|
452
441
|
code: SpanStatusCode.ERROR,
|
|
453
442
|
message: "Request body is locked."
|
|
@@ -461,15 +450,15 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
461
450
|
try {
|
|
462
451
|
json = await request.clone().json();
|
|
463
452
|
} catch (error) {
|
|
464
|
-
logger
|
|
453
|
+
logger.error("Failed to parse JSON:\n{error}", {
|
|
465
454
|
recipient,
|
|
466
455
|
error
|
|
467
456
|
});
|
|
468
457
|
try {
|
|
469
458
|
await inboxErrorHandler?.(ctx, error);
|
|
470
|
-
} catch (error
|
|
471
|
-
logger
|
|
472
|
-
error
|
|
459
|
+
} catch (error) {
|
|
460
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
461
|
+
error,
|
|
473
462
|
activity: json,
|
|
474
463
|
recipient
|
|
475
464
|
});
|
|
@@ -494,7 +483,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
494
483
|
});
|
|
495
484
|
} catch (error) {
|
|
496
485
|
if (error instanceof Error && error.name === "jsonld.SyntaxError") {
|
|
497
|
-
logger
|
|
486
|
+
logger.error("Failed to parse JSON-LD:\n{error}", {
|
|
498
487
|
recipient,
|
|
499
488
|
error
|
|
500
489
|
});
|
|
@@ -509,14 +498,14 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
509
498
|
let activity = null;
|
|
510
499
|
let activityVerified = false;
|
|
511
500
|
if (ldSigVerified) {
|
|
512
|
-
logger
|
|
501
|
+
logger.debug("Linked Data Signatures are verified.", {
|
|
513
502
|
recipient,
|
|
514
503
|
json
|
|
515
504
|
});
|
|
516
505
|
activity = await Activity.fromJsonLd(jsonWithoutSig, ctx);
|
|
517
506
|
activityVerified = true;
|
|
518
507
|
} else {
|
|
519
|
-
logger
|
|
508
|
+
logger.debug("Linked Data Signatures are not verified.", {
|
|
520
509
|
recipient,
|
|
521
510
|
json
|
|
522
511
|
});
|
|
@@ -528,16 +517,16 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
528
517
|
tracerProvider
|
|
529
518
|
});
|
|
530
519
|
} catch (error) {
|
|
531
|
-
logger
|
|
520
|
+
logger.error("Failed to parse activity:\n{error}", {
|
|
532
521
|
recipient,
|
|
533
522
|
activity: json,
|
|
534
523
|
error
|
|
535
524
|
});
|
|
536
525
|
try {
|
|
537
526
|
await inboxErrorHandler?.(ctx, error);
|
|
538
|
-
} catch (error
|
|
539
|
-
logger
|
|
540
|
-
error
|
|
527
|
+
} catch (error) {
|
|
528
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
529
|
+
error,
|
|
541
530
|
activity: json,
|
|
542
531
|
recipient
|
|
543
532
|
});
|
|
@@ -551,12 +540,12 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
551
540
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
552
541
|
});
|
|
553
542
|
}
|
|
554
|
-
if (activity == null) logger
|
|
543
|
+
if (activity == null) logger.debug("Object Integrity Proofs are not verified.", {
|
|
555
544
|
recipient,
|
|
556
545
|
activity: json
|
|
557
546
|
});
|
|
558
547
|
else {
|
|
559
|
-
logger
|
|
548
|
+
logger.debug("Object Integrity Proofs are verified.", {
|
|
560
549
|
recipient,
|
|
561
550
|
activity: json
|
|
562
551
|
});
|
|
@@ -576,7 +565,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
576
565
|
});
|
|
577
566
|
if (verification.verified === false) {
|
|
578
567
|
const reason = verification.reason;
|
|
579
|
-
logger
|
|
568
|
+
logger.error("Failed to verify the request's HTTP Signatures.", {
|
|
580
569
|
recipient,
|
|
581
570
|
reason: reason.type,
|
|
582
571
|
keyId: "keyId" in reason ? reason.keyId?.href : void 0
|
|
@@ -589,16 +578,16 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
589
578
|
try {
|
|
590
579
|
activity = await Activity.fromJsonLd(jsonWithoutSig, ctx);
|
|
591
580
|
} catch (error) {
|
|
592
|
-
logger
|
|
581
|
+
logger.error("Failed to parse activity:\n{error}", {
|
|
593
582
|
recipient,
|
|
594
583
|
activity: json,
|
|
595
584
|
error
|
|
596
585
|
});
|
|
597
586
|
try {
|
|
598
587
|
await inboxErrorHandler?.(ctx, error);
|
|
599
|
-
} catch (error
|
|
600
|
-
logger
|
|
601
|
-
error
|
|
588
|
+
} catch (error) {
|
|
589
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
590
|
+
error,
|
|
602
591
|
activity: json,
|
|
603
592
|
recipient
|
|
604
593
|
});
|
|
@@ -625,16 +614,16 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
625
614
|
try {
|
|
626
615
|
response = await unverifiedActivityHandler(ctx, activity, reason);
|
|
627
616
|
} catch (error) {
|
|
628
|
-
logger
|
|
617
|
+
logger.error("An unexpected error occurred in unverified activity handler:\n{error}", {
|
|
629
618
|
error,
|
|
630
619
|
activity: json,
|
|
631
620
|
recipient
|
|
632
621
|
});
|
|
633
622
|
try {
|
|
634
623
|
await inboxErrorHandler?.(ctx, error);
|
|
635
|
-
} catch (error
|
|
636
|
-
logger
|
|
637
|
-
error
|
|
624
|
+
} catch (error) {
|
|
625
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
626
|
+
error,
|
|
638
627
|
activity: json,
|
|
639
628
|
recipient
|
|
640
629
|
});
|
|
@@ -645,7 +634,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
645
634
|
return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
|
|
646
635
|
} else {
|
|
647
636
|
if (inboxChallengePolicy?.enabled && inboxChallengePolicy.requestNonce) pendingNonceLabel = verification.signatureLabel;
|
|
648
|
-
logger
|
|
637
|
+
logger.debug("HTTP Signatures are verified.", { recipient });
|
|
649
638
|
activityVerified = true;
|
|
650
639
|
}
|
|
651
640
|
httpSigKey = verification.key;
|
|
@@ -662,7 +651,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
662
651
|
"http_signatures.key_id": httpSigKey?.id?.href ?? ""
|
|
663
652
|
});
|
|
664
653
|
if (httpSigKey != null && !await doesActorOwnKey(activity, httpSigKey, ctx)) {
|
|
665
|
-
logger
|
|
654
|
+
logger.error("The signer ({keyId}) and the actor ({actorId}) do not match.", {
|
|
666
655
|
activity: json,
|
|
667
656
|
recipient,
|
|
668
657
|
keyId: httpSigKey.id?.href,
|
|
@@ -678,9 +667,8 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
678
667
|
});
|
|
679
668
|
}
|
|
680
669
|
if (pendingNonceLabel != null) {
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
logger$2.error("Signature nonce verification failed (missing, expired, or replayed).", { recipient });
|
|
670
|
+
if (!await verifySignatureNonce(request, kv, kvPrefixes.acceptSignatureNonce, pendingNonceLabel)) {
|
|
671
|
+
logger.error("Signature nonce verification failed (missing, expired, or replayed).", { recipient });
|
|
684
672
|
return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
|
|
685
673
|
}
|
|
686
674
|
}
|
|
@@ -736,11 +724,11 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
736
724
|
* @since 1.8.0
|
|
737
725
|
*/
|
|
738
726
|
const handleCustomCollection = exceptWrapper(_handleCustomCollection);
|
|
739
|
-
async function _handleCustomCollection(request, { name, values, context
|
|
727
|
+
async function _handleCustomCollection(request, { name, values, context, tracerProvider, collectionCallbacks: callbacks, filterPredicate }) {
|
|
740
728
|
verifyDefined(callbacks);
|
|
741
|
-
await authIfNeeded(context
|
|
729
|
+
await authIfNeeded(context, values, callbacks);
|
|
742
730
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
743
|
-
return await new CustomCollectionHandler(name, values, context
|
|
731
|
+
return await new CustomCollectionHandler(name, values, context, callbacks, tracerProvider, Collection, CollectionPage, filterPredicate).fetchCollection(cursor).toJsonLd().then(respondAsActivity);
|
|
744
732
|
}
|
|
745
733
|
/**
|
|
746
734
|
* Handles an ordered collection request.
|
|
@@ -754,11 +742,11 @@ async function _handleCustomCollection(request, { name, values, context: context
|
|
|
754
742
|
* @since 1.8.0
|
|
755
743
|
*/
|
|
756
744
|
const handleOrderedCollection = exceptWrapper(_handleOrderedCollection);
|
|
757
|
-
async function _handleOrderedCollection(request, { name, values, context
|
|
745
|
+
async function _handleOrderedCollection(request, { name, values, context, tracerProvider, collectionCallbacks: callbacks, filterPredicate }) {
|
|
758
746
|
verifyDefined(callbacks);
|
|
759
|
-
await authIfNeeded(context
|
|
747
|
+
await authIfNeeded(context, values, callbacks);
|
|
760
748
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
761
|
-
return await new CustomCollectionHandler(name, values, context
|
|
749
|
+
return await new CustomCollectionHandler(name, values, context, callbacks, tracerProvider, OrderedCollection, OrderedCollectionPage, filterPredicate).fetchCollection(cursor).toJsonLd().then(respondAsActivity);
|
|
762
750
|
}
|
|
763
751
|
/**
|
|
764
752
|
* Handling custom collections with support for pagination and filtering.
|
|
@@ -808,17 +796,17 @@ var CustomCollectionHandler = class {
|
|
|
808
796
|
* @param CollectionPage The CollectionPage constructor.
|
|
809
797
|
* @param filterPredicate Optional filter predicate for items.
|
|
810
798
|
*/
|
|
811
|
-
constructor(name, values, context
|
|
812
|
-
this.name = name;
|
|
799
|
+
constructor(name$1, values, context, callbacks, tracerProvider = trace.getTracerProvider(), Collection, CollectionPage, filterPredicate) {
|
|
800
|
+
this.name = name$1;
|
|
813
801
|
this.values = values;
|
|
814
|
-
this.context = context
|
|
802
|
+
this.context = context;
|
|
815
803
|
this.callbacks = callbacks;
|
|
816
804
|
this.tracerProvider = tracerProvider;
|
|
817
|
-
this.Collection = Collection
|
|
818
|
-
this.CollectionPage = CollectionPage
|
|
805
|
+
this.Collection = Collection;
|
|
806
|
+
this.CollectionPage = CollectionPage;
|
|
819
807
|
this.filterPredicate = filterPredicate;
|
|
820
808
|
this.name = this.name.trim().replace(/\s+/g, "_");
|
|
821
|
-
this.#tracer = this.tracerProvider.getTracer(
|
|
809
|
+
this.#tracer = this.tracerProvider.getTracer(name, version);
|
|
822
810
|
this.#id = new URL(this.context.url);
|
|
823
811
|
this.#dispatcher = callbacks.dispatcher.bind(callbacks);
|
|
824
812
|
}
|
|
@@ -847,8 +835,8 @@ var CustomCollectionHandler = class {
|
|
|
847
835
|
*/
|
|
848
836
|
async getCollection(cursor = null) {
|
|
849
837
|
if (cursor !== null) {
|
|
850
|
-
const props
|
|
851
|
-
return new this.CollectionPage(props
|
|
838
|
+
const props = await this.getPageProps(cursor);
|
|
839
|
+
return new this.CollectionPage(props);
|
|
852
840
|
}
|
|
853
841
|
const firstCursor = await this.firstCursor;
|
|
854
842
|
const props = typeof firstCursor === "string" ? await this.getProps(firstCursor) : await this.getPropsWithoutCursor();
|
|
@@ -996,7 +984,7 @@ var CustomCollectionHandler = class {
|
|
|
996
984
|
* @param value The total items count or a promise that resolves to it.
|
|
997
985
|
*/
|
|
998
986
|
set totalItems(value) {
|
|
999
|
-
const toNumber = (value
|
|
987
|
+
const toNumber = (value) => value == null ? null : Number(value);
|
|
1000
988
|
this.#totalItems = value instanceof Promise ? value.then(toNumber) : Promise.resolve(toNumber(value));
|
|
1001
989
|
}
|
|
1002
990
|
/**
|
|
@@ -1060,9 +1048,9 @@ const verifyDefined = (callbacks) => {
|
|
|
1060
1048
|
* @throws {UnauthorizedError} If authorization fails.
|
|
1061
1049
|
* @since 1.8.0
|
|
1062
1050
|
*/
|
|
1063
|
-
const authIfNeeded = async (context
|
|
1051
|
+
const authIfNeeded = async (context, values, { authorizePredicate: authorize = void 0 }) => {
|
|
1064
1052
|
if (authorize === void 0) return;
|
|
1065
|
-
if (!await authorize(context
|
|
1053
|
+
if (!await authorize(context, values)) throw new UnauthorizedError();
|
|
1066
1054
|
};
|
|
1067
1055
|
/**
|
|
1068
1056
|
* Appends a cursor parameter to a URL if the cursor exists.
|
|
@@ -1164,8 +1152,7 @@ async function verifySignatureNonce(request, kv, noncePrefix, verifiedLabel) {
|
|
|
1164
1152
|
if (nonce == null) return false;
|
|
1165
1153
|
const key = [...noncePrefix, nonce];
|
|
1166
1154
|
if (kv.cas != null) return await kv.cas(key, true, void 0);
|
|
1167
|
-
|
|
1168
|
-
if (stored != null) {
|
|
1155
|
+
if (await kv.get(key) != null) {
|
|
1169
1156
|
await kv.delete(key);
|
|
1170
1157
|
return true;
|
|
1171
1158
|
}
|
|
@@ -1190,18 +1177,16 @@ async function buildAcceptSignatureHeader(policy, kv, noncePrefix) {
|
|
|
1190
1177
|
const parameters = { created: true };
|
|
1191
1178
|
if (policy.requestNonce) {
|
|
1192
1179
|
const nonce = generateNonce();
|
|
1193
|
-
|
|
1194
|
-
await setKey(kv, key, policy);
|
|
1180
|
+
await setKey(kv, [...noncePrefix, nonce], policy);
|
|
1195
1181
|
parameters.nonce = nonce;
|
|
1196
1182
|
}
|
|
1197
1183
|
const baseComponents = policy.components ?? DEF_COMPONENTS;
|
|
1198
|
-
const components = uniq(MIN_COMPONENTS.concat(baseComponents)).filter((c) => c !== "@status").map((v) => ({
|
|
1199
|
-
value: v,
|
|
1200
|
-
params: {}
|
|
1201
|
-
}));
|
|
1202
1184
|
return formatAcceptSignature([{
|
|
1203
1185
|
label: "sig1",
|
|
1204
|
-
components
|
|
1186
|
+
components: uniq(MIN_COMPONENTS.concat(baseComponents)).filter((c) => c !== "@status").map((v) => ({
|
|
1187
|
+
value: v,
|
|
1188
|
+
params: {}
|
|
1189
|
+
})),
|
|
1205
1190
|
parameters
|
|
1206
1191
|
}]);
|
|
1207
1192
|
}
|
|
@@ -1221,7 +1206,6 @@ const MIN_COMPONENTS = [
|
|
|
1221
1206
|
"@target-uri",
|
|
1222
1207
|
"@authority"
|
|
1223
1208
|
];
|
|
1224
|
-
|
|
1225
1209
|
//#endregion
|
|
1226
1210
|
//#region src/federation/webfinger.ts
|
|
1227
1211
|
const logger = getLogger([
|
|
@@ -1254,12 +1238,12 @@ async function handleWebFinger(request, options) {
|
|
|
1254
1238
|
}
|
|
1255
1239
|
});
|
|
1256
1240
|
}
|
|
1257
|
-
async function handleWebFingerInternal(request, { context
|
|
1241
|
+
async function handleWebFingerInternal(request, { context, host, actorDispatcher, actorHandleMapper, actorAliasMapper, onNotFound, span, webFingerLinksDispatcher }) {
|
|
1258
1242
|
if (actorDispatcher == null) {
|
|
1259
1243
|
logger.error("Actor dispatcher is not set.");
|
|
1260
1244
|
return await onNotFound(request);
|
|
1261
1245
|
}
|
|
1262
|
-
const resource = context
|
|
1246
|
+
const resource = context.url.searchParams.get("resource");
|
|
1263
1247
|
if (resource == null) return new Response("Missing resource parameter.", { status: 400 });
|
|
1264
1248
|
span?.setAttribute("webfinger.resource", resource);
|
|
1265
1249
|
let resourceUrl;
|
|
@@ -1275,26 +1259,26 @@ async function handleWebFingerInternal(request, { context: context$1, host, acto
|
|
|
1275
1259
|
logger.error("No actor handle mapper is set; use the WebFinger username {username} as the actor's internal identifier.", { username });
|
|
1276
1260
|
return username;
|
|
1277
1261
|
}
|
|
1278
|
-
const identifier
|
|
1279
|
-
if (identifier
|
|
1262
|
+
const identifier = await actorHandleMapper(context, username);
|
|
1263
|
+
if (identifier == null) {
|
|
1280
1264
|
logger.error("Actor {username} not found.", { username });
|
|
1281
1265
|
return null;
|
|
1282
1266
|
}
|
|
1283
|
-
return identifier
|
|
1267
|
+
return identifier;
|
|
1284
1268
|
}
|
|
1285
1269
|
let identifier = null;
|
|
1286
|
-
const uriParsed = context
|
|
1270
|
+
const uriParsed = context.parseUri(resourceUrl);
|
|
1287
1271
|
if (uriParsed?.type != "actor") {
|
|
1288
1272
|
const match = /^acct:([^@]+)@([^@]+)$/.exec(resource);
|
|
1289
1273
|
if (match == null) {
|
|
1290
|
-
const result = await actorAliasMapper?.(context
|
|
1274
|
+
const result = await actorAliasMapper?.(context, resourceUrl);
|
|
1291
1275
|
if (result == null) return await onNotFound(request);
|
|
1292
1276
|
if ("identifier" in result) identifier = result.identifier;
|
|
1293
1277
|
else identifier = await mapUsernameToIdentifier(result.username);
|
|
1294
1278
|
} else {
|
|
1295
1279
|
const portMatch = /:\d+$/.exec(match[2]);
|
|
1296
1280
|
const normalizedHost = portMatch == null ? domainToASCII(match[2].toLowerCase()) : domainToASCII(match[2].substring(0, portMatch.index).toLowerCase()) + portMatch[0];
|
|
1297
|
-
if (normalizedHost != context
|
|
1281
|
+
if (normalizedHost != context.url.host && normalizedHost != host) return await onNotFound(request);
|
|
1298
1282
|
else {
|
|
1299
1283
|
identifier = await mapUsernameToIdentifier(match[1]);
|
|
1300
1284
|
resourceUrl = new URL(`acct:${match[1]}@${normalizedHost}`);
|
|
@@ -1302,14 +1286,14 @@ async function handleWebFingerInternal(request, { context: context$1, host, acto
|
|
|
1302
1286
|
}
|
|
1303
1287
|
} else identifier = uriParsed.identifier;
|
|
1304
1288
|
if (identifier == null) return await onNotFound(request);
|
|
1305
|
-
const actor = await actorDispatcher(context
|
|
1289
|
+
const actor = await actorDispatcher(context, identifier);
|
|
1306
1290
|
if (actor == null) {
|
|
1307
1291
|
logger.error("Actor {identifier} not found.", { identifier });
|
|
1308
1292
|
return await onNotFound(request);
|
|
1309
1293
|
}
|
|
1310
1294
|
const links = [{
|
|
1311
1295
|
rel: "self",
|
|
1312
|
-
href: context
|
|
1296
|
+
href: context.getActorUri(identifier).href,
|
|
1313
1297
|
type: "application/activity+json"
|
|
1314
1298
|
}];
|
|
1315
1299
|
for (const url of actor.urls) if (url instanceof Link && url.href != null) links.push({
|
|
@@ -1330,16 +1314,16 @@ async function handleWebFingerInternal(request, { context: context$1, host, acto
|
|
|
1330
1314
|
});
|
|
1331
1315
|
}
|
|
1332
1316
|
if (webFingerLinksDispatcher != null) {
|
|
1333
|
-
const customLinks = await webFingerLinksDispatcher(context
|
|
1317
|
+
const customLinks = await webFingerLinksDispatcher(context, resourceUrl);
|
|
1334
1318
|
if (customLinks != null) for (const link of customLinks) links.push(link);
|
|
1335
1319
|
}
|
|
1336
1320
|
const aliases = [];
|
|
1337
1321
|
if (resourceUrl.protocol != "acct:" && actor.preferredUsername != null) {
|
|
1338
|
-
aliases.push(`acct:${actor.preferredUsername}@${host ?? context
|
|
1339
|
-
if (host != null && host !== context
|
|
1322
|
+
aliases.push(`acct:${actor.preferredUsername}@${host ?? context.url.host}`);
|
|
1323
|
+
if (host != null && host !== context.url.host) aliases.push(`acct:${actor.preferredUsername}@${context.url.host}`);
|
|
1340
1324
|
}
|
|
1341
|
-
if (resourceUrl.href !== context
|
|
1342
|
-
if (resourceUrl.protocol === "acct:" && host != null && host !== context
|
|
1325
|
+
if (resourceUrl.href !== context.getActorUri(identifier).href) aliases.push(context.getActorUri(identifier).href);
|
|
1326
|
+
if (resourceUrl.protocol === "acct:" && host != null && host !== context.url.host && !resourceUrl.href.endsWith(`@${host}`)) {
|
|
1343
1327
|
const username = resourceUrl.href.replace(/^acct:/, "").replace(/@.*$/, "");
|
|
1344
1328
|
aliases.push(`acct:${username}@${host}`);
|
|
1345
1329
|
}
|
|
@@ -1353,7 +1337,6 @@ async function handleWebFingerInternal(request, { context: context$1, host, acto
|
|
|
1353
1337
|
"Access-Control-Allow-Origin": "*"
|
|
1354
1338
|
} });
|
|
1355
1339
|
}
|
|
1356
|
-
|
|
1357
1340
|
//#endregion
|
|
1358
1341
|
//#region src/federation/middleware.ts
|
|
1359
1342
|
/**
|
|
@@ -1484,28 +1467,28 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1484
1467
|
this.router.add("/.well-known/nodeinfo", "nodeInfoJrd");
|
|
1485
1468
|
}
|
|
1486
1469
|
_getTracer() {
|
|
1487
|
-
return this.tracerProvider.getTracer(
|
|
1470
|
+
return this.tracerProvider.getTracer(name, version);
|
|
1488
1471
|
}
|
|
1489
1472
|
async _startQueueInternal(ctxData, signal, queue) {
|
|
1490
1473
|
if (this.inboxQueue == null && this.outboxQueue == null) return;
|
|
1491
|
-
const logger
|
|
1474
|
+
const logger = getLogger([
|
|
1492
1475
|
"fedify",
|
|
1493
1476
|
"federation",
|
|
1494
1477
|
"queue"
|
|
1495
1478
|
]);
|
|
1496
1479
|
const promises = [];
|
|
1497
1480
|
if (this.inboxQueue != null && (queue == null || queue === "inbox") && !this.inboxQueueStarted) {
|
|
1498
|
-
logger
|
|
1481
|
+
logger.debug("Starting an inbox task worker.");
|
|
1499
1482
|
this.inboxQueueStarted = true;
|
|
1500
1483
|
promises.push(this.inboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
|
|
1501
1484
|
}
|
|
1502
1485
|
if (this.outboxQueue != null && this.outboxQueue !== this.inboxQueue && (queue == null || queue === "outbox") && !this.outboxQueueStarted) {
|
|
1503
|
-
logger
|
|
1486
|
+
logger.debug("Starting an outbox task worker.");
|
|
1504
1487
|
this.outboxQueueStarted = true;
|
|
1505
1488
|
promises.push(this.outboxQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
|
|
1506
1489
|
}
|
|
1507
1490
|
if (this.fanoutQueue != null && this.fanoutQueue !== this.inboxQueue && this.fanoutQueue !== this.outboxQueue && (queue == null || queue === "fanout") && !this.fanoutQueueStarted) {
|
|
1508
|
-
logger
|
|
1491
|
+
logger.debug("Starting a fanout task worker.");
|
|
1509
1492
|
this.fanoutQueueStarted = true;
|
|
1510
1493
|
promises.push(this.fanoutQueue.listen((msg) => this.processQueuedTask(ctxData, msg), { signal }));
|
|
1511
1494
|
}
|
|
@@ -1589,12 +1572,11 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1589
1572
|
});
|
|
1590
1573
|
}
|
|
1591
1574
|
async #listenFanoutMessage(data, message) {
|
|
1592
|
-
|
|
1575
|
+
getLogger([
|
|
1593
1576
|
"fedify",
|
|
1594
1577
|
"federation",
|
|
1595
1578
|
"fanout"
|
|
1596
|
-
])
|
|
1597
|
-
logger$2.debug("Fanning out activity {activityId} to {inboxes} inbox(es)...", {
|
|
1579
|
+
]).debug("Fanning out activity {activityId} to {inboxes} inbox(es)...", {
|
|
1598
1580
|
activityId: message.activityId,
|
|
1599
1581
|
inboxes: globalThis.Object.keys(message.inboxes).length
|
|
1600
1582
|
});
|
|
@@ -1613,18 +1595,18 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1613
1595
|
}),
|
|
1614
1596
|
tracerProvider: this.tracerProvider
|
|
1615
1597
|
});
|
|
1616
|
-
const context
|
|
1598
|
+
const context = this.#createContext(new URL(message.baseUrl), data, { documentLoader: this.documentLoaderFactory({
|
|
1617
1599
|
allowPrivateAddress: this.allowPrivateAddress,
|
|
1618
1600
|
userAgent: this.userAgent
|
|
1619
1601
|
}) });
|
|
1620
1602
|
await this.sendActivity(keys, message.inboxes, activity, {
|
|
1621
1603
|
collectionSync: message.collectionSync,
|
|
1622
1604
|
orderingKey: message.orderingKey,
|
|
1623
|
-
context
|
|
1605
|
+
context
|
|
1624
1606
|
});
|
|
1625
1607
|
}
|
|
1626
1608
|
async #listenOutboxMessage(_, message, span) {
|
|
1627
|
-
const logger
|
|
1609
|
+
const logger = getLogger([
|
|
1628
1610
|
"fedify",
|
|
1629
1611
|
"federation",
|
|
1630
1612
|
"outbox"
|
|
@@ -1672,14 +1654,14 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1672
1654
|
});
|
|
1673
1655
|
try {
|
|
1674
1656
|
await this.onOutboxError?.(error, activity);
|
|
1675
|
-
} catch (error
|
|
1676
|
-
logger
|
|
1657
|
+
} catch (error) {
|
|
1658
|
+
logger.error("An unexpected error occurred in onError handler:\n{error}", {
|
|
1677
1659
|
...logData,
|
|
1678
|
-
error
|
|
1660
|
+
error
|
|
1679
1661
|
});
|
|
1680
1662
|
}
|
|
1681
1663
|
if (error instanceof SendActivityError && this.permanentFailureStatusCodes.includes(error.statusCode)) {
|
|
1682
|
-
logger
|
|
1664
|
+
logger.warn("Permanent delivery failure for activity {activityId} to {inbox} ({status}); not retrying.", {
|
|
1683
1665
|
...logData,
|
|
1684
1666
|
status: error.statusCode
|
|
1685
1667
|
});
|
|
@@ -1695,13 +1677,13 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1695
1677
|
try {
|
|
1696
1678
|
return [new URL(id)];
|
|
1697
1679
|
} catch {
|
|
1698
|
-
logger
|
|
1680
|
+
logger.warn("Invalid actorId URL in OutboxMessage: {id}", { id });
|
|
1699
1681
|
return [];
|
|
1700
1682
|
}
|
|
1701
1683
|
})
|
|
1702
1684
|
});
|
|
1703
1685
|
} catch (handlerError) {
|
|
1704
|
-
logger
|
|
1686
|
+
logger.error("An unexpected error occurred in outboxPermanentFailureHandler:\n{error}", {
|
|
1705
1687
|
...logData,
|
|
1706
1688
|
error: handlerError
|
|
1707
1689
|
});
|
|
@@ -1710,58 +1692,57 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1710
1692
|
return;
|
|
1711
1693
|
}
|
|
1712
1694
|
if (this.outboxQueue?.nativeRetrial) {
|
|
1713
|
-
logger
|
|
1695
|
+
logger.error("Failed to send activity {activityId} to {inbox}; backend will handle retry:\n{error}", {
|
|
1714
1696
|
...logData,
|
|
1715
1697
|
error
|
|
1716
1698
|
});
|
|
1717
1699
|
throw error;
|
|
1718
1700
|
}
|
|
1719
|
-
const delay
|
|
1701
|
+
const delay = this.outboxRetryPolicy({
|
|
1720
1702
|
elapsedTime: Temporal.Instant.from(message.started).until(Temporal.Now.instant()),
|
|
1721
1703
|
attempts: message.attempt
|
|
1722
1704
|
});
|
|
1723
|
-
if (delay
|
|
1724
|
-
logger
|
|
1705
|
+
if (delay != null) {
|
|
1706
|
+
logger.error("Failed to send activity {activityId} to {inbox} (attempt #{attempt}); retry...:\n{error}", {
|
|
1725
1707
|
...logData,
|
|
1726
1708
|
error
|
|
1727
1709
|
});
|
|
1728
1710
|
await this.outboxQueue?.enqueue({
|
|
1729
1711
|
...message,
|
|
1730
1712
|
attempt: message.attempt + 1
|
|
1731
|
-
}, { delay: Temporal.Duration.compare(delay
|
|
1732
|
-
} else logger
|
|
1713
|
+
}, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
|
|
1714
|
+
} else logger.error("Failed to send activity {activityId} to {inbox} after {attempt} attempts; giving up:\n{error}", {
|
|
1733
1715
|
...logData,
|
|
1734
1716
|
error
|
|
1735
1717
|
});
|
|
1736
1718
|
return;
|
|
1737
1719
|
}
|
|
1738
|
-
logger
|
|
1720
|
+
logger.info("Successfully sent activity {activityId} to {inbox}.", { ...logData });
|
|
1739
1721
|
}
|
|
1740
1722
|
async #listenInboxMessage(ctxData, message, span) {
|
|
1741
|
-
const logger
|
|
1723
|
+
const logger = getLogger([
|
|
1742
1724
|
"fedify",
|
|
1743
1725
|
"federation",
|
|
1744
1726
|
"inbox"
|
|
1745
1727
|
]);
|
|
1746
1728
|
const baseUrl = new URL(message.baseUrl);
|
|
1747
|
-
let context
|
|
1748
|
-
if (message.identifier != null) context
|
|
1729
|
+
let context = this.#createContext(baseUrl, ctxData);
|
|
1730
|
+
if (message.identifier != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: await context.getDocumentLoader({ identifier: message.identifier }) });
|
|
1749
1731
|
else if (this.sharedInboxKeyDispatcher != null) {
|
|
1750
|
-
const identity = await this.sharedInboxKeyDispatcher(context
|
|
1751
|
-
if (identity != null) context
|
|
1732
|
+
const identity = await this.sharedInboxKeyDispatcher(context);
|
|
1733
|
+
if (identity != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
1752
1734
|
}
|
|
1753
|
-
const activity = await Activity.fromJsonLd(message.activity, context
|
|
1735
|
+
const activity = await Activity.fromJsonLd(message.activity, context);
|
|
1754
1736
|
span.setAttribute("activitypub.activity.type", getTypeId(activity).href);
|
|
1755
1737
|
if (activity.id != null) span.setAttribute("activitypub.activity.id", activity.id.href);
|
|
1756
1738
|
const cacheKey = activity.id == null ? null : [
|
|
1757
1739
|
...this.kvPrefixes.activityIdempotence,
|
|
1758
|
-
context
|
|
1740
|
+
context.origin,
|
|
1759
1741
|
activity.id.href
|
|
1760
1742
|
];
|
|
1761
1743
|
if (cacheKey != null) {
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
logger$2.debug("Activity {activityId} has already been processed.", {
|
|
1744
|
+
if (await this.kv.get(cacheKey) === true) {
|
|
1745
|
+
logger.debug("Activity {activityId} has already been processed.", {
|
|
1765
1746
|
activityId: activity.id?.href,
|
|
1766
1747
|
activity: message.activity,
|
|
1767
1748
|
recipient: message.identifier
|
|
@@ -1769,32 +1750,32 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1769
1750
|
return;
|
|
1770
1751
|
}
|
|
1771
1752
|
}
|
|
1772
|
-
await this._getTracer().startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span
|
|
1753
|
+
await this._getTracer().startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span) => {
|
|
1773
1754
|
const dispatched = this.inboxListeners?.dispatchWithClass(activity);
|
|
1774
1755
|
if (dispatched == null) {
|
|
1775
|
-
logger
|
|
1756
|
+
logger.error("Unsupported activity type:\n{activity}", {
|
|
1776
1757
|
activityId: activity.id?.href,
|
|
1777
1758
|
activity: message.activity,
|
|
1778
1759
|
recipient: message.identifier,
|
|
1779
1760
|
trial: message.attempt
|
|
1780
1761
|
});
|
|
1781
|
-
span
|
|
1762
|
+
span.setStatus({
|
|
1782
1763
|
code: SpanStatusCode.ERROR,
|
|
1783
1764
|
message: `Unsupported activity type: ${getTypeId(activity).href}`
|
|
1784
1765
|
});
|
|
1785
|
-
span
|
|
1766
|
+
span.end();
|
|
1786
1767
|
return;
|
|
1787
1768
|
}
|
|
1788
1769
|
const { class: cls, listener } = dispatched;
|
|
1789
|
-
span
|
|
1770
|
+
span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
|
|
1790
1771
|
try {
|
|
1791
|
-
await listener(context
|
|
1772
|
+
await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, getTypeId(activity).href), activity);
|
|
1792
1773
|
} catch (error) {
|
|
1793
1774
|
try {
|
|
1794
|
-
await this.inboxErrorHandler?.(context
|
|
1795
|
-
} catch (error
|
|
1796
|
-
logger
|
|
1797
|
-
error
|
|
1775
|
+
await this.inboxErrorHandler?.(context, error);
|
|
1776
|
+
} catch (error) {
|
|
1777
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
1778
|
+
error,
|
|
1798
1779
|
trial: message.attempt,
|
|
1799
1780
|
activityId: activity.id?.href,
|
|
1800
1781
|
activity: message.activity,
|
|
@@ -1802,25 +1783,25 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1802
1783
|
});
|
|
1803
1784
|
}
|
|
1804
1785
|
if (this.inboxQueue?.nativeRetrial) {
|
|
1805
|
-
logger
|
|
1786
|
+
logger.error("Failed to process the incoming activity {activityId}; backend will handle retry:\n{error}", {
|
|
1806
1787
|
error,
|
|
1807
1788
|
activityId: activity.id?.href,
|
|
1808
1789
|
activity: message.activity,
|
|
1809
1790
|
recipient: message.identifier
|
|
1810
1791
|
});
|
|
1811
|
-
span
|
|
1792
|
+
span.setStatus({
|
|
1812
1793
|
code: SpanStatusCode.ERROR,
|
|
1813
1794
|
message: String(error)
|
|
1814
1795
|
});
|
|
1815
|
-
span
|
|
1796
|
+
span.end();
|
|
1816
1797
|
throw error;
|
|
1817
1798
|
}
|
|
1818
|
-
const delay
|
|
1799
|
+
const delay = this.inboxRetryPolicy({
|
|
1819
1800
|
elapsedTime: Temporal.Instant.from(message.started).until(Temporal.Now.instant()),
|
|
1820
1801
|
attempts: message.attempt
|
|
1821
1802
|
});
|
|
1822
|
-
if (delay
|
|
1823
|
-
logger
|
|
1803
|
+
if (delay != null) {
|
|
1804
|
+
logger.error("Failed to process the incoming activity {activityId} (attempt #{attempt}); retry...:\n{error}", {
|
|
1824
1805
|
error,
|
|
1825
1806
|
attempt: message.attempt,
|
|
1826
1807
|
activityId: activity.id?.href,
|
|
@@ -1830,27 +1811,27 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1830
1811
|
await this.inboxQueue?.enqueue({
|
|
1831
1812
|
...message,
|
|
1832
1813
|
attempt: message.attempt + 1
|
|
1833
|
-
}, { delay: Temporal.Duration.compare(delay
|
|
1834
|
-
} else logger
|
|
1814
|
+
}, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
|
|
1815
|
+
} else logger.error("Failed to process the incoming activity {activityId} after {trial} attempts; giving up:\n{error}", {
|
|
1835
1816
|
error,
|
|
1836
1817
|
activityId: activity.id?.href,
|
|
1837
1818
|
activity: message.activity,
|
|
1838
1819
|
recipient: message.identifier
|
|
1839
1820
|
});
|
|
1840
|
-
span
|
|
1821
|
+
span.setStatus({
|
|
1841
1822
|
code: SpanStatusCode.ERROR,
|
|
1842
1823
|
message: String(error)
|
|
1843
1824
|
});
|
|
1844
|
-
span
|
|
1825
|
+
span.end();
|
|
1845
1826
|
return;
|
|
1846
1827
|
}
|
|
1847
1828
|
if (cacheKey != null) await this.kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
|
|
1848
|
-
logger
|
|
1829
|
+
logger.info("Activity {activityId} has been processed.", {
|
|
1849
1830
|
activityId: activity.id?.href,
|
|
1850
1831
|
activity: message.activity,
|
|
1851
1832
|
recipient: message.identifier
|
|
1852
1833
|
});
|
|
1853
|
-
span
|
|
1834
|
+
span.end();
|
|
1854
1835
|
});
|
|
1855
1836
|
}
|
|
1856
1837
|
startQueue(contextData, options = {}) {
|
|
@@ -1894,7 +1875,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1894
1875
|
};
|
|
1895
1876
|
}
|
|
1896
1877
|
async sendActivity(keys, inboxes, activity, options) {
|
|
1897
|
-
const logger
|
|
1878
|
+
const logger = getLogger([
|
|
1898
1879
|
"fedify",
|
|
1899
1880
|
"federation",
|
|
1900
1881
|
"outbox"
|
|
@@ -1928,7 +1909,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1928
1909
|
format: "compact",
|
|
1929
1910
|
contextLoader
|
|
1930
1911
|
});
|
|
1931
|
-
if (rsaKey == null) logger
|
|
1912
|
+
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.", {
|
|
1932
1913
|
activityId,
|
|
1933
1914
|
keys: keys.map((pair) => ({
|
|
1934
1915
|
keyId: pair.keyId.href,
|
|
@@ -1939,7 +1920,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1939
1920
|
contextLoader,
|
|
1940
1921
|
tracerProvider: this.tracerProvider
|
|
1941
1922
|
});
|
|
1942
|
-
if (!proofCreated) logger
|
|
1923
|
+
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.", {
|
|
1943
1924
|
activityId,
|
|
1944
1925
|
keys: keys.map((pair) => ({
|
|
1945
1926
|
keyId: pair.keyId.href,
|
|
@@ -1947,11 +1928,11 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1947
1928
|
}))
|
|
1948
1929
|
});
|
|
1949
1930
|
if (immediate || this.outboxQueue == null) {
|
|
1950
|
-
if (immediate) logger
|
|
1931
|
+
if (immediate) logger.debug("Sending activity immediately without queue since immediate option is set.", {
|
|
1951
1932
|
activityId: activity.id.href,
|
|
1952
1933
|
activity: jsonLd
|
|
1953
1934
|
});
|
|
1954
|
-
else logger
|
|
1935
|
+
else logger.debug("Sending activity immediately without queue since queue is not set.", {
|
|
1955
1936
|
activityId: activity.id.href,
|
|
1956
1937
|
activity: jsonLd
|
|
1957
1938
|
});
|
|
@@ -1970,7 +1951,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1970
1951
|
await Promise.all(promises);
|
|
1971
1952
|
return;
|
|
1972
1953
|
}
|
|
1973
|
-
logger
|
|
1954
|
+
logger.debug("Enqueuing activity {activityId} to send later.", {
|
|
1974
1955
|
activityId: activity.id.href,
|
|
1975
1956
|
activity: jsonLd
|
|
1976
1957
|
});
|
|
@@ -2014,10 +1995,9 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2014
1995
|
const { outboxQueue } = this;
|
|
2015
1996
|
if (outboxQueue.enqueueMany == null) {
|
|
2016
1997
|
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
2017
|
-
const
|
|
2018
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
1998
|
+
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2019
1999
|
if (errors.length > 0) {
|
|
2020
|
-
logger
|
|
2000
|
+
logger.error("Failed to enqueue activity {activityId} to send later: {errors}", {
|
|
2021
2001
|
activityId: activity.id.href,
|
|
2022
2002
|
errors
|
|
2023
2003
|
});
|
|
@@ -2026,10 +2006,9 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2026
2006
|
}
|
|
2027
2007
|
} else if (orderingKey != null) {
|
|
2028
2008
|
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
2029
|
-
const
|
|
2030
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2009
|
+
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
2031
2010
|
if (errors.length > 0) {
|
|
2032
|
-
logger
|
|
2011
|
+
logger.error("Failed to enqueue activity {activityId} to send later: {errors}", {
|
|
2033
2012
|
activityId: activity.id.href,
|
|
2034
2013
|
errors
|
|
2035
2014
|
});
|
|
@@ -2039,7 +2018,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2039
2018
|
} else try {
|
|
2040
2019
|
await outboxQueue.enqueueMany(messages.map((m) => m.message));
|
|
2041
2020
|
} catch (error) {
|
|
2042
|
-
logger
|
|
2021
|
+
logger.error("Failed to enqueue activity {activityId} to send later: {error}", {
|
|
2043
2022
|
activityId: activity.id.href,
|
|
2044
2023
|
error
|
|
2045
2024
|
});
|
|
@@ -2047,8 +2026,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2047
2026
|
}
|
|
2048
2027
|
}
|
|
2049
2028
|
fetch(request, options) {
|
|
2050
|
-
|
|
2051
|
-
return withContext({ requestId }, async () => {
|
|
2029
|
+
return withContext({ requestId: getRequestId(request) }, async () => {
|
|
2052
2030
|
const tracer = this._getTracer();
|
|
2053
2031
|
return await tracer.startActiveSpan(request.method, {
|
|
2054
2032
|
kind: SpanKind.SERVER,
|
|
@@ -2062,7 +2040,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2062
2040
|
traceId: spanCtx.traceId,
|
|
2063
2041
|
spanId: spanCtx.spanId
|
|
2064
2042
|
}, async () => {
|
|
2065
|
-
const logger
|
|
2043
|
+
const logger = getLogger([
|
|
2066
2044
|
"fedify",
|
|
2067
2045
|
"federation",
|
|
2068
2046
|
"http"
|
|
@@ -2082,7 +2060,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2082
2060
|
message: `${error}`
|
|
2083
2061
|
});
|
|
2084
2062
|
span.end();
|
|
2085
|
-
logger
|
|
2063
|
+
logger.error("An error occurred while serving request {method} {url}: {error}", {
|
|
2086
2064
|
method: request.method,
|
|
2087
2065
|
url: request.url,
|
|
2088
2066
|
error
|
|
@@ -2106,9 +2084,9 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2106
2084
|
url: request.url,
|
|
2107
2085
|
status: response.status
|
|
2108
2086
|
};
|
|
2109
|
-
if (response.status >= 500) logger
|
|
2110
|
-
else if (response.status >= 400) logger
|
|
2111
|
-
else logger
|
|
2087
|
+
if (response.status >= 500) logger.error(logTpl, values);
|
|
2088
|
+
else if (response.status >= 400) logger.warn(logTpl, values);
|
|
2089
|
+
else logger.info(logTpl, values);
|
|
2112
2090
|
return response;
|
|
2113
2091
|
});
|
|
2114
2092
|
});
|
|
@@ -2122,11 +2100,11 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2122
2100
|
const route = this.router.route(url.pathname);
|
|
2123
2101
|
if (route == null) return await onNotFound(request);
|
|
2124
2102
|
span.updateName(`${request.method} ${route.template}`);
|
|
2125
|
-
let context
|
|
2103
|
+
let context = this.#createContext(request, contextData);
|
|
2126
2104
|
const routeName = route.name.replace(/:.*$/, "");
|
|
2127
2105
|
switch (routeName) {
|
|
2128
2106
|
case "webfinger": return await handleWebFinger(request, {
|
|
2129
|
-
context
|
|
2107
|
+
context,
|
|
2130
2108
|
host: this.origin?.handleHost,
|
|
2131
2109
|
actorDispatcher: this.actorCallbacks?.dispatcher,
|
|
2132
2110
|
actorHandleMapper: this.actorCallbacks?.handleMapper,
|
|
@@ -2135,19 +2113,19 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2135
2113
|
onNotFound,
|
|
2136
2114
|
tracer
|
|
2137
2115
|
});
|
|
2138
|
-
case "nodeInfoJrd": return await handleNodeInfoJrd(request, context
|
|
2116
|
+
case "nodeInfoJrd": return await handleNodeInfoJrd(request, context);
|
|
2139
2117
|
case "nodeInfo": return await handleNodeInfo(request, {
|
|
2140
|
-
context
|
|
2118
|
+
context,
|
|
2141
2119
|
nodeInfoDispatcher: this.nodeInfoDispatcher
|
|
2142
2120
|
});
|
|
2143
2121
|
}
|
|
2144
2122
|
if (request.method !== "POST" && !acceptsJsonLd(request)) return await onNotAcceptable(request);
|
|
2145
2123
|
switch (routeName) {
|
|
2146
2124
|
case "actor":
|
|
2147
|
-
context
|
|
2125
|
+
context = this.#createContext(request, contextData, { invokedFromActorDispatcher: { identifier: route.values.identifier } });
|
|
2148
2126
|
return await handleActor(request, {
|
|
2149
2127
|
identifier: route.values.identifier,
|
|
2150
|
-
context
|
|
2128
|
+
context,
|
|
2151
2129
|
actorDispatcher: this.actorCallbacks?.dispatcher,
|
|
2152
2130
|
authorizePredicate: this.actorCallbacks?.authorizePredicate,
|
|
2153
2131
|
onUnauthorized,
|
|
@@ -2157,13 +2135,13 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2157
2135
|
const typeId = route.name.replace(/^object:/, "");
|
|
2158
2136
|
const callbacks = this.objectCallbacks[typeId];
|
|
2159
2137
|
const cls = this.objectTypeIds[typeId];
|
|
2160
|
-
context
|
|
2138
|
+
context = this.#createContext(request, contextData, { invokedFromObjectDispatcher: {
|
|
2161
2139
|
cls,
|
|
2162
2140
|
values: route.values
|
|
2163
2141
|
} });
|
|
2164
2142
|
return await handleObject(request, {
|
|
2165
2143
|
values: route.values,
|
|
2166
|
-
context
|
|
2144
|
+
context,
|
|
2167
2145
|
objectDispatcher: callbacks?.dispatcher,
|
|
2168
2146
|
authorizePredicate: callbacks?.authorizePredicate,
|
|
2169
2147
|
onUnauthorized,
|
|
@@ -2173,8 +2151,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2173
2151
|
case "outbox": return await handleCollection(request, {
|
|
2174
2152
|
name: "outbox",
|
|
2175
2153
|
identifier: route.values.identifier,
|
|
2176
|
-
uriGetter: context
|
|
2177
|
-
context
|
|
2154
|
+
uriGetter: context.getOutboxUri.bind(context),
|
|
2155
|
+
context,
|
|
2178
2156
|
collectionCallbacks: this.outboxCallbacks,
|
|
2179
2157
|
tracerProvider: this.tracerProvider,
|
|
2180
2158
|
onUnauthorized,
|
|
@@ -2184,24 +2162,24 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2184
2162
|
if (request.method !== "POST") return await handleCollection(request, {
|
|
2185
2163
|
name: "inbox",
|
|
2186
2164
|
identifier: route.values.identifier,
|
|
2187
|
-
uriGetter: context
|
|
2188
|
-
context
|
|
2165
|
+
uriGetter: context.getInboxUri.bind(context),
|
|
2166
|
+
context,
|
|
2189
2167
|
collectionCallbacks: this.inboxCallbacks,
|
|
2190
2168
|
tracerProvider: this.tracerProvider,
|
|
2191
2169
|
onUnauthorized,
|
|
2192
2170
|
onNotFound
|
|
2193
2171
|
});
|
|
2194
|
-
context
|
|
2172
|
+
context = this.#createContext(request, contextData, { documentLoader: await context.getDocumentLoader({ identifier: route.values.identifier }) });
|
|
2195
2173
|
case "sharedInbox":
|
|
2196
2174
|
if (routeName !== "inbox" && this.sharedInboxKeyDispatcher != null) {
|
|
2197
|
-
const identity = await this.sharedInboxKeyDispatcher(context
|
|
2198
|
-
if (identity != null) context
|
|
2175
|
+
const identity = await this.sharedInboxKeyDispatcher(context);
|
|
2176
|
+
if (identity != null) context = this.#createContext(request, contextData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
2199
2177
|
}
|
|
2200
2178
|
if (!this.manuallyStartQueue) this._startQueueInternal(contextData);
|
|
2201
2179
|
return await handleInbox(request, {
|
|
2202
2180
|
recipient: route.values.identifier ?? null,
|
|
2203
|
-
context
|
|
2204
|
-
inboxContextFactory: context
|
|
2181
|
+
context,
|
|
2182
|
+
inboxContextFactory: context.toInboxContext.bind(context),
|
|
2205
2183
|
kv: this.kv,
|
|
2206
2184
|
kvPrefixes: this.kvPrefixes,
|
|
2207
2185
|
queue: this.inboxQueue,
|
|
@@ -2219,8 +2197,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2219
2197
|
case "following": return await handleCollection(request, {
|
|
2220
2198
|
name: "following",
|
|
2221
2199
|
identifier: route.values.identifier,
|
|
2222
|
-
uriGetter: context
|
|
2223
|
-
context
|
|
2200
|
+
uriGetter: context.getFollowingUri.bind(context),
|
|
2201
|
+
context,
|
|
2224
2202
|
collectionCallbacks: this.followingCallbacks,
|
|
2225
2203
|
tracerProvider: this.tracerProvider,
|
|
2226
2204
|
onUnauthorized,
|
|
@@ -2236,14 +2214,14 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2236
2214
|
return await handleCollection(request, {
|
|
2237
2215
|
name: "followers",
|
|
2238
2216
|
identifier: route.values.identifier,
|
|
2239
|
-
uriGetter: baseUrl == null ? context
|
|
2240
|
-
const uri = context
|
|
2217
|
+
uriGetter: baseUrl == null ? context.getFollowersUri.bind(context) : (identifier) => {
|
|
2218
|
+
const uri = context.getFollowersUri(identifier);
|
|
2241
2219
|
uri.searchParams.set("base-url", baseUrl);
|
|
2242
2220
|
return uri;
|
|
2243
2221
|
},
|
|
2244
|
-
context
|
|
2222
|
+
context,
|
|
2245
2223
|
filter: baseUrl != null ? new URL(baseUrl) : void 0,
|
|
2246
|
-
filterPredicate: baseUrl != null ? (i) => (i instanceof URL ? i.href : i.id?.href ?? "").startsWith(baseUrl) : void 0,
|
|
2224
|
+
filterPredicate: baseUrl != null ? ((i) => (i instanceof URL ? i.href : i.id?.href ?? "").startsWith(baseUrl)) : void 0,
|
|
2247
2225
|
collectionCallbacks: this.followersCallbacks,
|
|
2248
2226
|
tracerProvider: this.tracerProvider,
|
|
2249
2227
|
onUnauthorized,
|
|
@@ -2253,8 +2231,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2253
2231
|
case "liked": return await handleCollection(request, {
|
|
2254
2232
|
name: "liked",
|
|
2255
2233
|
identifier: route.values.identifier,
|
|
2256
|
-
uriGetter: context
|
|
2257
|
-
context
|
|
2234
|
+
uriGetter: context.getLikedUri.bind(context),
|
|
2235
|
+
context,
|
|
2258
2236
|
collectionCallbacks: this.likedCallbacks,
|
|
2259
2237
|
tracerProvider: this.tracerProvider,
|
|
2260
2238
|
onUnauthorized,
|
|
@@ -2263,8 +2241,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2263
2241
|
case "featured": return await handleCollection(request, {
|
|
2264
2242
|
name: "featured",
|
|
2265
2243
|
identifier: route.values.identifier,
|
|
2266
|
-
uriGetter: context
|
|
2267
|
-
context
|
|
2244
|
+
uriGetter: context.getFeaturedUri.bind(context),
|
|
2245
|
+
context,
|
|
2268
2246
|
collectionCallbacks: this.featuredCallbacks,
|
|
2269
2247
|
tracerProvider: this.tracerProvider,
|
|
2270
2248
|
onUnauthorized,
|
|
@@ -2273,8 +2251,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2273
2251
|
case "featuredTags": return await handleCollection(request, {
|
|
2274
2252
|
name: "featured tags",
|
|
2275
2253
|
identifier: route.values.identifier,
|
|
2276
|
-
uriGetter: context
|
|
2277
|
-
context
|
|
2254
|
+
uriGetter: context.getFeaturedTagsUri.bind(context),
|
|
2255
|
+
context,
|
|
2278
2256
|
collectionCallbacks: this.featuredTagsCallbacks,
|
|
2279
2257
|
tracerProvider: this.tracerProvider,
|
|
2280
2258
|
onUnauthorized,
|
|
@@ -2285,7 +2263,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2285
2263
|
const callbacks = this.collectionCallbacks[name];
|
|
2286
2264
|
return await handleCustomCollection(request, {
|
|
2287
2265
|
name,
|
|
2288
|
-
context
|
|
2266
|
+
context,
|
|
2289
2267
|
values: route.values,
|
|
2290
2268
|
collectionCallbacks: callbacks,
|
|
2291
2269
|
tracerProvider: this.tracerProvider,
|
|
@@ -2298,7 +2276,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2298
2276
|
const callbacks = this.collectionCallbacks[name];
|
|
2299
2277
|
return await handleOrderedCollection(request, {
|
|
2300
2278
|
name,
|
|
2301
|
-
context
|
|
2279
|
+
context,
|
|
2302
2280
|
values: route.values,
|
|
2303
2281
|
collectionCallbacks: callbacks,
|
|
2304
2282
|
tracerProvider: this.tracerProvider,
|
|
@@ -2389,9 +2367,9 @@ var ContextImpl = class ContextImpl {
|
|
|
2389
2367
|
}
|
|
2390
2368
|
getInboxUri(identifier) {
|
|
2391
2369
|
if (identifier == null) {
|
|
2392
|
-
const path
|
|
2393
|
-
if (path
|
|
2394
|
-
return new URL(path
|
|
2370
|
+
const path = this.federation.router.build("sharedInbox", {});
|
|
2371
|
+
if (path == null) throw new RouterError("No shared inbox path registered.");
|
|
2372
|
+
return new URL(path, this.canonicalOrigin);
|
|
2395
2373
|
}
|
|
2396
2374
|
const path = this.federation.router.build("inbox", { identifier });
|
|
2397
2375
|
if (path == null) throw new RouterError("No inbox path registered.");
|
|
@@ -2477,8 +2455,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2477
2455
|
type: "featuredTags",
|
|
2478
2456
|
identifier
|
|
2479
2457
|
};
|
|
2480
|
-
const
|
|
2481
|
-
const collectionRegex = /* @__PURE__ */ new RegExp(`^(${collectionTypes.join("|")}):(.*)$`);
|
|
2458
|
+
const collectionRegex = new RegExp(`^(${["collection", "orderedCollection"].join("|")}):(.*)$`);
|
|
2482
2459
|
const match = route.name.match(collectionRegex);
|
|
2483
2460
|
if (match !== null) {
|
|
2484
2461
|
const [, type, name] = match;
|
|
@@ -2494,12 +2471,12 @@ var ContextImpl = class ContextImpl {
|
|
|
2494
2471
|
return null;
|
|
2495
2472
|
}
|
|
2496
2473
|
async getActorKeyPairs(identifier) {
|
|
2497
|
-
const logger
|
|
2474
|
+
const logger = getLogger([
|
|
2498
2475
|
"fedify",
|
|
2499
2476
|
"federation",
|
|
2500
2477
|
"actor"
|
|
2501
2478
|
]);
|
|
2502
|
-
if (this.invokedFromActorKeyPairsDispatcher != null) logger
|
|
2479
|
+
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.", {
|
|
2503
2480
|
getActorKeyPairsIdentifier: identifier,
|
|
2504
2481
|
actorKeyPairsDispatcherIdentifier: this.invokedFromActorKeyPairsDispatcher.identifier
|
|
2505
2482
|
});
|
|
@@ -2507,7 +2484,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2507
2484
|
try {
|
|
2508
2485
|
keyPairs = await this.getKeyPairsFromIdentifier(identifier);
|
|
2509
2486
|
} catch (_) {
|
|
2510
|
-
logger
|
|
2487
|
+
logger.warn("No actor key pairs dispatcher registered.");
|
|
2511
2488
|
return [];
|
|
2512
2489
|
}
|
|
2513
2490
|
const owner = this.getActorUri(identifier);
|
|
@@ -2531,7 +2508,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2531
2508
|
return result;
|
|
2532
2509
|
}
|
|
2533
2510
|
async getKeyPairsFromIdentifier(identifier) {
|
|
2534
|
-
const logger
|
|
2511
|
+
const logger = getLogger([
|
|
2535
2512
|
"fedify",
|
|
2536
2513
|
"federation",
|
|
2537
2514
|
"actor"
|
|
@@ -2542,7 +2519,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2542
2519
|
actorUri = this.getActorUri(identifier);
|
|
2543
2520
|
} catch (error) {
|
|
2544
2521
|
if (error instanceof RouterError) {
|
|
2545
|
-
logger
|
|
2522
|
+
logger.warn(error.message);
|
|
2546
2523
|
return [];
|
|
2547
2524
|
}
|
|
2548
2525
|
throw error;
|
|
@@ -2551,7 +2528,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2551
2528
|
...this,
|
|
2552
2529
|
invokedFromActorKeyPairsDispatcher: { identifier }
|
|
2553
2530
|
}), identifier);
|
|
2554
|
-
if (keyPairs.length < 1) logger
|
|
2531
|
+
if (keyPairs.length < 1) logger.warn("No key pairs found for actor {identifier}.", { identifier });
|
|
2555
2532
|
let i = 0;
|
|
2556
2533
|
const result = [];
|
|
2557
2534
|
for (const keyPair of keyPairs) {
|
|
@@ -2590,8 +2567,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2590
2567
|
} else identifierPromise = Promise.resolve(identity.identifier);
|
|
2591
2568
|
return identifierPromise.then((identifier) => {
|
|
2592
2569
|
if (identifier == null) return this.documentLoader;
|
|
2593
|
-
|
|
2594
|
-
return keyPair.then((pair) => pair == null ? this.documentLoader : this.federation.authenticatedDocumentLoaderFactory(pair));
|
|
2570
|
+
return this.getRsaKeyPairFromIdentifier(identifier).then((pair) => pair == null ? this.documentLoader : this.federation.authenticatedDocumentLoaderFactory(pair));
|
|
2595
2571
|
});
|
|
2596
2572
|
}
|
|
2597
2573
|
return this.federation.authenticatedDocumentLoaderFactory(identity);
|
|
@@ -2633,8 +2609,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2633
2609
|
});
|
|
2634
2610
|
}
|
|
2635
2611
|
sendActivity(sender, recipients, activity, options = {}) {
|
|
2636
|
-
|
|
2637
|
-
return tracer.startActiveSpan(this.federation.outboxQueue == null || options.immediate ? "activitypub.outbox" : "activitypub.fanout", {
|
|
2612
|
+
return this.tracerProvider.getTracer(name, version).startActiveSpan(this.federation.outboxQueue == null || options.immediate ? "activitypub.outbox" : "activitypub.fanout", {
|
|
2638
2613
|
kind: this.federation.outboxQueue == null || options.immediate ? SpanKind.CLIENT : SpanKind.PRODUCER,
|
|
2639
2614
|
attributes: {
|
|
2640
2615
|
"activitypub.activity.type": getTypeId(activity).href,
|
|
@@ -2659,7 +2634,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2659
2634
|
});
|
|
2660
2635
|
}
|
|
2661
2636
|
async sendActivityInternal(sender, recipients, activity, options, span) {
|
|
2662
|
-
const logger
|
|
2637
|
+
const logger = getLogger([
|
|
2663
2638
|
"fedify",
|
|
2664
2639
|
"federation",
|
|
2665
2640
|
"outbox"
|
|
@@ -2709,7 +2684,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2709
2684
|
for (const activityTransformer of this.federation.activityTransformers) activity = activityTransformer(activity, this);
|
|
2710
2685
|
span?.setAttribute("activitypub.activity.id", activity?.id?.href ?? "");
|
|
2711
2686
|
if (activity.actorId == null) {
|
|
2712
|
-
logger
|
|
2687
|
+
logger.error("Activity {activityId} to send does not have an actor.", {
|
|
2713
2688
|
activity,
|
|
2714
2689
|
activityId: activity?.id?.href
|
|
2715
2690
|
});
|
|
@@ -2720,7 +2695,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2720
2695
|
preferSharedInbox: options.preferSharedInbox,
|
|
2721
2696
|
excludeBaseUris: options.excludeBaseUris
|
|
2722
2697
|
});
|
|
2723
|
-
logger
|
|
2698
|
+
logger.debug("Sending activity {activityId} to inboxes:\n{inboxes}", {
|
|
2724
2699
|
inboxes: globalThis.Object.keys(inboxes),
|
|
2725
2700
|
activityId: activity.id?.href,
|
|
2726
2701
|
activity
|
|
@@ -2772,16 +2747,14 @@ var ContextImpl = class ContextImpl {
|
|
|
2772
2747
|
"outbox"
|
|
2773
2748
|
]).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 });
|
|
2774
2749
|
while (cursor != null) {
|
|
2775
|
-
const result
|
|
2776
|
-
if (result
|
|
2777
|
-
for (const recipient of result
|
|
2778
|
-
cursor = result
|
|
2750
|
+
const result = await this.federation.followersCallbacks.dispatcher(this, identifier, cursor);
|
|
2751
|
+
if (result == null) break;
|
|
2752
|
+
for (const recipient of result.items) yield recipient;
|
|
2753
|
+
cursor = result.nextCursor ?? null;
|
|
2779
2754
|
}
|
|
2780
2755
|
}
|
|
2781
2756
|
routeActivity(recipient, activity, options = {}) {
|
|
2782
|
-
|
|
2783
|
-
const tracer = tracerProvider.getTracer(deno_default.name, deno_default.version);
|
|
2784
|
-
return tracer.startActiveSpan("activitypub.inbox", {
|
|
2757
|
+
return (this.tracerProvider ?? this.tracerProvider).getTracer(name, version).startActiveSpan("activitypub.inbox", {
|
|
2785
2758
|
kind: this.federation.inboxQueue == null || options.immediate ? SpanKind.INTERNAL : SpanKind.PRODUCER,
|
|
2786
2759
|
attributes: { "activitypub.activity.type": getTypeId(activity).href }
|
|
2787
2760
|
}, async (span) => {
|
|
@@ -2809,7 +2782,7 @@ var ContextImpl = class ContextImpl {
|
|
|
2809
2782
|
});
|
|
2810
2783
|
}
|
|
2811
2784
|
async routeActivityInternal(recipient, activity, options = {}, span) {
|
|
2812
|
-
const logger
|
|
2785
|
+
const logger = getLogger([
|
|
2813
2786
|
"fedify",
|
|
2814
2787
|
"federation",
|
|
2815
2788
|
"inbox"
|
|
@@ -2817,19 +2790,18 @@ var ContextImpl = class ContextImpl {
|
|
|
2817
2790
|
const contextLoader = options.contextLoader ?? this.contextLoader;
|
|
2818
2791
|
const json = await activity.toJsonLd({ contextLoader });
|
|
2819
2792
|
const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, this);
|
|
2820
|
-
|
|
2793
|
+
if (await verifyObject(Activity, json, {
|
|
2821
2794
|
contextLoader,
|
|
2822
2795
|
documentLoader: options.documentLoader ?? this.documentLoader,
|
|
2823
2796
|
tracerProvider: options.tracerProvider ?? this.tracerProvider,
|
|
2824
2797
|
keyCache
|
|
2825
|
-
})
|
|
2826
|
-
|
|
2827
|
-
logger$2.debug("Object Integrity Proofs are not verified.", {
|
|
2798
|
+
}) == null) {
|
|
2799
|
+
logger.debug("Object Integrity Proofs are not verified.", {
|
|
2828
2800
|
recipient,
|
|
2829
2801
|
activity: json
|
|
2830
2802
|
});
|
|
2831
2803
|
if (activity.id == null) {
|
|
2832
|
-
logger
|
|
2804
|
+
logger.debug("Activity is missing an ID; unable to fetch.", {
|
|
2833
2805
|
recipient,
|
|
2834
2806
|
activity: json
|
|
2835
2807
|
});
|
|
@@ -2837,26 +2809,26 @@ var ContextImpl = class ContextImpl {
|
|
|
2837
2809
|
}
|
|
2838
2810
|
const fetched = await this.lookupObject(activity.id, options);
|
|
2839
2811
|
if (fetched == null) {
|
|
2840
|
-
logger
|
|
2812
|
+
logger.debug("Failed to fetch the remote activity object {activityId}.", {
|
|
2841
2813
|
recipient,
|
|
2842
2814
|
activity: json,
|
|
2843
2815
|
activityId: activity.id.href
|
|
2844
2816
|
});
|
|
2845
2817
|
return false;
|
|
2846
2818
|
} else if (!(fetched instanceof Activity)) {
|
|
2847
|
-
logger
|
|
2819
|
+
logger.debug("Fetched object is not an Activity.", {
|
|
2848
2820
|
recipient,
|
|
2849
2821
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
2850
2822
|
});
|
|
2851
2823
|
return false;
|
|
2852
2824
|
} else if (fetched.id?.href !== activity.id.href) {
|
|
2853
|
-
logger
|
|
2825
|
+
logger.debug("Fetched activity object has a different ID; failed to verify.", {
|
|
2854
2826
|
recipient,
|
|
2855
2827
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
2856
2828
|
});
|
|
2857
2829
|
return false;
|
|
2858
2830
|
} else if (fetched.actorIds.length < 1) {
|
|
2859
|
-
logger
|
|
2831
|
+
logger.debug("Fetched activity object is missing an actor; unable to verify.", {
|
|
2860
2832
|
recipient,
|
|
2861
2833
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
2862
2834
|
});
|
|
@@ -2864,15 +2836,15 @@ var ContextImpl = class ContextImpl {
|
|
|
2864
2836
|
}
|
|
2865
2837
|
const activityId = fetched.id;
|
|
2866
2838
|
if (!fetched.actorIds.every((actor) => actor.origin === activityId.origin)) {
|
|
2867
|
-
logger
|
|
2839
|
+
logger.debug("Fetched activity object has actors from different origins; unable to verify.", {
|
|
2868
2840
|
recipient,
|
|
2869
2841
|
activity: await fetched.toJsonLd({ contextLoader })
|
|
2870
2842
|
});
|
|
2871
2843
|
return false;
|
|
2872
2844
|
}
|
|
2873
|
-
logger
|
|
2845
|
+
logger.debug("Successfully fetched the remote activity object {activityId}; ignore the original activity and use the fetched one, which is trustworthy.");
|
|
2874
2846
|
activity = fetched;
|
|
2875
|
-
} else logger
|
|
2847
|
+
} else logger.debug("Object Integrity Proofs are verified.", {
|
|
2876
2848
|
recipient,
|
|
2877
2849
|
activity: json
|
|
2878
2850
|
});
|
|
@@ -3014,8 +2986,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3014
2986
|
});
|
|
3015
2987
|
}
|
|
3016
2988
|
forwardActivity(forwarder, recipients, options) {
|
|
3017
|
-
|
|
3018
|
-
return tracer.startActiveSpan("activitypub.outbox", {
|
|
2989
|
+
return this.tracerProvider.getTracer(name, version).startActiveSpan("activitypub.outbox", {
|
|
3019
2990
|
kind: this.federation.outboxQueue == null || options?.immediate ? SpanKind.CLIENT : SpanKind.PRODUCER,
|
|
3020
2991
|
attributes: { "activitypub.activity.type": this.activityType }
|
|
3021
2992
|
}, async (span) => {
|
|
@@ -3034,7 +3005,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3034
3005
|
});
|
|
3035
3006
|
}
|
|
3036
3007
|
async forwardActivityInternal(forwarder, recipients, options) {
|
|
3037
|
-
const logger
|
|
3008
|
+
const logger = getLogger([
|
|
3038
3009
|
"fedify",
|
|
3039
3010
|
"federation",
|
|
3040
3011
|
"inbox"
|
|
@@ -3061,14 +3032,13 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3061
3032
|
if (!hasSignature(this.activity)) {
|
|
3062
3033
|
let hasProof;
|
|
3063
3034
|
try {
|
|
3064
|
-
|
|
3065
|
-
hasProof = await activity.getProof() != null;
|
|
3035
|
+
hasProof = await (await Activity.fromJsonLd(this.activity, this)).getProof() != null;
|
|
3066
3036
|
} catch {
|
|
3067
3037
|
hasProof = false;
|
|
3068
3038
|
}
|
|
3069
3039
|
if (!hasProof) {
|
|
3070
3040
|
if (options?.skipIfUnsigned) return;
|
|
3071
|
-
logger
|
|
3041
|
+
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.");
|
|
3072
3042
|
}
|
|
3073
3043
|
}
|
|
3074
3044
|
if (recipients === "followers") {
|
|
@@ -3082,14 +3052,14 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3082
3052
|
preferSharedInbox: options?.preferSharedInbox,
|
|
3083
3053
|
excludeBaseUris: options?.excludeBaseUris
|
|
3084
3054
|
});
|
|
3085
|
-
logger
|
|
3055
|
+
logger.debug("Forwarding activity {activityId} to inboxes:\n{inboxes}", {
|
|
3086
3056
|
inboxes: globalThis.Object.keys(inboxes),
|
|
3087
3057
|
activityId: this.activityId,
|
|
3088
3058
|
activity: this.activity
|
|
3089
3059
|
});
|
|
3090
3060
|
if (options?.immediate || this.federation.outboxQueue == null) {
|
|
3091
|
-
if (options?.immediate) logger
|
|
3092
|
-
else logger
|
|
3061
|
+
if (options?.immediate) logger.debug("Forwarding activity immediately without queue since immediate option is set.");
|
|
3062
|
+
else logger.debug("Forwarding activity immediately without queue since queue is not set.");
|
|
3093
3063
|
const promises = [];
|
|
3094
3064
|
for (const inbox in inboxes) promises.push(sendActivity({
|
|
3095
3065
|
keys,
|
|
@@ -3104,7 +3074,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3104
3074
|
await Promise.all(promises);
|
|
3105
3075
|
return;
|
|
3106
3076
|
}
|
|
3107
|
-
logger
|
|
3077
|
+
logger.debug("Enqueuing activity {activityId} to forward later.", {
|
|
3108
3078
|
activityId: this.activityId,
|
|
3109
3079
|
activity: this.activity
|
|
3110
3080
|
});
|
|
@@ -3146,10 +3116,9 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3146
3116
|
const { outboxQueue } = this.federation;
|
|
3147
3117
|
if (outboxQueue.enqueueMany == null) {
|
|
3148
3118
|
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
3149
|
-
const
|
|
3150
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3119
|
+
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3151
3120
|
if (errors.length > 0) {
|
|
3152
|
-
logger
|
|
3121
|
+
logger.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
|
|
3153
3122
|
activityId: this.activityId,
|
|
3154
3123
|
errors
|
|
3155
3124
|
});
|
|
@@ -3158,10 +3127,9 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3158
3127
|
}
|
|
3159
3128
|
} else if (orderingKey != null) {
|
|
3160
3129
|
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
3161
|
-
const
|
|
3162
|
-
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3130
|
+
const errors = (await Promise.allSettled(promises)).filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3163
3131
|
if (errors.length > 0) {
|
|
3164
|
-
logger
|
|
3132
|
+
logger.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
|
|
3165
3133
|
activityId: this.activityId,
|
|
3166
3134
|
errors
|
|
3167
3135
|
});
|
|
@@ -3171,7 +3139,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3171
3139
|
} else try {
|
|
3172
3140
|
await outboxQueue.enqueueMany(messages.map((m) => m.message));
|
|
3173
3141
|
} catch (error) {
|
|
3174
|
-
logger
|
|
3142
|
+
logger.error("Failed to enqueue activity {activityId} to forward later:\n{error}", {
|
|
3175
3143
|
activityId: this.activityId,
|
|
3176
3144
|
error
|
|
3177
3145
|
});
|
|
@@ -3226,10 +3194,7 @@ function unauthorized(_request) {
|
|
|
3226
3194
|
function getRequestId(request) {
|
|
3227
3195
|
const traceId = request.headers.get("X-Request-Id") || request.headers.get("X-Correlation-Id") || request.headers.get("Traceparent")?.split("-")[1];
|
|
3228
3196
|
if (traceId != null) return traceId;
|
|
3229
|
-
|
|
3230
|
-
const random = Math.random().toString(36).slice(2, 8);
|
|
3231
|
-
return `req_${timestamp}${random}`;
|
|
3197
|
+
return `req_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
|
|
3232
3198
|
}
|
|
3233
|
-
|
|
3234
3199
|
//#endregion
|
|
3235
|
-
export {
|
|
3200
|
+
export { autoIdAssigner as _, createFederation as a, handleCollection as c, handleObject as d, respondWithObject as f, actorDehydrator as g, handleNodeInfoJrd as h, KvSpecDeterminer as i, handleCustomCollection as l, handleNodeInfo as m, FederationImpl as n, handleWebFinger as o, respondWithObjectIfAcceptable as p, InboxContextImpl as r, handleActor as s, ContextImpl as t, handleInbox as u };
|