@fedify/fedify 2.4.0-dev.1964 → 2.4.0-dev.1995
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-B4zpKIFU.mjs → builder-D0DxgOV5.mjs} +2 -2
- package/dist/{client-CtxvmazV.mjs → client-DpnpgjyX.mjs} +78 -4
- 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/compound-proof-CJnWc6c-.mjs +495 -0
- package/dist/{context-COLwHogJ.d.cts → context-BeDnDuF3.d.cts} +4 -3
- package/dist/{context-DiiCt4S7.d.ts → context-uyRUWoZQ.d.ts} +4 -3
- package/dist/{deno-CtG93ohj.mjs → deno-CABhzCb_.mjs} +1 -1
- package/dist/{docloader-dk_k3S8d.mjs → docloader-BbGSL0Xq.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/handler-compound-proof.test.d.mts +2 -0
- package/dist/federation/handler-compound-proof.test.mjs +152 -0
- package/dist/federation/handler.test.mjs +122 -4
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/keycache.test.mjs +52 -9
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +111 -15
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +2 -2
- package/dist/federation/mod.d.ts +2 -2
- package/dist/federation/mod.js +1 -1
- package/dist/federation/send.test.mjs +139 -4
- package/dist/federation/tasks/enqueue.test.mjs +1 -1
- package/dist/federation/tasks/tasks.test.mjs +2 -2
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +1 -1
- package/dist/{federation-Drjlrrax.cjs → federation-DCEHQk4G.cjs} +632 -57
- package/dist/{http-6TI0tI03.d.cts → http-65PYi9jY.d.ts} +34 -2
- package/dist/{http-Dj4s1UQ0.js → http-9WyuldYh.js} +170 -8
- package/dist/{http-CdrSn2ip.d.ts → http-CP-7OdSq.d.cts} +34 -2
- package/dist/{http-B3skRvGo.cjs → http-CRFns-UE.cjs} +181 -7
- package/dist/{http-D7LX-BL9.mjs → http-D9urSO2D.mjs} +3 -3
- package/dist/{key-BVjgbs_9.mjs → key-Ccs8cnd7.mjs} +169 -7
- package/dist/{keycache-ZLqIfrkL.mjs → keycache-BUDHB5rY.mjs} +12 -4
- package/dist/{kv-cache-DtsjH_bY.cjs → kv-cache-DXT9vmIg.cjs} +2 -2
- package/dist/{kv-cache-tGNbvDCF.js → kv-cache-DtmXhPXG.js} +2 -2
- package/dist/{kv-cache-xRcC_xxP.mjs → kv-cache-lKyFn_Dn.mjs} +1 -1
- package/dist/{ld-OuCeQFny.mjs → ld-qup__MAW.mjs} +3 -3
- package/dist/map-local-context-conflict-DOYEEJ3u.mjs +204 -0
- package/dist/map-local-create-note-B0SeXJms.mjs +214 -0
- package/dist/{metrics-B9N27cCB.mjs → metrics-CISXCvB1.mjs} +1 -1
- package/dist/{middleware-TeLjzoxn.mjs → middleware-CzvJvPHK.mjs} +58 -15
- package/dist/{middleware-Cd_vPqDH.mjs → middleware-DkrU2WhY.mjs} +1 -1
- package/dist/{middleware-CPTDFMmJ.js → middleware-DsfWajaD.js} +593 -18
- package/dist/{mod-DypxPS9H.d.ts → mod-C0BYc0OU.d.ts} +1 -1
- package/dist/{mod-CnGLNoVw.d.cts → mod-CbKDOnCt.d.cts} +1 -1
- package/dist/{mod-CLHkCwLm.d.cts → mod-CyiSjRkk.d.cts} +1 -1
- package/dist/{mod-CSH1Ee-I.d.ts → mod-D882_Xsg.d.ts} +1 -1
- package/dist/{mod-DzRXACM5.d.ts → mod-UDwMjuHM.d.ts} +1 -1
- package/dist/{mod-BZldCEU0.d.cts → mod-x9W0d0Pk.d.cts} +1 -1
- package/dist/mod.cjs +20 -20
- package/dist/mod.d.cts +6 -6
- package/dist/mod.d.ts +6 -6
- package/dist/mod.js +5 -5
- package/dist/nodeinfo/client.test.mjs +28 -1
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/nodeinfo/mod.cjs +1 -1
- package/dist/nodeinfo/mod.js +1 -1
- package/dist/{owner-DGSfntI-.d.ts → owner-BF0L9cMt.d.cts} +12 -1
- package/dist/{proof-BO_esQii.js → owner-BIPEZGiU.js} +1255 -1098
- package/dist/{owner-r_waTiQj.d.cts → owner-BSzr5-I8.d.ts} +12 -1
- package/dist/owner-CRoq8Spb.mjs +175 -0
- package/dist/{proof-Dua0d906.cjs → owner-CVA7L9MA.cjs} +1266 -1097
- package/dist/{proof-D5Ajk4DJ.mjs → proof-BDxNVZ3E.mjs} +186 -83
- package/dist/{send-DVXyUqhO.mjs → send-BzM5GLyn.mjs} +68 -11
- package/dist/sig/compound-proof-discovery.test.d.mts +2 -0
- package/dist/sig/compound-proof-discovery.test.mjs +331 -0
- package/dist/sig/compound-proof-verification.test.d.mts +2 -0
- package/dist/sig/compound-proof-verification.test.mjs +465 -0
- package/dist/sig/compound-proof.test.d.mts +2 -0
- package/dist/sig/compound-proof.test.mjs +324 -0
- package/dist/sig/http.test.mjs +2 -2
- package/dist/sig/key.test.mjs +169 -2
- package/dist/sig/ld.test.mjs +55 -2
- package/dist/sig/mod.cjs +17 -17
- package/dist/sig/mod.d.cts +3 -3
- package/dist/sig/mod.d.ts +3 -3
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +103 -4
- package/dist/sig/proof.test.mjs +120 -1
- package/dist/{temporal-BoDw51A-.mjs → temporal-Dv6Qv-8k.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- package/dist/testing/mod.d.mts +2 -1
- package/dist/{types-RXm5YxpC.cjs → types-Be2zbyeG.cjs} +94 -2
- package/dist/{types-Dtyf8lVj.js → types-C_cNlNVK.js} +78 -4
- package/dist/utils/docloader.test.mjs +27 -3
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.d.cts +1 -1
- package/dist/utils/mod.d.ts +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +6 -6
- package/dist/owner-DTEqTzSr.mjs +0 -120
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
2
|
const require_rolldown_runtime = require("./rolldown-runtime-Dmm3t92W.cjs");
|
|
3
3
|
const require_transformers = require("./transformers-BalCrSsr.cjs");
|
|
4
|
-
const require_http = require("./http-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const require_kv_cache = require("./kv-cache-
|
|
4
|
+
const require_http = require("./http-CRFns-UE.cjs");
|
|
5
|
+
const require_types = require("./types-Be2zbyeG.cjs");
|
|
6
|
+
const require_owner = require("./owner-CVA7L9MA.cjs");
|
|
7
|
+
const require_kv_cache = require("./kv-cache-DXT9vmIg.cjs");
|
|
8
8
|
let _logtape_logtape = require("@logtape/logtape");
|
|
9
9
|
let _fedify_uri_template = require("@fedify/uri-template");
|
|
10
10
|
let _fedify_vocab = require("@fedify/vocab");
|
|
11
11
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
12
12
|
let byte_encodings_hex = require("byte-encodings/hex");
|
|
13
|
-
let es_toolkit = require("es-toolkit");
|
|
14
13
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
15
|
-
let
|
|
14
|
+
let es_toolkit = require("es-toolkit");
|
|
16
15
|
let _fedify_vocab_runtime_jsonld = require("@fedify/vocab-runtime/jsonld");
|
|
17
16
|
_fedify_vocab_runtime_jsonld = require_rolldown_runtime.__toESM(_fedify_vocab_runtime_jsonld, 1);
|
|
17
|
+
let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
18
18
|
let _fedify_webfinger = require("@fedify/webfinger");
|
|
19
19
|
let _opentelemetry_sdk_metrics = require("@opentelemetry/sdk-metrics");
|
|
20
20
|
let devalue = require("devalue");
|
|
@@ -1297,6 +1297,474 @@ async function buildCollectionSynchronizationHeader(collectionId, actorIds) {
|
|
|
1297
1297
|
return `collectionId="${collectionId}", url="${url}", digest="${(0, byte_encodings_hex.encodeHex)(await digest(actorIds))}"`;
|
|
1298
1298
|
}
|
|
1299
1299
|
//#endregion
|
|
1300
|
+
//#region src/sig/compound-proof.ts
|
|
1301
|
+
const textEncoder = new TextEncoder();
|
|
1302
|
+
const PORTABLE_OBJECT_ID_PATTERN = /^ap(?:\+ef61)?:\/\//i;
|
|
1303
|
+
function isJsonMap(value) {
|
|
1304
|
+
return typeof value === "object" && value != null && !Array.isArray(value);
|
|
1305
|
+
}
|
|
1306
|
+
function isCompoundProofJsonObject(value) {
|
|
1307
|
+
return typeof value === "object" && value != null && !Array.isArray(value);
|
|
1308
|
+
}
|
|
1309
|
+
function hasOnlyDataProperties(value) {
|
|
1310
|
+
try {
|
|
1311
|
+
return Reflect.ownKeys(value).every((key) => {
|
|
1312
|
+
if (typeof key !== "string") return false;
|
|
1313
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
1314
|
+
return descriptor != null && "value" in descriptor && descriptor.enumerable;
|
|
1315
|
+
});
|
|
1316
|
+
} catch {
|
|
1317
|
+
return false;
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
function hasOnlyJsonArrayProperties(value) {
|
|
1321
|
+
try {
|
|
1322
|
+
const keys = Reflect.ownKeys(value);
|
|
1323
|
+
if (keys.length !== value.length + 1) return false;
|
|
1324
|
+
for (const key of keys) {
|
|
1325
|
+
if (key === "length") continue;
|
|
1326
|
+
if (typeof key !== "string") return false;
|
|
1327
|
+
const index = Number(key);
|
|
1328
|
+
if (!Number.isInteger(index) || index < 0 || index >= value.length || String(index) !== key) return false;
|
|
1329
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
1330
|
+
if (descriptor == null || !descriptor.enumerable || !("value" in descriptor)) return false;
|
|
1331
|
+
}
|
|
1332
|
+
return true;
|
|
1333
|
+
} catch {
|
|
1334
|
+
return false;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
function escapeJsonPointerSegment(segment) {
|
|
1338
|
+
return segment.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
1339
|
+
}
|
|
1340
|
+
function childPath(path, segment) {
|
|
1341
|
+
return `${path}/${escapeJsonPointerSegment(segment)}`;
|
|
1342
|
+
}
|
|
1343
|
+
function comparePaths(left, right) {
|
|
1344
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
1345
|
+
}
|
|
1346
|
+
function encodedLength(value) {
|
|
1347
|
+
return textEncoder.encode(value).byteLength;
|
|
1348
|
+
}
|
|
1349
|
+
function validateLimits(limits) {
|
|
1350
|
+
for (const [name, value] of Object.entries(limits)) if (!Number.isSafeInteger(value) || value < 0) throw new RangeError(`${name} must be a non-negative safe integer.`);
|
|
1351
|
+
}
|
|
1352
|
+
function limitExceeded(limit, maximum, actual, path) {
|
|
1353
|
+
return {
|
|
1354
|
+
status: "unsupported",
|
|
1355
|
+
reason: {
|
|
1356
|
+
type: "limitExceeded",
|
|
1357
|
+
limit,
|
|
1358
|
+
maximum,
|
|
1359
|
+
actual,
|
|
1360
|
+
path
|
|
1361
|
+
}
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
function addBytes(statistics, bytes, limits, path) {
|
|
1365
|
+
statistics.byteLength += bytes;
|
|
1366
|
+
if (statistics.byteLength > limits.maxBytes) return limitExceeded("bytes", limits.maxBytes, statistics.byteLength, path);
|
|
1367
|
+
}
|
|
1368
|
+
function inspectJsonTree(root, limits) {
|
|
1369
|
+
if (!isJsonMap(root)) return {
|
|
1370
|
+
status: "unsupported",
|
|
1371
|
+
reason: {
|
|
1372
|
+
type: "invalidJsonTree",
|
|
1373
|
+
path: ""
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
const statistics = {
|
|
1377
|
+
byteLength: 0,
|
|
1378
|
+
mapCount: 0,
|
|
1379
|
+
proofCount: 0,
|
|
1380
|
+
maxDepth: 0
|
|
1381
|
+
};
|
|
1382
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1383
|
+
const pending = [{
|
|
1384
|
+
value: root,
|
|
1385
|
+
path: "",
|
|
1386
|
+
depth: 0,
|
|
1387
|
+
insideProof: false,
|
|
1388
|
+
insideContext: false
|
|
1389
|
+
}];
|
|
1390
|
+
while (pending.length > 0) {
|
|
1391
|
+
const current = pending.pop();
|
|
1392
|
+
statistics.maxDepth = Math.max(statistics.maxDepth, current.depth);
|
|
1393
|
+
if (current.depth > limits.maxDepth) return limitExceeded("depth", limits.maxDepth, current.depth, current.path);
|
|
1394
|
+
const value = current.value;
|
|
1395
|
+
if (value === null) {
|
|
1396
|
+
const failure = addBytes(statistics, 4, limits, current.path);
|
|
1397
|
+
if (failure != null) return failure;
|
|
1398
|
+
} else if (typeof value === "boolean") {
|
|
1399
|
+
const failure = addBytes(statistics, value ? 4 : 5, limits, current.path);
|
|
1400
|
+
if (failure != null) return failure;
|
|
1401
|
+
} else if (typeof value === "string") {
|
|
1402
|
+
const failure = addBytes(statistics, encodedLength(JSON.stringify(value)), limits, current.path);
|
|
1403
|
+
if (failure != null) return failure;
|
|
1404
|
+
} else if (typeof value === "number") {
|
|
1405
|
+
if (!Number.isFinite(value)) return {
|
|
1406
|
+
status: "unsupported",
|
|
1407
|
+
reason: {
|
|
1408
|
+
type: "invalidJsonTree",
|
|
1409
|
+
path: current.path
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
const failure = addBytes(statistics, encodedLength(JSON.stringify(value)), limits, current.path);
|
|
1413
|
+
if (failure != null) return failure;
|
|
1414
|
+
} else if (Array.isArray(value)) {
|
|
1415
|
+
if (seen.has(value) || !hasOnlyJsonArrayProperties(value)) return {
|
|
1416
|
+
status: "unsupported",
|
|
1417
|
+
reason: {
|
|
1418
|
+
type: "invalidJsonTree",
|
|
1419
|
+
path: current.path
|
|
1420
|
+
}
|
|
1421
|
+
};
|
|
1422
|
+
seen.add(value);
|
|
1423
|
+
const failure = addBytes(statistics, 2 + Math.max(0, value.length - 1), limits, current.path);
|
|
1424
|
+
if (failure != null) return failure;
|
|
1425
|
+
for (let index = value.length - 1; index >= 0; index--) pending.push({
|
|
1426
|
+
value: value[index],
|
|
1427
|
+
path: childPath(current.path, String(index)),
|
|
1428
|
+
depth: current.depth + 1,
|
|
1429
|
+
insideProof: current.insideProof,
|
|
1430
|
+
insideContext: current.insideContext
|
|
1431
|
+
});
|
|
1432
|
+
} else if (isJsonMap(value)) {
|
|
1433
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1434
|
+
if (seen.has(value) || !hasOnlyDataProperties(value) || prototype !== Object.prototype && prototype !== null) return {
|
|
1435
|
+
status: "unsupported",
|
|
1436
|
+
reason: {
|
|
1437
|
+
type: "invalidJsonTree",
|
|
1438
|
+
path: current.path
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
seen.add(value);
|
|
1442
|
+
statistics.mapCount++;
|
|
1443
|
+
if (statistics.mapCount > limits.maxMaps) return limitExceeded("maps", limits.maxMaps, statistics.mapCount, current.path);
|
|
1444
|
+
const entries = Object.entries(value).sort(([left], [right]) => comparePaths(left, right));
|
|
1445
|
+
let objectBytes = 2 + Math.max(0, entries.length - 1);
|
|
1446
|
+
for (const [key] of entries) objectBytes += encodedLength(JSON.stringify(key)) + 1;
|
|
1447
|
+
const failure = addBytes(statistics, objectBytes, limits, current.path);
|
|
1448
|
+
if (failure != null) return failure;
|
|
1449
|
+
const hasDirectProof = !current.insideProof && !current.insideContext && Object.hasOwn(value, "proof");
|
|
1450
|
+
if (hasDirectProof) {
|
|
1451
|
+
statistics.proofCount++;
|
|
1452
|
+
if (statistics.proofCount > limits.maxProofs) return limitExceeded("proofs", limits.maxProofs, statistics.proofCount, childPath(current.path, "proof"));
|
|
1453
|
+
if (!isJsonMap(value.proof)) return {
|
|
1454
|
+
status: "unsupported",
|
|
1455
|
+
reason: {
|
|
1456
|
+
type: "unsupportedProofShape",
|
|
1457
|
+
path: childPath(current.path, "proof")
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
for (let index = entries.length - 1; index >= 0; index--) {
|
|
1462
|
+
const [key, child] = entries[index];
|
|
1463
|
+
pending.push({
|
|
1464
|
+
value: child,
|
|
1465
|
+
path: childPath(current.path, key),
|
|
1466
|
+
depth: current.depth + 1,
|
|
1467
|
+
insideProof: current.insideProof || hasDirectProof && key === "proof",
|
|
1468
|
+
insideContext: current.insideContext || key === "@context"
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
} else return {
|
|
1472
|
+
status: "unsupported",
|
|
1473
|
+
reason: {
|
|
1474
|
+
type: "invalidJsonTree",
|
|
1475
|
+
path: current.path
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
return statistics;
|
|
1480
|
+
}
|
|
1481
|
+
function freezeJsonTree(root) {
|
|
1482
|
+
const pending = [root];
|
|
1483
|
+
while (pending.length > 0) {
|
|
1484
|
+
const value = pending.pop();
|
|
1485
|
+
if (typeof value !== "object" || value == null) continue;
|
|
1486
|
+
if (Array.isArray(value)) for (const child of value) pending.push(child);
|
|
1487
|
+
else for (const child of Object.values(value)) pending.push(child);
|
|
1488
|
+
Object.freeze(value);
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
function collectDocuments(snapshot) {
|
|
1492
|
+
const documents = [];
|
|
1493
|
+
const pending = [{
|
|
1494
|
+
value: snapshot,
|
|
1495
|
+
path: "",
|
|
1496
|
+
depth: 0
|
|
1497
|
+
}];
|
|
1498
|
+
while (pending.length > 0) {
|
|
1499
|
+
const current = pending.pop();
|
|
1500
|
+
if (Array.isArray(current.value)) {
|
|
1501
|
+
for (let index = current.value.length - 1; index >= 0; index--) pending.push({
|
|
1502
|
+
value: current.value[index],
|
|
1503
|
+
path: childPath(current.path, String(index)),
|
|
1504
|
+
depth: current.depth + 1
|
|
1505
|
+
});
|
|
1506
|
+
continue;
|
|
1507
|
+
}
|
|
1508
|
+
if (!isCompoundProofJsonObject(current.value)) continue;
|
|
1509
|
+
const document = current.value;
|
|
1510
|
+
if (Object.hasOwn(document, "proof")) {
|
|
1511
|
+
const proof = document.proof;
|
|
1512
|
+
const id = typeof document.id === "string" ? document.id : typeof document["@id"] === "string" ? document["@id"] : void 0;
|
|
1513
|
+
documents.push(Object.freeze({
|
|
1514
|
+
path: current.path,
|
|
1515
|
+
id,
|
|
1516
|
+
depth: current.depth,
|
|
1517
|
+
securedDocument: document,
|
|
1518
|
+
proof
|
|
1519
|
+
}));
|
|
1520
|
+
}
|
|
1521
|
+
const entries = Object.entries(document).sort(([left], [right]) => comparePaths(left, right));
|
|
1522
|
+
for (let index = entries.length - 1; index >= 0; index--) {
|
|
1523
|
+
const [key, value] = entries[index];
|
|
1524
|
+
if (key === "proof" || key === "@context") continue;
|
|
1525
|
+
pending.push({
|
|
1526
|
+
value,
|
|
1527
|
+
path: childPath(current.path, key),
|
|
1528
|
+
depth: current.depth + 1
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
documents.sort((left, right) => right.depth - left.depth || comparePaths(left.path, right.path));
|
|
1533
|
+
return documents;
|
|
1534
|
+
}
|
|
1535
|
+
function collectPortableObjects(snapshot) {
|
|
1536
|
+
const objects = [];
|
|
1537
|
+
const pending = [{
|
|
1538
|
+
value: snapshot,
|
|
1539
|
+
path: "",
|
|
1540
|
+
depth: 0
|
|
1541
|
+
}];
|
|
1542
|
+
while (pending.length > 0) {
|
|
1543
|
+
const current = pending.pop();
|
|
1544
|
+
if (Array.isArray(current.value)) {
|
|
1545
|
+
for (let index = current.value.length - 1; index >= 0; index--) pending.push({
|
|
1546
|
+
value: current.value[index],
|
|
1547
|
+
path: childPath(current.path, String(index)),
|
|
1548
|
+
depth: current.depth + 1
|
|
1549
|
+
});
|
|
1550
|
+
continue;
|
|
1551
|
+
}
|
|
1552
|
+
if (!isCompoundProofJsonObject(current.value)) continue;
|
|
1553
|
+
const document = current.value;
|
|
1554
|
+
const id = [document.id, document["@id"]].find((value) => typeof value === "string" && PORTABLE_OBJECT_ID_PATTERN.test(value));
|
|
1555
|
+
if (typeof id === "string") objects.push(Object.freeze({
|
|
1556
|
+
path: current.path,
|
|
1557
|
+
id,
|
|
1558
|
+
depth: current.depth,
|
|
1559
|
+
document
|
|
1560
|
+
}));
|
|
1561
|
+
const entries = Object.entries(document).sort(([left], [right]) => comparePaths(left, right));
|
|
1562
|
+
for (let index = entries.length - 1; index >= 0; index--) {
|
|
1563
|
+
const [key, value] = entries[index];
|
|
1564
|
+
if (key === "proof" || key === "@context") continue;
|
|
1565
|
+
pending.push({
|
|
1566
|
+
value,
|
|
1567
|
+
path: childPath(current.path, key),
|
|
1568
|
+
depth: current.depth + 1
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
objects.sort((left, right) => right.depth - left.depth || comparePaths(left.path, right.path));
|
|
1573
|
+
return objects;
|
|
1574
|
+
}
|
|
1575
|
+
/**
|
|
1576
|
+
* Determines whether a received JSON tree contains a portable object ID
|
|
1577
|
+
* outside a proof or context definition, without exceeding discovery limits.
|
|
1578
|
+
*
|
|
1579
|
+
* This is only an applicability check. It does not authenticate the input;
|
|
1580
|
+
* callers must still use {@link verifyCompoundPortableObjectProofs} to obtain
|
|
1581
|
+
* an atomic result from an immutable snapshot. `indeterminate` means the
|
|
1582
|
+
* applicability scan itself reached a limit, so a caller must not treat the
|
|
1583
|
+
* document as outside the compound profile.
|
|
1584
|
+
*
|
|
1585
|
+
* @internal
|
|
1586
|
+
*/
|
|
1587
|
+
function inspectCompoundPortableObjectApplicability(json, limits) {
|
|
1588
|
+
validateLimits(limits);
|
|
1589
|
+
let byteLength = 0;
|
|
1590
|
+
let mapCount = 0;
|
|
1591
|
+
const pending = [{
|
|
1592
|
+
iterator: [json].values(),
|
|
1593
|
+
depth: 0
|
|
1594
|
+
}];
|
|
1595
|
+
const addByteLength = (length) => {
|
|
1596
|
+
byteLength += length;
|
|
1597
|
+
return byteLength <= limits.maxBytes;
|
|
1598
|
+
};
|
|
1599
|
+
while (pending.length > 0) {
|
|
1600
|
+
const frame = pending[pending.length - 1];
|
|
1601
|
+
const next = frame.iterator.next();
|
|
1602
|
+
if (next.done) {
|
|
1603
|
+
pending.pop();
|
|
1604
|
+
if (byteLength > limits.maxBytes) return "indeterminate";
|
|
1605
|
+
continue;
|
|
1606
|
+
}
|
|
1607
|
+
const value = next.value;
|
|
1608
|
+
if (frame.depth > limits.maxDepth) return "indeterminate";
|
|
1609
|
+
if (value === null) {
|
|
1610
|
+
if (!addByteLength(4)) return "indeterminate";
|
|
1611
|
+
} else if (typeof value === "boolean") {
|
|
1612
|
+
if (!addByteLength(value ? 4 : 5)) return "indeterminate";
|
|
1613
|
+
} else if (typeof value === "string" || typeof value === "number") {
|
|
1614
|
+
if (!addByteLength(encodedLength(JSON.stringify(value)))) return "indeterminate";
|
|
1615
|
+
} else if (Array.isArray(value)) {
|
|
1616
|
+
if (!addByteLength(2 + Math.max(0, value.length - 1))) return "indeterminate";
|
|
1617
|
+
pending.push({
|
|
1618
|
+
iterator: value.values(),
|
|
1619
|
+
depth: frame.depth + 1
|
|
1620
|
+
});
|
|
1621
|
+
} else if (isJsonMap(value)) {
|
|
1622
|
+
mapCount++;
|
|
1623
|
+
if (mapCount > limits.maxMaps) return "indeterminate";
|
|
1624
|
+
if ([value.id, value["@id"]].some((id) => typeof id === "string" && PORTABLE_OBJECT_ID_PATTERN.test(id))) return "present";
|
|
1625
|
+
if (!addByteLength(2)) return "indeterminate";
|
|
1626
|
+
const children = function* () {
|
|
1627
|
+
let first = true;
|
|
1628
|
+
for (const key in value) {
|
|
1629
|
+
if (!Object.hasOwn(value, key)) continue;
|
|
1630
|
+
if (key === "proof" || key === "@context") continue;
|
|
1631
|
+
if (!first && !addByteLength(1)) return;
|
|
1632
|
+
first = false;
|
|
1633
|
+
if (!addByteLength(encodedLength(JSON.stringify(key)) + 1)) return;
|
|
1634
|
+
yield value[key];
|
|
1635
|
+
}
|
|
1636
|
+
}();
|
|
1637
|
+
pending.push({
|
|
1638
|
+
iterator: children,
|
|
1639
|
+
depth: frame.depth + 1
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
if (byteLength > limits.maxBytes) return "indeterminate";
|
|
1643
|
+
}
|
|
1644
|
+
return "absent";
|
|
1645
|
+
}
|
|
1646
|
+
/**
|
|
1647
|
+
* Discovers direct literal proof-bearing maps in an immutable JSON snapshot.
|
|
1648
|
+
*
|
|
1649
|
+
* Discovery is bounded and atomic. Unsupported proof shapes, non-JSON input,
|
|
1650
|
+
* or a resource-limit failure return no partial candidate list. Proof
|
|
1651
|
+
* configuration subtrees are validated and counted as JSON, but are not
|
|
1652
|
+
* themselves searched for secured documents.
|
|
1653
|
+
*/
|
|
1654
|
+
function discoverCompoundProofDocuments(json, limits) {
|
|
1655
|
+
validateLimits(limits);
|
|
1656
|
+
let inspected;
|
|
1657
|
+
try {
|
|
1658
|
+
inspected = inspectJsonTree(json, limits);
|
|
1659
|
+
} catch {
|
|
1660
|
+
return {
|
|
1661
|
+
status: "unsupported",
|
|
1662
|
+
reason: {
|
|
1663
|
+
type: "invalidJsonTree",
|
|
1664
|
+
path: ""
|
|
1665
|
+
}
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
if ("status" in inspected) return inspected;
|
|
1669
|
+
let snapshot;
|
|
1670
|
+
try {
|
|
1671
|
+
snapshot = structuredClone(json);
|
|
1672
|
+
} catch {
|
|
1673
|
+
return {
|
|
1674
|
+
status: "unsupported",
|
|
1675
|
+
reason: {
|
|
1676
|
+
type: "invalidJsonTree",
|
|
1677
|
+
path: ""
|
|
1678
|
+
}
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1681
|
+
freezeJsonTree(snapshot);
|
|
1682
|
+
return {
|
|
1683
|
+
status: "ok",
|
|
1684
|
+
snapshot,
|
|
1685
|
+
documents: Object.freeze(collectDocuments(snapshot)),
|
|
1686
|
+
statistics: Object.freeze({ ...inspected })
|
|
1687
|
+
};
|
|
1688
|
+
}
|
|
1689
|
+
async function verifyDiscoveredProofDocuments(discovered, options) {
|
|
1690
|
+
const documents = await Promise.all(discovered.documents.map(async (document) => {
|
|
1691
|
+
const metadata = {
|
|
1692
|
+
path: document.path,
|
|
1693
|
+
...document.id == null ? {} : { id: document.id },
|
|
1694
|
+
depth: document.depth
|
|
1695
|
+
};
|
|
1696
|
+
if (document.depth > 0 && !Object.hasOwn(document.securedDocument, "@context")) return Object.freeze({
|
|
1697
|
+
...metadata,
|
|
1698
|
+
verified: false,
|
|
1699
|
+
reason: { type: "missingContext" }
|
|
1700
|
+
});
|
|
1701
|
+
const key = await require_owner.verifyMapLocalProof(document.securedDocument, options);
|
|
1702
|
+
return key == null ? Object.freeze({
|
|
1703
|
+
...metadata,
|
|
1704
|
+
verified: false,
|
|
1705
|
+
reason: { type: "invalidProof" }
|
|
1706
|
+
}) : Object.freeze({
|
|
1707
|
+
...metadata,
|
|
1708
|
+
verified: true,
|
|
1709
|
+
key
|
|
1710
|
+
});
|
|
1711
|
+
}));
|
|
1712
|
+
return Object.freeze(documents);
|
|
1713
|
+
}
|
|
1714
|
+
/**
|
|
1715
|
+
* Applies FEP-ef61 portable-object policy to every portable map in a compound
|
|
1716
|
+
* snapshot without changing the map-local cryptographic inputs.
|
|
1717
|
+
*
|
|
1718
|
+
* @internal
|
|
1719
|
+
*/
|
|
1720
|
+
async function verifyCompoundPortableObjectProofs(json, limits, options = {}) {
|
|
1721
|
+
const discovered = discoverCompoundProofDocuments(json, limits);
|
|
1722
|
+
if (discovered.status !== "ok") return discovered;
|
|
1723
|
+
const proofs = await verifyDiscoveredProofDocuments(discovered, options);
|
|
1724
|
+
const proofByPath = new Map(proofs.map((proof) => [proof.path, proof]));
|
|
1725
|
+
const portableObjects = await Promise.all(collectPortableObjects(discovered.snapshot).map(async (object) => {
|
|
1726
|
+
const metadata = {
|
|
1727
|
+
path: object.path,
|
|
1728
|
+
id: object.id,
|
|
1729
|
+
depth: object.depth
|
|
1730
|
+
};
|
|
1731
|
+
if (object.depth > 0 && !Object.hasOwn(object.document, "@context")) return Object.freeze({
|
|
1732
|
+
...metadata,
|
|
1733
|
+
verified: false,
|
|
1734
|
+
reason: { type: "missingContext" }
|
|
1735
|
+
});
|
|
1736
|
+
const proof = proofByPath.get(object.path);
|
|
1737
|
+
const key = proof?.verified === true ? proof.key : null;
|
|
1738
|
+
try {
|
|
1739
|
+
const policy = await require_owner.verifyPortableObjectProofPolicy(object.document, key, options);
|
|
1740
|
+
return policy.verified ? Object.freeze({
|
|
1741
|
+
...metadata,
|
|
1742
|
+
id: policy.objectId,
|
|
1743
|
+
verified: true,
|
|
1744
|
+
keys: policy.keys
|
|
1745
|
+
}) : Object.freeze({
|
|
1746
|
+
...metadata,
|
|
1747
|
+
verified: false,
|
|
1748
|
+
reason: policy.reason
|
|
1749
|
+
});
|
|
1750
|
+
} catch {
|
|
1751
|
+
return Object.freeze({
|
|
1752
|
+
...metadata,
|
|
1753
|
+
verified: false,
|
|
1754
|
+
reason: { type: "invalidPortableObject" }
|
|
1755
|
+
});
|
|
1756
|
+
}
|
|
1757
|
+
}));
|
|
1758
|
+
return {
|
|
1759
|
+
status: "ok",
|
|
1760
|
+
verified: portableObjects.length > 0 && proofs.every((proof) => proof.verified) && portableObjects.every((object) => object.verified),
|
|
1761
|
+
snapshot: discovered.snapshot,
|
|
1762
|
+
proofs,
|
|
1763
|
+
portableObjects: Object.freeze(portableObjects),
|
|
1764
|
+
statistics: discovered.statistics
|
|
1765
|
+
};
|
|
1766
|
+
}
|
|
1767
|
+
//#endregion
|
|
1300
1768
|
//#region src/federation/inbox.ts
|
|
1301
1769
|
const Temporal$9 = require_http.Temporal;
|
|
1302
1770
|
async function routeActivity({ context: ctx, json, originalJson, normalizedActivity, ldSignatureVerified, activity, recipient, inboxListeners, inboxContextFactory, listenerInboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, meterProvider, tracerProvider, idempotencyStrategy }) {
|
|
@@ -1458,6 +1926,7 @@ async function routeActivity({ context: ctx, json, originalJson, normalizedActiv
|
|
|
1458
1926
|
//#endregion
|
|
1459
1927
|
//#region src/federation/keycache.ts
|
|
1460
1928
|
const Temporal$8 = require_http.Temporal;
|
|
1929
|
+
const KEY_CACHE_GENERATION = "2";
|
|
1461
1930
|
var KvKeyCache = class {
|
|
1462
1931
|
kv;
|
|
1463
1932
|
prefix;
|
|
@@ -1480,13 +1949,20 @@ var KvKeyCache = class {
|
|
|
1480
1949
|
keyId.href
|
|
1481
1950
|
];
|
|
1482
1951
|
}
|
|
1952
|
+
#entryKey(keyId) {
|
|
1953
|
+
return [
|
|
1954
|
+
...this.prefix,
|
|
1955
|
+
KEY_CACHE_GENERATION,
|
|
1956
|
+
keyId.href
|
|
1957
|
+
];
|
|
1958
|
+
}
|
|
1483
1959
|
async get(keyId) {
|
|
1484
1960
|
const negativeExpiration = this.nullKeys.get(keyId.href);
|
|
1485
1961
|
if (negativeExpiration != null) {
|
|
1486
1962
|
if (Temporal$8.Now.instant().until(negativeExpiration).sign >= 0) return null;
|
|
1487
1963
|
this.nullKeys.delete(keyId.href);
|
|
1488
1964
|
}
|
|
1489
|
-
const serialized = await this.kv.get(
|
|
1965
|
+
const serialized = await this.kv.get(this.#entryKey(keyId));
|
|
1490
1966
|
if (serialized === void 0) return void 0;
|
|
1491
1967
|
if (serialized === null) {
|
|
1492
1968
|
this.nullKeys.set(keyId.href, Temporal$8.Now.instant().add(this.unavailableKeyTtl));
|
|
@@ -1498,7 +1974,7 @@ var KvKeyCache = class {
|
|
|
1498
1974
|
try {
|
|
1499
1975
|
return await _fedify_vocab.Multikey.fromJsonLd(serialized, this.options);
|
|
1500
1976
|
} catch {
|
|
1501
|
-
await this.kv.delete(
|
|
1977
|
+
await this.kv.delete(this.#entryKey(keyId));
|
|
1502
1978
|
return;
|
|
1503
1979
|
}
|
|
1504
1980
|
}
|
|
@@ -1506,12 +1982,12 @@ var KvKeyCache = class {
|
|
|
1506
1982
|
async set(keyId, key) {
|
|
1507
1983
|
if (key == null) {
|
|
1508
1984
|
this.nullKeys.set(keyId.href, Temporal$8.Now.instant().add(this.unavailableKeyTtl));
|
|
1509
|
-
await this.kv.set(
|
|
1985
|
+
await this.kv.set(this.#entryKey(keyId), null, { ttl: this.unavailableKeyTtl });
|
|
1510
1986
|
return;
|
|
1511
1987
|
}
|
|
1512
1988
|
this.nullKeys.delete(keyId.href);
|
|
1513
1989
|
const serialized = await key.toJsonLd(this.options);
|
|
1514
|
-
await this.kv.set(
|
|
1990
|
+
await this.kv.set(this.#entryKey(keyId), serialized, { ttl: this.keyTtl });
|
|
1515
1991
|
}
|
|
1516
1992
|
async getFetchError(keyId) {
|
|
1517
1993
|
const cached = await this.kv.get(this.#getFetchErrorKey(keyId));
|
|
@@ -1725,7 +2201,7 @@ function hasMalformedKnownTemporalLiteralInternal(value, visited) {
|
|
|
1725
2201
|
async function hasMalformedKnownTemporalLiteral(value, contextLoader) {
|
|
1726
2202
|
try {
|
|
1727
2203
|
return hasMalformedKnownTemporalLiteralInternal(await _fedify_vocab_runtime_jsonld.default.expand(value, {
|
|
1728
|
-
documentLoader:
|
|
2204
|
+
documentLoader: require_owner.getNormalizationContextLoader(contextLoader),
|
|
1729
2205
|
keepFreeFloatingNodes: true
|
|
1730
2206
|
}), /* @__PURE__ */ new Set());
|
|
1731
2207
|
} catch {
|
|
@@ -1736,6 +2212,12 @@ async function hasMalformedKnownTemporalLiteral(value, contextLoader) {
|
|
|
1736
2212
|
//#region src/federation/handler.ts
|
|
1737
2213
|
const Temporal$6 = require_http.Temporal;
|
|
1738
2214
|
const rawInboxContextFactorySymbol = Symbol("fedify.rawInboxContextFactory");
|
|
2215
|
+
const INBOX_COMPOUND_PROOF_LIMITS = {
|
|
2216
|
+
maxDepth: 64,
|
|
2217
|
+
maxMaps: 1e4,
|
|
2218
|
+
maxProofs: 32,
|
|
2219
|
+
maxBytes: 10 * 1024 * 1024
|
|
2220
|
+
};
|
|
1739
2221
|
function isRemoteContextLoadingFailure$1(error) {
|
|
1740
2222
|
return error instanceof Error && typeof error.details === "object" && error.details != null && error.details.code === "loading remote context failed";
|
|
1741
2223
|
}
|
|
@@ -1743,15 +2225,15 @@ function isPermanentRemoteContextError$1(error) {
|
|
|
1743
2225
|
if (!(error instanceof Error) || error.name !== "jsonld.InvalidUrl") return false;
|
|
1744
2226
|
const details = error.details;
|
|
1745
2227
|
if (details?.code === "invalid remote context") return true;
|
|
1746
|
-
return isRemoteContextLoadingFailure$1(error) && typeof details?.url === "string" && !URL.canParse(details.url) &&
|
|
2228
|
+
return isRemoteContextLoadingFailure$1(error) && typeof details?.url === "string" && !URL.canParse(details.url) && require_owner.isClearlyMalformedContextReference(details.url);
|
|
1747
2229
|
}
|
|
1748
2230
|
function isInvalidJsonLdError(error) {
|
|
1749
2231
|
if (!(error instanceof Error)) return false;
|
|
1750
2232
|
const name = error.name;
|
|
1751
|
-
return name === "UnsafeJsonLdError" || error instanceof
|
|
2233
|
+
return name === "UnsafeJsonLdError" || error instanceof require_owner.InvalidContextReferenceError || isPermanentRemoteContextError$1(error) || name === "jsonld.SyntaxError" && !isRemoteContextLoadingFailure$1(error);
|
|
1752
2234
|
}
|
|
1753
2235
|
function isValidationTypeError(error) {
|
|
1754
|
-
return error instanceof TypeError && (/^(Invalid JSON-LD:|Invalid type:|Unexpected type:|Invalid @id:)/.test(error.message) ||
|
|
2236
|
+
return error instanceof TypeError && (/^(Invalid JSON-LD:|Invalid type:|Unexpected type:|Invalid @id:)/.test(error.message) || require_owner.isInvalidUrlTypeError(error));
|
|
1755
2237
|
}
|
|
1756
2238
|
function isPermanentActivityParseError(error) {
|
|
1757
2239
|
return isInvalidJsonLdError(error) || isValidationTypeError(error);
|
|
@@ -1860,13 +2342,13 @@ function recordCollectionMetrics(meterProvider, base, result, options = {}) {
|
|
|
1860
2342
|
* @param parameters The parameters for handling the collection.
|
|
1861
2343
|
* @returns A promise that resolves to an HTTP response.
|
|
1862
2344
|
*/
|
|
1863
|
-
async function handleCollection(request, { name: name$
|
|
1864
|
-
const spanName = name$
|
|
2345
|
+
async function handleCollection(request, { name: name$1, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
|
|
2346
|
+
const spanName = name$1.trim().replace(/\s+/g, "_");
|
|
1865
2347
|
tracerProvider = tracerProvider ?? _opentelemetry_api.trace.getTracerProvider();
|
|
1866
2348
|
const tracer = tracerProvider.getTracer(require_http.name, require_http.version);
|
|
1867
2349
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
1868
2350
|
const metricBase = {
|
|
1869
|
-
kind: getCollectionMetricKind(name$
|
|
2351
|
+
kind: getCollectionMetricKind(name$1),
|
|
1870
2352
|
page: cursor != null,
|
|
1871
2353
|
dispatcher: "built_in"
|
|
1872
2354
|
};
|
|
@@ -1907,7 +2389,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
|
|
|
1907
2389
|
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
1908
2390
|
return await onNotFound(request);
|
|
1909
2391
|
}
|
|
1910
|
-
const items = filterCollectionItems(page.items, name$
|
|
2392
|
+
const items = filterCollectionItems(page.items, name$1, filterPredicate);
|
|
1911
2393
|
itemCount = items.length;
|
|
1912
2394
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
1913
2395
|
return items;
|
|
@@ -1947,7 +2429,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
|
|
|
1947
2429
|
} else {
|
|
1948
2430
|
const uri = new URL(baseUri);
|
|
1949
2431
|
uri.searchParams.set("cursor", cursor);
|
|
1950
|
-
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$
|
|
2432
|
+
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
|
|
1951
2433
|
kind: _opentelemetry_api.SpanKind.SERVER,
|
|
1952
2434
|
attributes: {
|
|
1953
2435
|
"activitypub.collection.id": uri.href,
|
|
@@ -1963,7 +2445,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
|
|
|
1963
2445
|
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
1964
2446
|
return await onNotFound(request);
|
|
1965
2447
|
}
|
|
1966
|
-
const items = filterCollectionItems(page.items, name$
|
|
2448
|
+
const items = filterCollectionItems(page.items, name$1, filterPredicate);
|
|
1967
2449
|
itemCount = items.length;
|
|
1968
2450
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
1969
2451
|
return {
|
|
@@ -2516,8 +2998,16 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2516
2998
|
}
|
|
2517
2999
|
let json;
|
|
2518
3000
|
try {
|
|
2519
|
-
json = await request.clone().
|
|
3001
|
+
json = JSON.parse(await require_types.readBoundedText(request.clone(), require_types.MAX_BODY_SIZE, request.url));
|
|
2520
3002
|
} catch (error) {
|
|
3003
|
+
if (error instanceof require_types.BodyTooLargeError) {
|
|
3004
|
+
request.body?.cancel(error).catch(() => {});
|
|
3005
|
+
span.setStatus({
|
|
3006
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
3007
|
+
message: String(error)
|
|
3008
|
+
});
|
|
3009
|
+
return new Response("Inbox body too large.", { status: 413 });
|
|
3010
|
+
}
|
|
2521
3011
|
logger.error("Failed to parse JSON:\n{error}", {
|
|
2522
3012
|
recipient,
|
|
2523
3013
|
error
|
|
@@ -2546,8 +3036,8 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2546
3036
|
tracerProvider,
|
|
2547
3037
|
keyTtl: publicKeyTtl
|
|
2548
3038
|
});
|
|
2549
|
-
const jsonWithoutSig =
|
|
2550
|
-
const hasLdSignature =
|
|
3039
|
+
const jsonWithoutSig = require_owner.detachSignature(json);
|
|
3040
|
+
const hasLdSignature = require_owner.hasSignature(json);
|
|
2551
3041
|
const canAttemptAlternateAuthAfterLdSignatureFailure = skipSignatureVerification || hasHttpSignatureHeaders(request) || hasObjectIntegrityProof(jsonWithoutSig);
|
|
2552
3042
|
let deferredLdSignatureError = void 0;
|
|
2553
3043
|
const respondInvalidActivity = async (error) => {
|
|
@@ -2579,7 +3069,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2579
3069
|
let ldSigVerified = false;
|
|
2580
3070
|
if (hasLdSignature) {
|
|
2581
3071
|
try {
|
|
2582
|
-
compactedJson = await
|
|
3072
|
+
compactedJson = await require_owner.compactJsonLd(json, ctx.contextLoader);
|
|
2583
3073
|
} catch (error) {
|
|
2584
3074
|
if (isInvalidJsonLdError(error)) {
|
|
2585
3075
|
logger.error("Failed to parse JSON-LD:\n{error}", {
|
|
@@ -2599,9 +3089,9 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2599
3089
|
});
|
|
2600
3090
|
}
|
|
2601
3091
|
if (compactedJson !== json) {
|
|
2602
|
-
compactedJsonWithoutSig =
|
|
3092
|
+
compactedJsonWithoutSig = require_owner.detachSignature(compactedJson);
|
|
2603
3093
|
try {
|
|
2604
|
-
ldSigVerified = await
|
|
3094
|
+
ldSigVerified = await require_owner.verifyCompactJsonLd(compactedJson, {
|
|
2605
3095
|
contextLoader: ctx.contextLoader,
|
|
2606
3096
|
documentLoader: ctx.documentLoader,
|
|
2607
3097
|
keyCache,
|
|
@@ -2623,7 +3113,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2623
3113
|
if (!canAttemptAlternateAuthAfterLdSignatureFailure) throw error;
|
|
2624
3114
|
if (!skipSignatureVerification) try {
|
|
2625
3115
|
await _fedify_vocab.Object.fromJsonLd(compactedJson, {
|
|
2626
|
-
contextLoader:
|
|
3116
|
+
contextLoader: require_owner.getNormalizationContextLoader(ctx.contextLoader),
|
|
2627
3117
|
documentLoader: ctx.documentLoader,
|
|
2628
3118
|
tracerProvider
|
|
2629
3119
|
});
|
|
@@ -2655,7 +3145,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2655
3145
|
try {
|
|
2656
3146
|
activity = await _fedify_vocab.Activity.fromJsonLd(compactedJsonWithoutSig, {
|
|
2657
3147
|
...ctx,
|
|
2658
|
-
contextLoader:
|
|
3148
|
+
contextLoader: require_owner.getNormalizationContextLoader(ctx.contextLoader)
|
|
2659
3149
|
});
|
|
2660
3150
|
} catch (error) {
|
|
2661
3151
|
if (error instanceof RangeError && await hasMalformedKnownTemporalLiteral(compactedJsonWithoutSig, ctx.contextLoader)) return await respondInvalidActivity(error);
|
|
@@ -2669,8 +3159,8 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2669
3159
|
json
|
|
2670
3160
|
});
|
|
2671
3161
|
try {
|
|
2672
|
-
activity = await
|
|
2673
|
-
contextLoader:
|
|
3162
|
+
activity = await require_owner.verifyObject(_fedify_vocab.Activity, jsonWithoutSig, {
|
|
3163
|
+
contextLoader: require_owner.wrapContextLoaderForJsonLd(ctx.contextLoader),
|
|
2674
3164
|
documentLoader: ctx.documentLoader,
|
|
2675
3165
|
keyCache,
|
|
2676
3166
|
meterProvider,
|
|
@@ -2815,7 +3305,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2815
3305
|
try {
|
|
2816
3306
|
activity = await _fedify_vocab.Activity.fromJsonLd(jsonWithoutSig, {
|
|
2817
3307
|
...ctx,
|
|
2818
|
-
contextLoader:
|
|
3308
|
+
contextLoader: require_owner.wrapContextLoaderForJsonLd(ctx.contextLoader)
|
|
2819
3309
|
});
|
|
2820
3310
|
} catch (error) {
|
|
2821
3311
|
if (!isPermanentActivityParseError(error)) throw error;
|
|
@@ -2831,7 +3321,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2831
3321
|
"http_signatures.verified": httpSigKey != null,
|
|
2832
3322
|
"http_signatures.key_id": httpSigKey?.id?.href ?? ""
|
|
2833
3323
|
});
|
|
2834
|
-
if (httpSigKey != null && !await
|
|
3324
|
+
if (httpSigKey != null && !await require_owner.doesActorOwnKey(activity, httpSigKey, ctx)) {
|
|
2835
3325
|
if (deferredLdSignatureError != null) throw deferredLdSignatureError;
|
|
2836
3326
|
require_http.getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure("actorKeyMismatch", httpSigKey.id == null ? void 0 : require_http.getRemoteHost(httpSigKey.id));
|
|
2837
3327
|
logger.error("The signer ({keyId}) and the actor ({actorId}) do not match.", {
|
|
@@ -2849,6 +3339,31 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2849
3339
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
2850
3340
|
});
|
|
2851
3341
|
}
|
|
3342
|
+
if (!skipSignatureVerification) {
|
|
3343
|
+
if (inspectCompoundPortableObjectApplicability(json, INBOX_COMPOUND_PROOF_LIMITS) !== "absent") {
|
|
3344
|
+
const compoundProof = await verifyCompoundPortableObjectProofs(json, INBOX_COMPOUND_PROOF_LIMITS, {
|
|
3345
|
+
documentLoader: ctx.documentLoader,
|
|
3346
|
+
keyCache,
|
|
3347
|
+
meterProvider,
|
|
3348
|
+
tracerProvider
|
|
3349
|
+
});
|
|
3350
|
+
if (compoundProof.status !== "ok" || !compoundProof.verified) {
|
|
3351
|
+
logger.error("Failed to verify compound portable Object Integrity Proofs.", {
|
|
3352
|
+
recipient,
|
|
3353
|
+
activity: json,
|
|
3354
|
+
reason: compoundProof.status === "unsupported" ? compoundProof.reason.type : "invalidProof"
|
|
3355
|
+
});
|
|
3356
|
+
span.setStatus({
|
|
3357
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
3358
|
+
message: "Failed to verify compound portable Object Integrity Proofs."
|
|
3359
|
+
});
|
|
3360
|
+
return new Response("Failed to verify compound portable Object Integrity Proofs.", {
|
|
3361
|
+
status: 401,
|
|
3362
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
3363
|
+
});
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
2852
3367
|
if (pendingNonceLabel != null) {
|
|
2853
3368
|
if (!await verifySignatureNonce(request, kv, kvPrefixes.acceptSignatureNonce, pendingNonceLabel)) {
|
|
2854
3369
|
require_http.getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure("invalidNonce", httpSigKey?.id == null ? void 0 : require_http.getRemoteHost(httpSigKey.id));
|
|
@@ -3023,8 +3538,8 @@ var CustomCollectionHandler = class {
|
|
|
3023
3538
|
* @param CollectionPage The CollectionPage constructor.
|
|
3024
3539
|
* @param filterPredicate Optional filter predicate for items.
|
|
3025
3540
|
*/
|
|
3026
|
-
constructor(name$
|
|
3027
|
-
this.name = name$
|
|
3541
|
+
constructor(name$2, values, context, callbacks, tracerProvider = _opentelemetry_api.trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate) {
|
|
3542
|
+
this.name = name$2;
|
|
3028
3543
|
this.values = values;
|
|
3029
3544
|
this.context = context;
|
|
3030
3545
|
this.callbacks = callbacks;
|
|
@@ -3737,7 +4252,7 @@ async function readLimitedResponseBody(response, maxBytes) {
|
|
|
3737
4252
|
if (truncated) result += "… (truncated)";
|
|
3738
4253
|
return result;
|
|
3739
4254
|
}
|
|
3740
|
-
async function sendActivityInternal({ activity, activityId, activityType, keys, inbox, headers, specDeterminer, meterProvider, tracerProvider }, span) {
|
|
4255
|
+
async function sendActivityInternal({ activity, activityId, activityType, keys, inbox, allowPrivateAddress, headers, specDeterminer, meterProvider, tracerProvider }, span) {
|
|
3741
4256
|
const logger = (0, _logtape_logtape.getLogger)([
|
|
3742
4257
|
"fedify",
|
|
3743
4258
|
"federation",
|
|
@@ -3746,12 +4261,25 @@ async function sendActivityInternal({ activity, activityId, activityType, keys,
|
|
|
3746
4261
|
const federationMetrics = require_http.getFederationMetrics(meterProvider);
|
|
3747
4262
|
const started = performance.now();
|
|
3748
4263
|
let deliverySuccess = false;
|
|
4264
|
+
async function validateUrl(url) {
|
|
4265
|
+
if (!allowPrivateAddress) try {
|
|
4266
|
+
await (0, _fedify_vocab_runtime.validatePublicUrl)(url);
|
|
4267
|
+
} catch (error) {
|
|
4268
|
+
if (error instanceof _fedify_vocab_runtime.UrlError) logger.error("Disallowed private URL: {url}", {
|
|
4269
|
+
url,
|
|
4270
|
+
error
|
|
4271
|
+
});
|
|
4272
|
+
throw error;
|
|
4273
|
+
}
|
|
4274
|
+
}
|
|
4275
|
+
await validateUrl(inbox.href);
|
|
3749
4276
|
headers = new Headers(headers);
|
|
3750
4277
|
headers.set("Content-Type", "application/activity+json");
|
|
3751
4278
|
const request = new Request(inbox, {
|
|
3752
4279
|
method: "POST",
|
|
3753
4280
|
headers,
|
|
3754
|
-
body: JSON.stringify(activity)
|
|
4281
|
+
body: JSON.stringify(activity),
|
|
4282
|
+
redirect: "manual"
|
|
3755
4283
|
});
|
|
3756
4284
|
let rsaKey = null;
|
|
3757
4285
|
for (const key of keys) if (key.privateKey.algorithm.name === "RSASSA-PKCS1-v1_5") {
|
|
@@ -3767,19 +4295,20 @@ async function sendActivityInternal({ activity, activityId, activityType, keys,
|
|
|
3767
4295
|
});
|
|
3768
4296
|
let response;
|
|
3769
4297
|
try {
|
|
3770
|
-
response = rsaKey == null ? await
|
|
4298
|
+
response = rsaKey == null ? await fetchWithValidatedRedirects(request, validateUrl) : await require_http.doubleKnock(request, rsaKey, {
|
|
3771
4299
|
tracerProvider,
|
|
3772
|
-
specDeterminer
|
|
4300
|
+
specDeterminer,
|
|
4301
|
+
validateRedirect: validateUrl
|
|
3773
4302
|
});
|
|
3774
4303
|
} catch (error) {
|
|
3775
|
-
const
|
|
4304
|
+
const failure = error instanceof _fedify_vocab_runtime.FetchError || error instanceof _fedify_vocab_runtime.UrlError ? error : createFetchError(inbox.href, error);
|
|
3776
4305
|
logger.error("Failed to send activity {activityId} to {inbox}:\n{error}", {
|
|
3777
4306
|
activityId,
|
|
3778
4307
|
inbox: inbox.href,
|
|
3779
|
-
error:
|
|
4308
|
+
error: failure
|
|
3780
4309
|
});
|
|
3781
4310
|
federationMetrics.recordDelivery(inbox, require_http.getDurationMs(started), false, activityType);
|
|
3782
|
-
throw
|
|
4311
|
+
throw failure;
|
|
3783
4312
|
}
|
|
3784
4313
|
try {
|
|
3785
4314
|
if (!response.ok) {
|
|
@@ -3816,6 +4345,49 @@ function createFetchError(url, cause) {
|
|
|
3816
4345
|
error.cause = cause;
|
|
3817
4346
|
return error;
|
|
3818
4347
|
}
|
|
4348
|
+
async function fetchWithValidatedRedirects(request, validateUrl) {
|
|
4349
|
+
let body = await request.clone().text();
|
|
4350
|
+
for (let redirects = 0;; redirects++) {
|
|
4351
|
+
const response = await fetch(request, { redirect: "manual" });
|
|
4352
|
+
const location = response.headers.get("Location");
|
|
4353
|
+
if (![
|
|
4354
|
+
301,
|
|
4355
|
+
302,
|
|
4356
|
+
303,
|
|
4357
|
+
307,
|
|
4358
|
+
308
|
|
4359
|
+
].includes(response.status) || location == null) return response;
|
|
4360
|
+
await response.body?.cancel();
|
|
4361
|
+
if (redirects >= 20) throw new TypeError("Too many redirects");
|
|
4362
|
+
const url = new URL(location, request.url);
|
|
4363
|
+
await validateUrl(url.href);
|
|
4364
|
+
const headers = new Headers(request.headers);
|
|
4365
|
+
if (url.origin !== new URL(request.url).origin) {
|
|
4366
|
+
headers.delete("Authorization");
|
|
4367
|
+
headers.delete("Proxy-Authorization");
|
|
4368
|
+
headers.delete("Cookie");
|
|
4369
|
+
headers.delete("Host");
|
|
4370
|
+
}
|
|
4371
|
+
let method = request.method;
|
|
4372
|
+
if ((response.status === 301 || response.status === 302) && method === "POST" || response.status === 303 && method !== "GET" && method !== "HEAD") {
|
|
4373
|
+
method = "GET";
|
|
4374
|
+
body = void 0;
|
|
4375
|
+
for (const name of [
|
|
4376
|
+
"Content-Encoding",
|
|
4377
|
+
"Content-Language",
|
|
4378
|
+
"Content-Length",
|
|
4379
|
+
"Content-Location",
|
|
4380
|
+
"Content-Type"
|
|
4381
|
+
]) headers.delete(name);
|
|
4382
|
+
}
|
|
4383
|
+
request = new Request(url, {
|
|
4384
|
+
method,
|
|
4385
|
+
headers,
|
|
4386
|
+
body,
|
|
4387
|
+
redirect: "manual"
|
|
4388
|
+
});
|
|
4389
|
+
}
|
|
4390
|
+
}
|
|
3819
4391
|
/**
|
|
3820
4392
|
* An error that is thrown when an activity fails to send to a remote inbox.
|
|
3821
4393
|
* It contains structured information about the failure, including the HTTP
|
|
@@ -4742,10 +5314,10 @@ function isPermanentRemoteContextError(error) {
|
|
|
4742
5314
|
if (!(error instanceof Error) || error.name !== "jsonld.InvalidUrl") return false;
|
|
4743
5315
|
const details = error.details;
|
|
4744
5316
|
if (details?.code === "invalid remote context") return true;
|
|
4745
|
-
return isRemoteContextLoadingFailure(error) && typeof details?.url === "string" && !URL.canParse(details.url) &&
|
|
5317
|
+
return isRemoteContextLoadingFailure(error) && typeof details?.url === "string" && !URL.canParse(details.url) && require_owner.isClearlyMalformedContextReference(details.url);
|
|
4746
5318
|
}
|
|
4747
5319
|
function isPermanentInboxParseError(error) {
|
|
4748
|
-
return error instanceof Error && (error.name === "UnsafeJsonLdError" || error instanceof
|
|
5320
|
+
return error instanceof Error && (error.name === "UnsafeJsonLdError" || error instanceof require_owner.InvalidContextReferenceError || isPermanentRemoteContextError(error) || error.name === "jsonld.SyntaxError" && !isRemoteContextLoadingFailure(error)) || error instanceof TypeError && (/^(Invalid JSON-LD:|Invalid type:|Unexpected type:|Invalid @id:)/.test(error.message) || require_owner.isInvalidUrlTypeError(error));
|
|
4749
5321
|
}
|
|
4750
5322
|
function hasLinkedDataSignatureJsonLdProcessingError(error) {
|
|
4751
5323
|
if (error.message.startsWith("Maximum deep iterations exceeded")) return true;
|
|
@@ -5309,6 +5881,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5309
5881
|
if (decision.stateChange != null) recordCircuitBreakerSpanEvent(span, remoteHost, decision.stateChange);
|
|
5310
5882
|
}
|
|
5311
5883
|
await sendActivity({
|
|
5884
|
+
allowPrivateAddress: this.allowPrivateAddress,
|
|
5312
5885
|
keys,
|
|
5313
5886
|
activity: message.activity,
|
|
5314
5887
|
activityId: message.activityId,
|
|
@@ -5596,22 +6169,22 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5596
6169
|
let parseInput = void 0;
|
|
5597
6170
|
let parseContextLoader = context.contextLoader;
|
|
5598
6171
|
try {
|
|
5599
|
-
const hasSignatureField =
|
|
6172
|
+
const hasSignatureField = require_owner.hasSignature(message.activity);
|
|
5600
6173
|
const shouldParseFromNormalizedSignedPayload = message.ldSignatureVerified === true || message.normalizedActivity != null || message.ldSignatureVerified == null && hasSignatureField;
|
|
5601
6174
|
const parseContext = hasSignatureField ? {
|
|
5602
6175
|
...context,
|
|
5603
|
-
contextLoader:
|
|
6176
|
+
contextLoader: require_owner.getNormalizationContextLoader(context.contextLoader)
|
|
5604
6177
|
} : {
|
|
5605
6178
|
...context,
|
|
5606
|
-
contextLoader:
|
|
6179
|
+
contextLoader: require_owner.wrapContextLoaderForJsonLd(context.contextLoader)
|
|
5607
6180
|
};
|
|
5608
6181
|
parseContextLoader = parseContext.contextLoader;
|
|
5609
6182
|
let normalizedActivity;
|
|
5610
6183
|
if (shouldParseFromNormalizedSignedPayload) {
|
|
5611
|
-
normalizedActivity = message.normalizedActivity ?? await
|
|
5612
|
-
|
|
6184
|
+
normalizedActivity = message.normalizedActivity ?? await require_owner.compactJsonLd(message.activity, context.contextLoader);
|
|
6185
|
+
require_owner.assertSafeJsonLd(normalizedActivity);
|
|
5613
6186
|
}
|
|
5614
|
-
parseInput = shouldParseFromNormalizedSignedPayload ?
|
|
6187
|
+
parseInput = shouldParseFromNormalizedSignedPayload ? require_owner.detachSignature(normalizedActivity) : hasSignatureField ? require_owner.detachSignature(message.activity) : message.activity;
|
|
5615
6188
|
activity = await _fedify_vocab.Activity.fromJsonLd(parseInput, parseContext);
|
|
5616
6189
|
activityType = (0, _fedify_vocab.getTypeId)(activity).href;
|
|
5617
6190
|
span.setAttribute("activitypub.activity.type", activityType);
|
|
@@ -5880,7 +6453,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5880
6453
|
}
|
|
5881
6454
|
if (!hasProof) {
|
|
5882
6455
|
for (const { keyId, privateKey } of keys) if (privateKey.algorithm.name === "Ed25519") {
|
|
5883
|
-
activity = await
|
|
6456
|
+
activity = await require_owner.signObject(activity, privateKey, keyId, {
|
|
5884
6457
|
contextLoader,
|
|
5885
6458
|
tracerProvider: this.tracerProvider
|
|
5886
6459
|
});
|
|
@@ -5892,7 +6465,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5892
6465
|
format: "compact",
|
|
5893
6466
|
contextLoader
|
|
5894
6467
|
});
|
|
5895
|
-
if (proofCreated || !hasProof || options.normalizeExistingProofs) jsonLd = await
|
|
6468
|
+
if (proofCreated || !hasProof || options.normalizeExistingProofs) jsonLd = await require_owner.normalizeOutgoingActivityJsonLd(jsonLd, contextLoader);
|
|
5896
6469
|
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.", {
|
|
5897
6470
|
activityId,
|
|
5898
6471
|
keys: keys.map((pair) => ({
|
|
@@ -5901,7 +6474,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5901
6474
|
}))
|
|
5902
6475
|
});
|
|
5903
6476
|
else try {
|
|
5904
|
-
jsonLd = await
|
|
6477
|
+
jsonLd = await require_owner.signJsonLd(jsonLd, rsaKey.privateKey, rsaKey.keyId, {
|
|
5905
6478
|
contextLoader,
|
|
5906
6479
|
tracerProvider: this.tracerProvider
|
|
5907
6480
|
});
|
|
@@ -5930,6 +6503,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5930
6503
|
});
|
|
5931
6504
|
const promises = [];
|
|
5932
6505
|
for (const inbox in inboxes) promises.push(sendActivity({
|
|
6506
|
+
allowPrivateAddress: this.allowPrivateAddress,
|
|
5933
6507
|
keys,
|
|
5934
6508
|
activity: jsonLd,
|
|
5935
6509
|
activityId: activity.id?.href,
|
|
@@ -6868,7 +7442,7 @@ var ContextImpl = class ContextImpl {
|
|
|
6868
7442
|
const contextLoader = this.contextLoader;
|
|
6869
7443
|
for (const kp of actorKeyPairs) {
|
|
6870
7444
|
if (kp.privateKey.algorithm.name !== "Ed25519" || kp.multikey.id == null) continue;
|
|
6871
|
-
activity = await
|
|
7445
|
+
activity = await require_owner.signObject(activity, kp.privateKey, kp.multikey.id, {
|
|
6872
7446
|
contextLoader,
|
|
6873
7447
|
tracerProvider: this.tracerProvider
|
|
6874
7448
|
});
|
|
@@ -6998,7 +7572,7 @@ var ContextImpl = class ContextImpl {
|
|
|
6998
7572
|
tracerProvider: this.tracerProvider,
|
|
6999
7573
|
keyTtl: this.federation.publicKeyTtl
|
|
7000
7574
|
});
|
|
7001
|
-
if (await
|
|
7575
|
+
if (await require_owner.verifyObject(_fedify_vocab.Activity, json, {
|
|
7002
7576
|
contextLoader,
|
|
7003
7577
|
documentLoader: options.documentLoader ?? this.documentLoader,
|
|
7004
7578
|
meterProvider: this.meterProvider,
|
|
@@ -7155,7 +7729,7 @@ var RequestContextImpl = class RequestContextImpl extends ContextImpl {
|
|
|
7155
7729
|
const key = await this.getSignedKey(options);
|
|
7156
7730
|
if (key == null) return this.#signedKeyOwner = null;
|
|
7157
7731
|
try {
|
|
7158
|
-
return this.#signedKeyOwner = await
|
|
7732
|
+
return this.#signedKeyOwner = await require_owner.getKeyOwner(key, {
|
|
7159
7733
|
contextLoader: options.contextLoader ?? this.contextLoader,
|
|
7160
7734
|
documentLoader: options.documentLoader ?? this.documentLoader,
|
|
7161
7735
|
tracerProvider: options.tracerProvider ?? this.tracerProvider
|
|
@@ -7225,8 +7799,8 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
|
|
|
7225
7799
|
if (forwarder.length < 1) throw new Error("The forwarder's key pairs are empty.");
|
|
7226
7800
|
keys = forwarder;
|
|
7227
7801
|
} else keys = [forwarder];
|
|
7228
|
-
if (!
|
|
7229
|
-
if (!
|
|
7802
|
+
if (!require_owner.hasSignatureLike(ctx.activity)) {
|
|
7803
|
+
if (!require_owner.hasProofLike(ctx.activity)) {
|
|
7230
7804
|
if (options?.skipIfUnsigned) return false;
|
|
7231
7805
|
logger.warn("The 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.", {
|
|
7232
7806
|
activityId: ctx.activityId,
|
|
@@ -7264,6 +7838,7 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
|
|
|
7264
7838
|
else logger.debug("Forwarding activity immediately without queue since queue is not set.");
|
|
7265
7839
|
const promises = [];
|
|
7266
7840
|
for (const inbox in inboxes) promises.push(sendActivity({
|
|
7841
|
+
allowPrivateAddress: ctx.federation.allowPrivateAddress,
|
|
7267
7842
|
keys,
|
|
7268
7843
|
activity: ctx.activity,
|
|
7269
7844
|
activityId: ctx.activityId,
|