@fedify/fedify 2.3.0-dev.1145 → 2.3.0-dev.1150
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{builder-ShiR1K6b.mjs → builder-Bjm1Jq9n.mjs} +2 -2
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{context-DI2gRbyN.d.cts → context-CRXCkTM6.d.cts} +48 -6
- package/dist/{context-DCtsSHDv.d.ts → context-MgCh7YGu.d.ts} +48 -6
- package/dist/{deno-h0TWFuEz.mjs → deno-CKFE6Uya.mjs} +1 -1
- package/dist/{docloader-BdDN0Aqx.mjs → docloader-B-ZE1cZf.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +1363 -44
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +1667 -163
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +2 -2
- package/dist/federation/mod.d.ts +2 -2
- package/dist/federation/mod.js +1 -1
- package/dist/federation/retry.test.mjs +1 -1
- package/dist/federation/send.test.mjs +8 -8
- package/dist/federation/temporal.test.d.mts +2 -0
- package/dist/federation/temporal.test.mjs +71 -0
- package/dist/federation/webfinger.test.mjs +1 -1
- package/dist/{getMachineId-bsd-etIyxDet.mjs → getMachineId-bsd-BY01PL1n.mjs} +1 -1
- package/dist/{getMachineId-darwin-D23zTf4g.mjs → getMachineId-darwin-Dr1gkBkp.mjs} +1 -1
- package/dist/{getMachineId-win-Dpap6v5i.mjs → getMachineId-win-QEYwcJiy.mjs} +1 -1
- package/dist/{http-7kAB7PVx.cjs → http-DQYEA7AZ.cjs} +1 -1
- package/dist/{http-B2hxA7dO.js → http-WbS1gKzr.js} +1 -1
- package/dist/{http-QzW9IWfs.mjs → http-vHCgbhTg.mjs} +3 -3
- package/dist/{key-Dh2OK1XQ.mjs → key-N0zP_oJA.mjs} +2 -2
- package/dist/{kv-cache-b22dNkjt.js → kv-cache-DM2O-Yjy.js} +1 -1
- package/dist/{kv-cache-DCPp-MT0.cjs → kv-cache-Dsg_bi4N.cjs} +1 -1
- package/dist/{kv-cache-EZRIPZXD.mjs → kv-cache-GXXZEemD.mjs} +1 -1
- package/dist/{ld-eZbar1rr.mjs → ld-BwKhquPx.mjs} +302 -6
- package/dist/{metrics-E0hAHtLZ.mjs → metrics-7Vy9FvEw.mjs} +1 -1
- package/dist/{middleware-BrGIM_Ra.js → middleware-BscgvU-m.js} +428 -99
- package/dist/{middleware-BUl1BH4x.cjs → middleware-D_iXrYHJ.cjs} +429 -99
- package/dist/{middleware-mToCR2tG.mjs → middleware-Db1_qAFG.mjs} +1 -1
- package/dist/{middleware-CyJDCmNg.mjs → middleware-ZuUcO0t1.mjs} +348 -108
- package/dist/{mod-CI9fduEi.d.cts → mod-C7HOzGqH.d.cts} +1 -1
- package/dist/{mod-CkRiJHGA.d.ts → mod-CpQHB3Ys.d.ts} +1 -1
- package/dist/mod.cjs +4 -4
- package/dist/mod.d.cts +2 -2
- package/dist/mod.d.ts +2 -2
- package/dist/mod.js +4 -4
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/{owner-ByO_Fw6U.mjs → owner-FD0H_vpj.mjs} +2 -2
- package/dist/{proof-jVqClF49.cjs → proof-CYK8T8IS.cjs} +353 -3
- package/dist/{proof-BkRyFchv.js → proof-I3EokKN-.js} +300 -4
- package/dist/{proof-CSo0S8OK.mjs → proof-V_lafPmA.mjs} +3 -3
- package/dist/{send-jzrTV1FU.mjs → send-Cc2_10tF.mjs} +3 -3
- package/dist/sig/http.test.mjs +2 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +558 -2
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/proof.test.mjs +1 -1
- package/dist/temporal-BkmBfs__.mjs +95 -0
- package/dist/testing/mod.d.mts +48 -6
- package/dist/utils/docloader.test.mjs +2 -2
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +7 -7
- /package/dist/{execAsync-DCBrgFiV.mjs → execAsync-Dxb7rNf3.mjs} +0 -0
- /package/dist/{getMachineId-linux-ObI47Hql.mjs → getMachineId-linux-Bbhofx-s.mjs} +0 -0
- /package/dist/{getMachineId-unsupported-Ddu-PFeh.mjs → getMachineId-unsupported-dIOte2Ct.mjs} +0 -0
- /package/dist/{retry-v_sGLH1d.mjs → retry-_VvV0h9f.mjs} +0 -0
|
@@ -2,10 +2,10 @@ const { Temporal } = require("@js-temporal/polyfill");
|
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
3
|
const require_chunk = require("./chunk-DDcVe30Y.cjs");
|
|
4
4
|
const require_transformers = require("./transformers-NeAONrAq.cjs");
|
|
5
|
-
const require_http = require("./http-
|
|
6
|
-
const require_proof = require("./proof-
|
|
5
|
+
const require_http = require("./http-DQYEA7AZ.cjs");
|
|
6
|
+
const require_proof = require("./proof-CYK8T8IS.cjs");
|
|
7
7
|
const require_types = require("./types-KC4QAoxe.cjs");
|
|
8
|
-
const require_kv_cache = require("./kv-cache-
|
|
8
|
+
const require_kv_cache = require("./kv-cache-Dsg_bi4N.cjs");
|
|
9
9
|
let _logtape_logtape = require("@logtape/logtape");
|
|
10
10
|
let _fedify_uri_template = require("@fedify/uri-template");
|
|
11
11
|
let _fedify_vocab = require("@fedify/vocab");
|
|
@@ -14,6 +14,8 @@ let byte_encodings_hex = require("byte-encodings/hex");
|
|
|
14
14
|
let es_toolkit = require("es-toolkit");
|
|
15
15
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
16
16
|
let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
17
|
+
let _fedify_vocab_runtime_jsonld = require("@fedify/vocab-runtime/jsonld");
|
|
18
|
+
_fedify_vocab_runtime_jsonld = require_chunk.__toESM(_fedify_vocab_runtime_jsonld, 1);
|
|
17
19
|
let _fedify_webfinger = require("@fedify/webfinger");
|
|
18
20
|
let node_url = require("node:url");
|
|
19
21
|
//#region src/federation/activity-listener.ts
|
|
@@ -691,7 +693,7 @@ async function buildCollectionSynchronizationHeader(collectionId, actorIds) {
|
|
|
691
693
|
}
|
|
692
694
|
//#endregion
|
|
693
695
|
//#region src/federation/inbox.ts
|
|
694
|
-
async function routeActivity({ context: ctx, json, activity, recipient, inboxListeners, inboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, meterProvider, tracerProvider, idempotencyStrategy }) {
|
|
696
|
+
async function routeActivity({ context: ctx, json, originalJson, normalizedActivity, ldSignatureVerified, activity, recipient, inboxListeners, inboxContextFactory, listenerInboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, meterProvider, tracerProvider, idempotencyStrategy }) {
|
|
695
697
|
const logger = (0, _logtape_logtape.getLogger)([
|
|
696
698
|
"fedify",
|
|
697
699
|
"federation",
|
|
@@ -750,7 +752,9 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
750
752
|
type: "inbox",
|
|
751
753
|
id: crypto.randomUUID(),
|
|
752
754
|
baseUrl: ctx.origin,
|
|
753
|
-
activity: json,
|
|
755
|
+
activity: originalJson ?? json,
|
|
756
|
+
...normalizedActivity == null ? {} : { normalizedActivity },
|
|
757
|
+
...ldSignatureVerified == null ? {} : { ldSignatureVerified },
|
|
754
758
|
identifier: recipient,
|
|
755
759
|
attempt: 0,
|
|
756
760
|
started: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -804,7 +808,8 @@ async function routeActivity({ context: ctx, json, activity, recipient, inboxLis
|
|
|
804
808
|
const activityType = (0, _fedify_vocab.getTypeId)(activity).href;
|
|
805
809
|
const started = performance.now();
|
|
806
810
|
try {
|
|
807
|
-
|
|
811
|
+
const contextFactory = listenerInboxContextFactory ?? inboxContextFactory;
|
|
812
|
+
await listener(contextFactory(recipient, contextFactory === inboxContextFactory ? json : originalJson ?? json, activity.id?.href, activityType), activity);
|
|
808
813
|
} finally {
|
|
809
814
|
require_http.getFederationMetrics(meterProvider).recordInboxProcessingDuration(activityType, require_http.getDurationMs(started));
|
|
810
815
|
}
|
|
@@ -1029,7 +1034,123 @@ function acceptsJsonLd(request) {
|
|
|
1029
1034
|
return types.includes("application/activity+json") || types.includes("application/ld+json") || types.includes("application/json");
|
|
1030
1035
|
}
|
|
1031
1036
|
//#endregion
|
|
1037
|
+
//#region src/federation/temporal.ts
|
|
1038
|
+
function isPlainObject(value) {
|
|
1039
|
+
return typeof value === "object" && value != null && !Array.isArray(value);
|
|
1040
|
+
}
|
|
1041
|
+
function normalizeDateTimeLiteral(value) {
|
|
1042
|
+
return value.substring(19).match(/[Z+-]/) ? value : value + "Z";
|
|
1043
|
+
}
|
|
1044
|
+
function isMalformedDateTimeLiteral(value) {
|
|
1045
|
+
if (typeof value !== "string") return false;
|
|
1046
|
+
try {
|
|
1047
|
+
Temporal.Instant.from(normalizeDateTimeLiteral(value));
|
|
1048
|
+
return false;
|
|
1049
|
+
} catch {
|
|
1050
|
+
return true;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
function isMalformedDurationLiteral(value) {
|
|
1054
|
+
if (typeof value !== "string") return false;
|
|
1055
|
+
try {
|
|
1056
|
+
Temporal.Duration.from(value);
|
|
1057
|
+
return false;
|
|
1058
|
+
} catch {
|
|
1059
|
+
return true;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
const TEMPORAL_DATE_TIME_IRIS = new Set([
|
|
1063
|
+
"https://www.w3.org/ns/activitystreams#deleted",
|
|
1064
|
+
"https://www.w3.org/ns/activitystreams#endTime",
|
|
1065
|
+
"https://www.w3.org/ns/activitystreams#published",
|
|
1066
|
+
"https://www.w3.org/ns/activitystreams#startTime",
|
|
1067
|
+
"https://www.w3.org/ns/activitystreams#updated",
|
|
1068
|
+
"http://purl.org/dc/terms/created",
|
|
1069
|
+
"https://w3id.org/security#created"
|
|
1070
|
+
]);
|
|
1071
|
+
const TEMPORAL_DURATION_IRIS = new Set(["https://www.w3.org/ns/activitystreams#duration"]);
|
|
1072
|
+
const QUESTION_CLOSED_IRI = "https://www.w3.org/ns/activitystreams#closed";
|
|
1073
|
+
const XSD_DATE_TIME_IRI = "http://www.w3.org/2001/XMLSchema#dateTime";
|
|
1074
|
+
function hasMalformedExpandedDateTimeLiteral(value) {
|
|
1075
|
+
if (Array.isArray(value)) return value.some(hasMalformedExpandedDateTimeLiteral);
|
|
1076
|
+
return isPlainObject(value) && "@value" in value && isMalformedDateTimeLiteral(value["@value"]);
|
|
1077
|
+
}
|
|
1078
|
+
function hasMalformedExpandedQuestionClosedLiteral(value) {
|
|
1079
|
+
if (Array.isArray(value)) return value.some(hasMalformedExpandedQuestionClosedLiteral);
|
|
1080
|
+
if (!isPlainObject(value) || !("@value" in value)) return false;
|
|
1081
|
+
const literal = value["@value"];
|
|
1082
|
+
if (typeof literal === "boolean") return false;
|
|
1083
|
+
if (typeof literal !== "string") return false;
|
|
1084
|
+
if (value["@type"] !== XSD_DATE_TIME_IRI) return false;
|
|
1085
|
+
if (new Date(literal).toString() === "Invalid Date") return false;
|
|
1086
|
+
return isMalformedDateTimeLiteral(literal);
|
|
1087
|
+
}
|
|
1088
|
+
function hasMalformedExpandedDurationLiteral(value) {
|
|
1089
|
+
if (Array.isArray(value)) return value.some(hasMalformedExpandedDurationLiteral);
|
|
1090
|
+
return isPlainObject(value) && "@value" in value && isMalformedDurationLiteral(value["@value"]);
|
|
1091
|
+
}
|
|
1092
|
+
function hasMalformedKnownTemporalLiteralInternal(value, visited) {
|
|
1093
|
+
if (Array.isArray(value)) return value.some((item) => hasMalformedKnownTemporalLiteralInternal(item, visited));
|
|
1094
|
+
if (!isPlainObject(value)) return false;
|
|
1095
|
+
if (visited.has(value)) return false;
|
|
1096
|
+
visited.add(value);
|
|
1097
|
+
if ("@value" in value) return false;
|
|
1098
|
+
for (const [key, child] of Object.entries(value)) {
|
|
1099
|
+
if (TEMPORAL_DATE_TIME_IRIS.has(key)) {
|
|
1100
|
+
if (hasMalformedExpandedDateTimeLiteral(child)) return true;
|
|
1101
|
+
continue;
|
|
1102
|
+
}
|
|
1103
|
+
if (key === QUESTION_CLOSED_IRI) {
|
|
1104
|
+
if (hasMalformedExpandedQuestionClosedLiteral(child)) return true;
|
|
1105
|
+
continue;
|
|
1106
|
+
}
|
|
1107
|
+
if (TEMPORAL_DURATION_IRIS.has(key)) {
|
|
1108
|
+
if (hasMalformedExpandedDurationLiteral(child)) return true;
|
|
1109
|
+
continue;
|
|
1110
|
+
}
|
|
1111
|
+
if (hasMalformedKnownTemporalLiteralInternal(child, visited)) return true;
|
|
1112
|
+
}
|
|
1113
|
+
return false;
|
|
1114
|
+
}
|
|
1115
|
+
async function hasMalformedKnownTemporalLiteral(value, contextLoader) {
|
|
1116
|
+
try {
|
|
1117
|
+
return hasMalformedKnownTemporalLiteralInternal(await _fedify_vocab_runtime_jsonld.default.expand(value, {
|
|
1118
|
+
documentLoader: require_proof.getNormalizationContextLoader(contextLoader),
|
|
1119
|
+
keepFreeFloatingNodes: true
|
|
1120
|
+
}), /* @__PURE__ */ new Set());
|
|
1121
|
+
} catch {
|
|
1122
|
+
return false;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
//#endregion
|
|
1032
1126
|
//#region src/federation/handler.ts
|
|
1127
|
+
const rawInboxContextFactorySymbol = Symbol("fedify.rawInboxContextFactory");
|
|
1128
|
+
function isRemoteContextLoadingFailure$1(error) {
|
|
1129
|
+
return error instanceof Error && typeof error.details === "object" && error.details != null && error.details.code === "loading remote context failed";
|
|
1130
|
+
}
|
|
1131
|
+
function isPermanentRemoteContextError$1(error) {
|
|
1132
|
+
if (!(error instanceof Error) || error.name !== "jsonld.InvalidUrl") return false;
|
|
1133
|
+
const details = error.details;
|
|
1134
|
+
if (details?.code === "invalid remote context") return true;
|
|
1135
|
+
return isRemoteContextLoadingFailure$1(error) && typeof details?.url === "string" && !URL.canParse(details.url) && require_proof.isClearlyMalformedContextReference(details.url);
|
|
1136
|
+
}
|
|
1137
|
+
function isInvalidJsonLdError(error) {
|
|
1138
|
+
if (!(error instanceof Error)) return false;
|
|
1139
|
+
const name = error.name;
|
|
1140
|
+
return name === "UnsafeJsonLdError" || error instanceof require_proof.InvalidContextReferenceError || isPermanentRemoteContextError$1(error) || name === "jsonld.SyntaxError" && !isRemoteContextLoadingFailure$1(error);
|
|
1141
|
+
}
|
|
1142
|
+
function isValidationTypeError(error) {
|
|
1143
|
+
return error instanceof TypeError && (/^(Invalid JSON-LD:|Invalid type:|Unexpected type:)/.test(error.message) || require_proof.isInvalidUrlTypeError(error));
|
|
1144
|
+
}
|
|
1145
|
+
function isPermanentActivityParseError(error) {
|
|
1146
|
+
return isInvalidJsonLdError(error) || isValidationTypeError(error);
|
|
1147
|
+
}
|
|
1148
|
+
function hasHttpSignatureHeaders(request) {
|
|
1149
|
+
return request.headers.has("Signature") || request.headers.has("Signature-Input");
|
|
1150
|
+
}
|
|
1151
|
+
function hasObjectIntegrityProof(json) {
|
|
1152
|
+
return typeof json === "object" && json != null && "proof" in json;
|
|
1153
|
+
}
|
|
1033
1154
|
/**
|
|
1034
1155
|
* Handles an actor request.
|
|
1035
1156
|
* @template TContextData The context data to pass to the context.
|
|
@@ -1101,8 +1222,8 @@ async function handleObject(request, { values, context, objectDispatcher, author
|
|
|
1101
1222
|
* @param parameters The parameters for handling the collection.
|
|
1102
1223
|
* @returns A promise that resolves to an HTTP response.
|
|
1103
1224
|
*/
|
|
1104
|
-
async function handleCollection(request, { name: name$
|
|
1105
|
-
const spanName = name$
|
|
1225
|
+
async function handleCollection(request, { name: name$1, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, onUnauthorized, onNotFound }) {
|
|
1226
|
+
const spanName = name$1.trim().replace(/\s+/g, "_");
|
|
1106
1227
|
tracerProvider = tracerProvider ?? _opentelemetry_api.trace.getTracerProvider();
|
|
1107
1228
|
const tracer = tracerProvider.getTracer(require_http.name, require_http.version);
|
|
1108
1229
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
@@ -1144,7 +1265,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
|
|
|
1144
1265
|
collection = new _fedify_vocab.OrderedCollection({
|
|
1145
1266
|
id: baseUri,
|
|
1146
1267
|
totalItems: totalItems == null ? null : Number(totalItems),
|
|
1147
|
-
items: filterCollectionItems(itemsOrResponse, name$
|
|
1268
|
+
items: filterCollectionItems(itemsOrResponse, name$1, filterPredicate)
|
|
1148
1269
|
});
|
|
1149
1270
|
} else {
|
|
1150
1271
|
const lastCursor = await collectionCallbacks.lastCursor?.(context, identifier);
|
|
@@ -1165,7 +1286,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
|
|
|
1165
1286
|
} else {
|
|
1166
1287
|
const uri = new URL(baseUri);
|
|
1167
1288
|
uri.searchParams.set("cursor", cursor);
|
|
1168
|
-
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$
|
|
1289
|
+
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
|
|
1169
1290
|
kind: _opentelemetry_api.SpanKind.SERVER,
|
|
1170
1291
|
attributes: {
|
|
1171
1292
|
"activitypub.collection.id": uri.href,
|
|
@@ -1209,7 +1330,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
|
|
|
1209
1330
|
id: uri,
|
|
1210
1331
|
prev,
|
|
1211
1332
|
next,
|
|
1212
|
-
items: filterCollectionItems(items, name$
|
|
1333
|
+
items: filterCollectionItems(items, name$1, filterPredicate),
|
|
1213
1334
|
partOf
|
|
1214
1335
|
});
|
|
1215
1336
|
}
|
|
@@ -1556,29 +1677,105 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1556
1677
|
});
|
|
1557
1678
|
}
|
|
1558
1679
|
const keyCache = new KvKeyCache(kv, kvPrefixes.publicKey, ctx);
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1680
|
+
const jsonWithoutSig = require_proof.detachSignature(json);
|
|
1681
|
+
const hasLdSignature = require_proof.hasSignature(json);
|
|
1682
|
+
const canAttemptAlternateAuthAfterLdSignatureFailure = skipSignatureVerification || hasHttpSignatureHeaders(request) || hasObjectIntegrityProof(jsonWithoutSig);
|
|
1683
|
+
let deferredLdSignatureError = void 0;
|
|
1684
|
+
const respondInvalidActivity = async (error) => {
|
|
1685
|
+
logger.error("Failed to parse activity:\n{error}", {
|
|
1686
|
+
recipient,
|
|
1687
|
+
activity: json,
|
|
1688
|
+
error
|
|
1567
1689
|
});
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1690
|
+
try {
|
|
1691
|
+
await inboxErrorHandler?.(ctx, error);
|
|
1692
|
+
} catch (error) {
|
|
1693
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
1694
|
+
error,
|
|
1695
|
+
activity: json,
|
|
1696
|
+
recipient
|
|
1697
|
+
});
|
|
1698
|
+
}
|
|
1699
|
+
span.setStatus({
|
|
1700
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
1701
|
+
message: `Failed to parse activity:\n${error}`
|
|
1702
|
+
});
|
|
1703
|
+
return new Response("Invalid activity.", {
|
|
1704
|
+
status: 400,
|
|
1705
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
1706
|
+
});
|
|
1707
|
+
};
|
|
1708
|
+
let compactedJson = json;
|
|
1709
|
+
let compactedJsonWithoutSig = jsonWithoutSig;
|
|
1710
|
+
let ldSigVerified = false;
|
|
1711
|
+
if (hasLdSignature) {
|
|
1712
|
+
try {
|
|
1713
|
+
compactedJson = await require_proof.compactJsonLd(json, ctx.contextLoader);
|
|
1714
|
+
} catch (error) {
|
|
1715
|
+
if (isInvalidJsonLdError(error)) {
|
|
1716
|
+
logger.error("Failed to parse JSON-LD:\n{error}", {
|
|
1717
|
+
recipient,
|
|
1718
|
+
error
|
|
1719
|
+
});
|
|
1720
|
+
return new Response("Invalid JSON-LD.", {
|
|
1721
|
+
status: 400,
|
|
1722
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
if (!canAttemptAlternateAuthAfterLdSignatureFailure) throw error;
|
|
1726
|
+
if (!skipSignatureVerification) deferredLdSignatureError = error;
|
|
1727
|
+
logger.debug("Failed to normalize JSON-LD for Linked Data Signatures; deferring to another authentication path only if it verifies:\n{error}", {
|
|
1571
1728
|
recipient,
|
|
1572
1729
|
error
|
|
1573
1730
|
});
|
|
1574
|
-
return new Response("Invalid JSON-LD.", {
|
|
1575
|
-
status: 400,
|
|
1576
|
-
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
1577
|
-
});
|
|
1578
1731
|
}
|
|
1579
|
-
|
|
1732
|
+
if (compactedJson !== json) {
|
|
1733
|
+
compactedJsonWithoutSig = require_proof.detachSignature(compactedJson);
|
|
1734
|
+
try {
|
|
1735
|
+
ldSigVerified = await require_proof.verifyCompactJsonLd(compactedJson, {
|
|
1736
|
+
contextLoader: ctx.contextLoader,
|
|
1737
|
+
documentLoader: ctx.documentLoader,
|
|
1738
|
+
keyCache,
|
|
1739
|
+
meterProvider,
|
|
1740
|
+
tracerProvider
|
|
1741
|
+
});
|
|
1742
|
+
} catch (error) {
|
|
1743
|
+
if (error instanceof RangeError && await hasMalformedKnownTemporalLiteral(compactedJsonWithoutSig, ctx.contextLoader)) return await respondInvalidActivity(error);
|
|
1744
|
+
if (isInvalidJsonLdError(error)) {
|
|
1745
|
+
logger.error("Failed to parse JSON-LD:\n{error}", {
|
|
1746
|
+
recipient,
|
|
1747
|
+
error
|
|
1748
|
+
});
|
|
1749
|
+
return new Response("Invalid JSON-LD.", {
|
|
1750
|
+
status: 400,
|
|
1751
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
if (!canAttemptAlternateAuthAfterLdSignatureFailure) throw error;
|
|
1755
|
+
if (!skipSignatureVerification) try {
|
|
1756
|
+
await _fedify_vocab.Object.fromJsonLd(compactedJson, {
|
|
1757
|
+
contextLoader: require_proof.getNormalizationContextLoader(ctx.contextLoader),
|
|
1758
|
+
documentLoader: ctx.documentLoader,
|
|
1759
|
+
tracerProvider
|
|
1760
|
+
});
|
|
1761
|
+
} catch (parseError) {
|
|
1762
|
+
if (parseError instanceof RangeError && await hasMalformedKnownTemporalLiteral(compactedJsonWithoutSig, ctx.contextLoader)) return await respondInvalidActivity(parseError);
|
|
1763
|
+
if (isInvalidJsonLdError(parseError)) {
|
|
1764
|
+
logger.error("Failed to parse JSON-LD:\n{error}", {
|
|
1765
|
+
recipient,
|
|
1766
|
+
error: parseError
|
|
1767
|
+
});
|
|
1768
|
+
return new Response("Invalid JSON-LD.", {
|
|
1769
|
+
status: 400,
|
|
1770
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
deferredLdSignatureError = parseError;
|
|
1774
|
+
}
|
|
1775
|
+
ldSigVerified = false;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1580
1778
|
}
|
|
1581
|
-
const jsonWithoutSig = require_proof.detachSignature(json);
|
|
1582
1779
|
let activity = null;
|
|
1583
1780
|
let activityVerified = false;
|
|
1584
1781
|
if (ldSigVerified) {
|
|
@@ -1586,7 +1783,16 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1586
1783
|
recipient,
|
|
1587
1784
|
json
|
|
1588
1785
|
});
|
|
1589
|
-
|
|
1786
|
+
try {
|
|
1787
|
+
activity = await _fedify_vocab.Activity.fromJsonLd(compactedJsonWithoutSig, {
|
|
1788
|
+
...ctx,
|
|
1789
|
+
contextLoader: require_proof.getNormalizationContextLoader(ctx.contextLoader)
|
|
1790
|
+
});
|
|
1791
|
+
} catch (error) {
|
|
1792
|
+
if (error instanceof RangeError && await hasMalformedKnownTemporalLiteral(compactedJsonWithoutSig, ctx.contextLoader)) return await respondInvalidActivity(error);
|
|
1793
|
+
if (!isPermanentActivityParseError(error)) throw error;
|
|
1794
|
+
return await respondInvalidActivity(error);
|
|
1795
|
+
}
|
|
1590
1796
|
activityVerified = true;
|
|
1591
1797
|
} else {
|
|
1592
1798
|
logger.debug("Linked Data Signatures are not verified.", {
|
|
@@ -1595,13 +1801,22 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1595
1801
|
});
|
|
1596
1802
|
try {
|
|
1597
1803
|
activity = await require_proof.verifyObject(_fedify_vocab.Activity, jsonWithoutSig, {
|
|
1598
|
-
contextLoader: ctx.contextLoader,
|
|
1804
|
+
contextLoader: require_proof.wrapContextLoaderForJsonLd(ctx.contextLoader),
|
|
1599
1805
|
documentLoader: ctx.documentLoader,
|
|
1600
1806
|
keyCache,
|
|
1601
1807
|
meterProvider,
|
|
1602
1808
|
tracerProvider
|
|
1603
1809
|
});
|
|
1604
1810
|
} catch (error) {
|
|
1811
|
+
if (error instanceof RangeError && await hasMalformedKnownTemporalLiteral(jsonWithoutSig, ctx.contextLoader)) return await respondInvalidActivity(error);
|
|
1812
|
+
if (deferredLdSignatureError != null) {
|
|
1813
|
+
logger.debug("Object Integrity Proof fallback did not supersede a deferred Linked Data Signature failure:\n{error}", {
|
|
1814
|
+
recipient,
|
|
1815
|
+
error
|
|
1816
|
+
});
|
|
1817
|
+
activity = null;
|
|
1818
|
+
}
|
|
1819
|
+
if (!isPermanentActivityParseError(error)) throw error;
|
|
1605
1820
|
logger.error("Failed to parse activity:\n{error}", {
|
|
1606
1821
|
recipient,
|
|
1607
1822
|
activity: json,
|
|
@@ -1650,6 +1865,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1650
1865
|
tracerProvider
|
|
1651
1866
|
});
|
|
1652
1867
|
if (verification.verified === false) {
|
|
1868
|
+
if (deferredLdSignatureError != null) throw deferredLdSignatureError;
|
|
1653
1869
|
const reason = verification.reason;
|
|
1654
1870
|
const remoteHost = "keyId" in reason && reason.keyId != null ? require_http.getRemoteHost(reason.keyId) : void 0;
|
|
1655
1871
|
require_http.getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure(reason.type, remoteHost);
|
|
@@ -1727,7 +1943,15 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1727
1943
|
}
|
|
1728
1944
|
httpSigKey = verification.key;
|
|
1729
1945
|
}
|
|
1730
|
-
|
|
1946
|
+
try {
|
|
1947
|
+
activity = await _fedify_vocab.Activity.fromJsonLd(jsonWithoutSig, {
|
|
1948
|
+
...ctx,
|
|
1949
|
+
contextLoader: require_proof.wrapContextLoaderForJsonLd(ctx.contextLoader)
|
|
1950
|
+
});
|
|
1951
|
+
} catch (error) {
|
|
1952
|
+
if (!isPermanentActivityParseError(error)) throw error;
|
|
1953
|
+
return await respondInvalidActivity(error);
|
|
1954
|
+
}
|
|
1731
1955
|
}
|
|
1732
1956
|
if (activity.id != null) span.setAttribute("activitypub.activity.id", activity.id.href);
|
|
1733
1957
|
span.setAttribute("activitypub.activity.type", (0, _fedify_vocab.getTypeId)(activity).href);
|
|
@@ -1739,6 +1963,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1739
1963
|
"http_signatures.key_id": httpSigKey?.id?.href ?? ""
|
|
1740
1964
|
});
|
|
1741
1965
|
if (httpSigKey != null && !await require_proof.doesActorOwnKey(activity, httpSigKey, ctx)) {
|
|
1966
|
+
if (deferredLdSignatureError != null) throw deferredLdSignatureError;
|
|
1742
1967
|
require_http.getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure("actorKeyMismatch", httpSigKey.id == null ? void 0 : require_http.getRemoteHost(httpSigKey.id));
|
|
1743
1968
|
logger.error("The signer ({keyId}) and the actor ({actorId}) do not match.", {
|
|
1744
1969
|
activity: json,
|
|
@@ -1765,10 +1990,14 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1765
1990
|
const routeResult = await routeActivity({
|
|
1766
1991
|
context: ctx,
|
|
1767
1992
|
json,
|
|
1993
|
+
originalJson: json,
|
|
1994
|
+
normalizedActivity: hasLdSignature && compactedJson !== json ? compactedJson : void 0,
|
|
1995
|
+
ldSignatureVerified: hasLdSignature ? ldSigVerified : void 0,
|
|
1768
1996
|
activity,
|
|
1769
1997
|
recipient,
|
|
1770
1998
|
inboxListeners,
|
|
1771
1999
|
inboxContextFactory,
|
|
2000
|
+
listenerInboxContextFactory: ldSigVerified ? inboxContextFactory[rawInboxContextFactorySymbol] : void 0,
|
|
1772
2001
|
inboxErrorHandler,
|
|
1773
2002
|
kv,
|
|
1774
2003
|
kvPrefixes,
|
|
@@ -1895,8 +2124,8 @@ var CustomCollectionHandler = class {
|
|
|
1895
2124
|
* @param CollectionPage The CollectionPage constructor.
|
|
1896
2125
|
* @param filterPredicate Optional filter predicate for items.
|
|
1897
2126
|
*/
|
|
1898
|
-
constructor(name$
|
|
1899
|
-
this.name = name$
|
|
2127
|
+
constructor(name$2, values, context, callbacks, tracerProvider = _opentelemetry_api.trace.getTracerProvider(), Collection, CollectionPage, filterPredicate) {
|
|
2128
|
+
this.name = name$2;
|
|
1900
2129
|
this.values = values;
|
|
1901
2130
|
this.context = context;
|
|
1902
2131
|
this.callbacks = callbacks;
|
|
@@ -2782,6 +3011,18 @@ var middleware_exports = /* @__PURE__ */ require_chunk.__exportAll({
|
|
|
2782
3011
|
OutboxContextImpl: () => OutboxContextImpl,
|
|
2783
3012
|
createFederation: () => createFederation
|
|
2784
3013
|
});
|
|
3014
|
+
function isRemoteContextLoadingFailure(error) {
|
|
3015
|
+
return error instanceof Error && typeof error.details === "object" && error.details != null && error.details.code === "loading remote context failed";
|
|
3016
|
+
}
|
|
3017
|
+
function isPermanentRemoteContextError(error) {
|
|
3018
|
+
if (!(error instanceof Error) || error.name !== "jsonld.InvalidUrl") return false;
|
|
3019
|
+
const details = error.details;
|
|
3020
|
+
if (details?.code === "invalid remote context") return true;
|
|
3021
|
+
return isRemoteContextLoadingFailure(error) && typeof details?.url === "string" && !URL.canParse(details.url) && require_proof.isClearlyMalformedContextReference(details.url);
|
|
3022
|
+
}
|
|
3023
|
+
function isPermanentInboxParseError(error) {
|
|
3024
|
+
return error instanceof Error && (error.name === "UnsafeJsonLdError" || error instanceof require_proof.InvalidContextReferenceError || isPermanentRemoteContextError(error) || error.name === "jsonld.SyntaxError" && !isRemoteContextLoadingFailure(error)) || error instanceof TypeError && (/^(Invalid JSON-LD:|Invalid type:|Unexpected type:)/.test(error.message) || require_proof.isInvalidUrlTypeError(error));
|
|
3025
|
+
}
|
|
2785
3026
|
/**
|
|
2786
3027
|
* Create a new {@link Federation} instance.
|
|
2787
3028
|
* @param parameters Parameters for initializing the instance.
|
|
@@ -3284,78 +3525,37 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3284
3525
|
const identity = await this.sharedInboxKeyDispatcher(context);
|
|
3285
3526
|
if (identity != null) context = this.#createContext(baseUrl, ctxData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
3286
3527
|
}
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
const cacheKey = activity.id == null ? null : [
|
|
3293
|
-
...this.kvPrefixes.activityIdempotence,
|
|
3294
|
-
context.origin,
|
|
3295
|
-
activity.id.href
|
|
3296
|
-
];
|
|
3297
|
-
if (cacheKey != null) {
|
|
3298
|
-
if (await this.kv.get(cacheKey) === true) {
|
|
3299
|
-
logger.debug("Activity {activityId} has already been processed.", {
|
|
3300
|
-
activityId: activity.id?.href,
|
|
3301
|
-
activity: message.activity,
|
|
3302
|
-
recipient: message.identifier
|
|
3303
|
-
});
|
|
3304
|
-
require_http.recordInboxActivity(this.meterProvider, "rejected", activityType);
|
|
3305
|
-
return;
|
|
3306
|
-
}
|
|
3307
|
-
}
|
|
3308
|
-
await this._getTracer().startActiveSpan("activitypub.dispatch_inbox_listener", { kind: _opentelemetry_api.SpanKind.INTERNAL }, async (span) => {
|
|
3309
|
-
const dispatched = this.inboxListeners?.dispatchWithClass(activity);
|
|
3310
|
-
if (dispatched == null) {
|
|
3311
|
-
logger.error("Unsupported activity type:\n{activity}", {
|
|
3312
|
-
activityId: activity.id?.href,
|
|
3313
|
-
activity: message.activity,
|
|
3314
|
-
recipient: message.identifier,
|
|
3315
|
-
trial: message.attempt
|
|
3316
|
-
});
|
|
3317
|
-
span.setStatus({
|
|
3318
|
-
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
3319
|
-
message: `Unsupported activity type: ${activityType}`
|
|
3320
|
-
});
|
|
3321
|
-
require_http.recordInboxActivity(this.meterProvider, "rejected", activityType);
|
|
3322
|
-
span.end();
|
|
3323
|
-
return;
|
|
3324
|
-
}
|
|
3325
|
-
const { class: cls, listener } = dispatched;
|
|
3326
|
-
span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
|
|
3327
|
-
try {
|
|
3328
|
-
const started = performance.now();
|
|
3329
|
-
try {
|
|
3330
|
-
await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, activityType), activity);
|
|
3331
|
-
} finally {
|
|
3332
|
-
require_http.getFederationMetrics(this.meterProvider).recordInboxProcessingDuration(activityType, require_http.getDurationMs(started));
|
|
3333
|
-
}
|
|
3334
|
-
require_http.recordInboxActivity(this.meterProvider, "processed", activityType);
|
|
3335
|
-
} catch (error) {
|
|
3528
|
+
await this._getTracer().startActiveSpan("activitypub.dispatch_inbox_listener", { kind: _opentelemetry_api.SpanKind.INTERNAL }, async (listenerSpan) => {
|
|
3529
|
+
let activity = null;
|
|
3530
|
+
let cacheKey = null;
|
|
3531
|
+
let activityType;
|
|
3532
|
+
const reportInboxError = async (error) => {
|
|
3336
3533
|
try {
|
|
3337
3534
|
await this.inboxErrorHandler?.(context, error);
|
|
3338
3535
|
} catch (error) {
|
|
3339
3536
|
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
3340
3537
|
error,
|
|
3341
3538
|
trial: message.attempt,
|
|
3342
|
-
activityId: activity
|
|
3539
|
+
activityId: activity?.id?.href,
|
|
3343
3540
|
activity: message.activity,
|
|
3344
3541
|
recipient: message.identifier
|
|
3345
3542
|
});
|
|
3346
3543
|
}
|
|
3544
|
+
};
|
|
3545
|
+
const handleRetriableFailure = async (error) => {
|
|
3546
|
+
await reportInboxError(error);
|
|
3347
3547
|
if (this.inboxQueue?.nativeRetrial) {
|
|
3348
3548
|
logger.error("Failed to process the incoming activity {activityId}; backend will handle retry:\n{error}", {
|
|
3349
3549
|
error,
|
|
3350
|
-
activityId: activity
|
|
3550
|
+
activityId: activity?.id?.href,
|
|
3351
3551
|
activity: message.activity,
|
|
3352
3552
|
recipient: message.identifier
|
|
3353
3553
|
});
|
|
3354
|
-
|
|
3554
|
+
listenerSpan.setStatus({
|
|
3355
3555
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
3356
3556
|
message: String(error)
|
|
3357
3557
|
});
|
|
3358
|
-
|
|
3558
|
+
listenerSpan.end();
|
|
3359
3559
|
throw error;
|
|
3360
3560
|
}
|
|
3361
3561
|
const delay = this.inboxRetryPolicy({
|
|
@@ -3366,20 +3566,27 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3366
3566
|
logger.error("Failed to process the incoming activity {activityId} (attempt #{attempt}); retry...:\n{error}", {
|
|
3367
3567
|
error,
|
|
3368
3568
|
attempt: message.attempt,
|
|
3369
|
-
activityId: activity
|
|
3569
|
+
activityId: activity?.id?.href,
|
|
3370
3570
|
activity: message.activity,
|
|
3371
3571
|
recipient: message.identifier
|
|
3372
3572
|
});
|
|
3573
|
+
if (this.inboxQueue == null) {
|
|
3574
|
+
listenerSpan.setStatus({
|
|
3575
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
3576
|
+
message: String(error)
|
|
3577
|
+
});
|
|
3578
|
+
listenerSpan.end();
|
|
3579
|
+
throw error;
|
|
3580
|
+
}
|
|
3373
3581
|
const retryMessage = {
|
|
3374
3582
|
...message,
|
|
3375
3583
|
attempt: message.attempt + 1
|
|
3376
3584
|
};
|
|
3377
|
-
|
|
3378
|
-
if (
|
|
3379
|
-
await inboxQueue.enqueue(retryMessage, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
|
|
3585
|
+
await this.inboxQueue.enqueue(retryMessage, { delay: Temporal.Duration.compare(delay, { seconds: 0 }) < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay });
|
|
3586
|
+
if (activityType != null) {
|
|
3380
3587
|
require_http.getFederationMetrics(this.meterProvider).recordQueueTaskEnqueued({
|
|
3381
3588
|
role: "inbox",
|
|
3382
|
-
queue: inboxQueue,
|
|
3589
|
+
queue: this.inboxQueue,
|
|
3383
3590
|
activityType
|
|
3384
3591
|
}, retryMessage.attempt);
|
|
3385
3592
|
require_http.recordInboxActivity(this.meterProvider, "retried", activityType);
|
|
@@ -3387,26 +3594,137 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3387
3594
|
} else {
|
|
3388
3595
|
logger.error("Failed to process the incoming activity {activityId} after {trial} attempts; giving up:\n{error}", {
|
|
3389
3596
|
error,
|
|
3390
|
-
activityId: activity
|
|
3597
|
+
activityId: activity?.id?.href,
|
|
3391
3598
|
activity: message.activity,
|
|
3392
3599
|
recipient: message.identifier
|
|
3393
3600
|
});
|
|
3394
|
-
require_http.recordInboxActivity(this.meterProvider, "abandoned", activityType);
|
|
3601
|
+
if (activityType != null) require_http.recordInboxActivity(this.meterProvider, "abandoned", activityType);
|
|
3395
3602
|
}
|
|
3396
|
-
|
|
3603
|
+
listenerSpan.setStatus({
|
|
3397
3604
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
3398
3605
|
message: String(error)
|
|
3399
3606
|
});
|
|
3400
|
-
|
|
3607
|
+
listenerSpan.end();
|
|
3608
|
+
};
|
|
3609
|
+
let dispatched;
|
|
3610
|
+
let parseInput = void 0;
|
|
3611
|
+
let parseContextLoader = context.contextLoader;
|
|
3612
|
+
try {
|
|
3613
|
+
const hasSignatureField = require_proof.hasSignature(message.activity);
|
|
3614
|
+
const shouldParseFromNormalizedSignedPayload = message.ldSignatureVerified === true || message.normalizedActivity != null || message.ldSignatureVerified == null && hasSignatureField;
|
|
3615
|
+
const parseContext = hasSignatureField ? {
|
|
3616
|
+
...context,
|
|
3617
|
+
contextLoader: require_proof.getNormalizationContextLoader(context.contextLoader)
|
|
3618
|
+
} : {
|
|
3619
|
+
...context,
|
|
3620
|
+
contextLoader: require_proof.wrapContextLoaderForJsonLd(context.contextLoader)
|
|
3621
|
+
};
|
|
3622
|
+
parseContextLoader = parseContext.contextLoader;
|
|
3623
|
+
let normalizedActivity;
|
|
3624
|
+
if (shouldParseFromNormalizedSignedPayload) {
|
|
3625
|
+
normalizedActivity = message.normalizedActivity ?? await require_proof.compactJsonLd(message.activity, context.contextLoader);
|
|
3626
|
+
require_proof.assertSafeJsonLd(normalizedActivity);
|
|
3627
|
+
}
|
|
3628
|
+
parseInput = shouldParseFromNormalizedSignedPayload ? require_proof.detachSignature(normalizedActivity) : hasSignatureField ? require_proof.detachSignature(message.activity) : message.activity;
|
|
3629
|
+
activity = await _fedify_vocab.Activity.fromJsonLd(parseInput, parseContext);
|
|
3630
|
+
activityType = (0, _fedify_vocab.getTypeId)(activity).href;
|
|
3631
|
+
span.setAttribute("activitypub.activity.type", activityType);
|
|
3632
|
+
listenerSpan.setAttribute("activitypub.activity.type", activityType);
|
|
3633
|
+
onActivityType?.(activityType);
|
|
3634
|
+
if (activity.id != null) {
|
|
3635
|
+
span.setAttribute("activitypub.activity.id", activity.id.href);
|
|
3636
|
+
listenerSpan.setAttribute("activitypub.activity.id", activity.id.href);
|
|
3637
|
+
}
|
|
3638
|
+
cacheKey = activity.id == null ? null : [
|
|
3639
|
+
...this.kvPrefixes.activityIdempotence,
|
|
3640
|
+
context.origin,
|
|
3641
|
+
activity.id.href
|
|
3642
|
+
];
|
|
3643
|
+
if (cacheKey != null) {
|
|
3644
|
+
if (await this.kv.get(cacheKey) === true) {
|
|
3645
|
+
logger.debug("Activity {activityId} has already been processed.", {
|
|
3646
|
+
activityId: activity.id?.href,
|
|
3647
|
+
activity: message.activity,
|
|
3648
|
+
recipient: message.identifier
|
|
3649
|
+
});
|
|
3650
|
+
require_http.recordInboxActivity(this.meterProvider, "rejected", activityType);
|
|
3651
|
+
listenerSpan.end();
|
|
3652
|
+
return;
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
dispatched = this.inboxListeners?.dispatchWithClass(activity);
|
|
3656
|
+
} catch (error) {
|
|
3657
|
+
if (activity == null && error instanceof RangeError && await hasMalformedKnownTemporalLiteral(parseInput, parseContextLoader)) {
|
|
3658
|
+
await reportInboxError(error);
|
|
3659
|
+
logger.error("Failed to parse the queued incoming activity {activityId}:\n{error}", {
|
|
3660
|
+
error,
|
|
3661
|
+
trial: message.attempt,
|
|
3662
|
+
activityId: null,
|
|
3663
|
+
activity: message.activity,
|
|
3664
|
+
recipient: message.identifier
|
|
3665
|
+
});
|
|
3666
|
+
listenerSpan.setStatus({
|
|
3667
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
3668
|
+
message: String(error)
|
|
3669
|
+
});
|
|
3670
|
+
listenerSpan.end();
|
|
3671
|
+
return;
|
|
3672
|
+
}
|
|
3673
|
+
if (isPermanentInboxParseError(error)) {
|
|
3674
|
+
await reportInboxError(error);
|
|
3675
|
+
logger.error("Failed to parse the queued incoming activity {activityId}:\n{error}", {
|
|
3676
|
+
error,
|
|
3677
|
+
trial: message.attempt,
|
|
3678
|
+
activityId: activity?.id?.href,
|
|
3679
|
+
activity: message.activity,
|
|
3680
|
+
recipient: message.identifier
|
|
3681
|
+
});
|
|
3682
|
+
listenerSpan.setStatus({
|
|
3683
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
3684
|
+
message: String(error)
|
|
3685
|
+
});
|
|
3686
|
+
listenerSpan.end();
|
|
3687
|
+
return;
|
|
3688
|
+
}
|
|
3689
|
+
await handleRetriableFailure(error);
|
|
3690
|
+
return;
|
|
3691
|
+
}
|
|
3692
|
+
if (dispatched == null) {
|
|
3693
|
+
logger.error("Unsupported activity type:\n{activity}", {
|
|
3694
|
+
activityId: activity.id?.href,
|
|
3695
|
+
activity: message.activity,
|
|
3696
|
+
recipient: message.identifier,
|
|
3697
|
+
trial: message.attempt
|
|
3698
|
+
});
|
|
3699
|
+
listenerSpan.setStatus({
|
|
3700
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
3701
|
+
message: `Unsupported activity type: ${activityType}`
|
|
3702
|
+
});
|
|
3703
|
+
require_http.recordInboxActivity(this.meterProvider, "rejected", activityType);
|
|
3704
|
+
listenerSpan.end();
|
|
3705
|
+
return;
|
|
3706
|
+
}
|
|
3707
|
+
const { class: cls, listener } = dispatched;
|
|
3708
|
+
listenerSpan.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
|
|
3709
|
+
try {
|
|
3710
|
+
const started = performance.now();
|
|
3711
|
+
try {
|
|
3712
|
+
await listener(context.toInboxContext(message.identifier, message.activity, activity.id?.href, activityType), activity);
|
|
3713
|
+
} finally {
|
|
3714
|
+
require_http.getFederationMetrics(this.meterProvider).recordInboxProcessingDuration(activityType, require_http.getDurationMs(started));
|
|
3715
|
+
}
|
|
3716
|
+
require_http.recordInboxActivity(this.meterProvider, "processed", activityType);
|
|
3717
|
+
} catch (error) {
|
|
3718
|
+
await handleRetriableFailure(error);
|
|
3401
3719
|
return;
|
|
3402
3720
|
}
|
|
3403
3721
|
if (cacheKey != null) await this.kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
|
|
3404
3722
|
logger.info("Activity {activityId} has been processed.", {
|
|
3405
|
-
activityId: activity
|
|
3723
|
+
activityId: activity?.id?.href,
|
|
3406
3724
|
activity: message.activity,
|
|
3407
3725
|
recipient: message.identifier
|
|
3408
3726
|
});
|
|
3409
|
-
|
|
3727
|
+
listenerSpan.end();
|
|
3410
3728
|
});
|
|
3411
3729
|
}
|
|
3412
3730
|
startQueue(contextData, options = {}) {
|
|
@@ -3787,16 +4105,18 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3787
4105
|
onNotFound
|
|
3788
4106
|
});
|
|
3789
4107
|
context = this.#createContext(request, contextData, { documentLoader: await context.getDocumentLoader({ identifier: route.values.identifier }) });
|
|
3790
|
-
case "sharedInbox":
|
|
4108
|
+
case "sharedInbox": {
|
|
3791
4109
|
if (routeName !== "inbox" && this.sharedInboxKeyDispatcher != null) {
|
|
3792
4110
|
const identity = await this.sharedInboxKeyDispatcher(context);
|
|
3793
4111
|
if (identity != null) context = this.#createContext(request, contextData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
3794
4112
|
}
|
|
3795
4113
|
if (!this.manuallyStartQueue) this._startQueueInternal(contextData);
|
|
4114
|
+
const inboxContextFactory = context.toInboxContext.bind(context);
|
|
4115
|
+
inboxContextFactory[rawInboxContextFactorySymbol] = context.toInboxContext.bind(context);
|
|
3796
4116
|
return await handleInbox(request, {
|
|
3797
4117
|
recipient: route.values.identifier ?? null,
|
|
3798
4118
|
context,
|
|
3799
|
-
inboxContextFactory
|
|
4119
|
+
inboxContextFactory,
|
|
3800
4120
|
kv: this.kv,
|
|
3801
4121
|
kvPrefixes: this.kvPrefixes,
|
|
3802
4122
|
queue: this.inboxQueue,
|
|
@@ -3812,6 +4132,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3812
4132
|
tracerProvider: this.tracerProvider,
|
|
3813
4133
|
idempotencyStrategy: this.idempotencyStrategy
|
|
3814
4134
|
});
|
|
4135
|
+
}
|
|
3815
4136
|
case "following": return await handleCollection(request, {
|
|
3816
4137
|
name: "following",
|
|
3817
4138
|
identifier: route.values.identifier,
|
|
@@ -4545,6 +4866,7 @@ var ContextImpl = class ContextImpl {
|
|
|
4545
4866
|
const routeResult = await routeActivity({
|
|
4546
4867
|
context: this,
|
|
4547
4868
|
json,
|
|
4869
|
+
ldSignatureVerified: false,
|
|
4548
4870
|
activity,
|
|
4549
4871
|
recipient,
|
|
4550
4872
|
inboxListeners: this.federation.inboxListeners,
|
|
@@ -4833,6 +5155,14 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
|
|
|
4833
5155
|
}
|
|
4834
5156
|
var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
4835
5157
|
recipient;
|
|
5158
|
+
/**
|
|
5159
|
+
* The original received activity payload.
|
|
5160
|
+
*
|
|
5161
|
+
* Fedify may normalize a Linked Data Signature payload internally for safe
|
|
5162
|
+
* parsing, but forwarding must keep the sender's payload unchanged so
|
|
5163
|
+
* third-party signatures/proofs remain intact.
|
|
5164
|
+
* @internal
|
|
5165
|
+
*/
|
|
4836
5166
|
activity;
|
|
4837
5167
|
activityId;
|
|
4838
5168
|
activityType;
|