@fedify/fedify 2.4.0-dev.1988 → 2.4.0-dev.2010
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-Cts78G9N.mjs → builder-asm96yV1.mjs} +2 -2
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/compound-proof-7UIAueLV.mjs +495 -0
- package/dist/{deno-BgMEefEr.mjs → deno-Ckq9TwCv.mjs} +1 -1
- package/dist/{docloader-DEYs99FZ.mjs → docloader-DUKEPG-O.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 +5 -5
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +7 -7
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.js +1 -1
- package/dist/federation/send.test.mjs +3 -3
- 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-DzPUG_AP.cjs → federation-CgbvMauV.cjs} +542 -43
- package/dist/{http-CgwqtxAy.js → http-DQA2JOEJ.js} +2 -2
- package/dist/{http-Z3anvCd-.cjs → http-DQBfmkrS.cjs} +2 -2
- package/dist/{http-CtidZS_t.mjs → http-DZaAutqg.mjs} +3 -3
- package/dist/{key-Cwbg5ggV.mjs → key-zxzx01Ec.mjs} +2 -2
- package/dist/{kv-cache-CykuL0ya.js → kv-cache-BBoePTOJ.js} +1 -1
- package/dist/{kv-cache-DHiR8yTf.mjs → kv-cache-CbrUX90H.mjs} +1 -1
- package/dist/{kv-cache-BM2-w-Wq.cjs → kv-cache-sy8OMNT8.cjs} +1 -1
- package/dist/{ld-CzhdWyTt.mjs → ld-CD_TN0e8.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-CrqsHP0l.mjs → metrics-B47Cm5gK.mjs} +1 -1
- package/dist/{middleware-CeCj5caM.js → middleware-U0OIuqwD.js} +511 -12
- package/dist/{middleware-CZpYxSKD.mjs → middleware-U_Gannqi.mjs} +1 -1
- package/dist/{middleware-DCpiAsZi.mjs → middleware-pHwDTAnq.mjs} +52 -20
- package/dist/mod.cjs +19 -19
- package/dist/mod.js +4 -4
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/{proof-DHu5zI0Z.cjs → owner--mNatWct.cjs} +1252 -1140
- package/dist/{proof-CUghqhAf.js → owner-BNKC3s6G.js} +1239 -1139
- package/dist/{owner-BqVXJLW8.mjs → owner-u3IJRhVx.mjs} +2 -2
- package/dist/{proof-DL8Iid3a.mjs → proof-D3te0SP-.mjs} +176 -76
- package/dist/{send-6jS4xFsX.mjs → send-CDr0Zivk.mjs} +3 -3
- 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 +1 -1
- package/dist/sig/ld.test.mjs +2 -2
- package/dist/sig/mod.cjs +17 -17
- 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-DcyzeytP.mjs → temporal-DKhVF_Uk.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- 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 +6 -6
|
@@ -1,10 +1,10 @@
|
|
|
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-
|
|
4
|
+
const require_http = require("./http-DQBfmkrS.cjs");
|
|
5
5
|
const require_types = require("./types-Be2zbyeG.cjs");
|
|
6
|
-
const
|
|
7
|
-
const require_kv_cache = require("./kv-cache-
|
|
6
|
+
const require_owner = require("./owner--mNatWct.cjs");
|
|
7
|
+
const require_kv_cache = require("./kv-cache-sy8OMNT8.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");
|
|
@@ -12,9 +12,9 @@ let _opentelemetry_api = require("@opentelemetry/api");
|
|
|
12
12
|
let byte_encodings_hex = require("byte-encodings/hex");
|
|
13
13
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
14
14
|
let es_toolkit = require("es-toolkit");
|
|
15
|
-
let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
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 }) {
|
|
@@ -1733,7 +2201,7 @@ function hasMalformedKnownTemporalLiteralInternal(value, visited) {
|
|
|
1733
2201
|
async function hasMalformedKnownTemporalLiteral(value, contextLoader) {
|
|
1734
2202
|
try {
|
|
1735
2203
|
return hasMalformedKnownTemporalLiteralInternal(await _fedify_vocab_runtime_jsonld.default.expand(value, {
|
|
1736
|
-
documentLoader:
|
|
2204
|
+
documentLoader: require_owner.getNormalizationContextLoader(contextLoader),
|
|
1737
2205
|
keepFreeFloatingNodes: true
|
|
1738
2206
|
}), /* @__PURE__ */ new Set());
|
|
1739
2207
|
} catch {
|
|
@@ -1744,6 +2212,12 @@ async function hasMalformedKnownTemporalLiteral(value, contextLoader) {
|
|
|
1744
2212
|
//#region src/federation/handler.ts
|
|
1745
2213
|
const Temporal$6 = require_http.Temporal;
|
|
1746
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
|
+
};
|
|
1747
2221
|
function isRemoteContextLoadingFailure$1(error) {
|
|
1748
2222
|
return error instanceof Error && typeof error.details === "object" && error.details != null && error.details.code === "loading remote context failed";
|
|
1749
2223
|
}
|
|
@@ -1751,15 +2225,15 @@ function isPermanentRemoteContextError$1(error) {
|
|
|
1751
2225
|
if (!(error instanceof Error) || error.name !== "jsonld.InvalidUrl") return false;
|
|
1752
2226
|
const details = error.details;
|
|
1753
2227
|
if (details?.code === "invalid remote context") return true;
|
|
1754
|
-
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);
|
|
1755
2229
|
}
|
|
1756
2230
|
function isInvalidJsonLdError(error) {
|
|
1757
2231
|
if (!(error instanceof Error)) return false;
|
|
1758
2232
|
const name = error.name;
|
|
1759
|
-
return name === "UnsafeJsonLdError" || error instanceof
|
|
2233
|
+
return name === "UnsafeJsonLdError" || error instanceof require_owner.InvalidContextReferenceError || isPermanentRemoteContextError$1(error) || name === "jsonld.SyntaxError" && !isRemoteContextLoadingFailure$1(error);
|
|
1760
2234
|
}
|
|
1761
2235
|
function isValidationTypeError(error) {
|
|
1762
|
-
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));
|
|
1763
2237
|
}
|
|
1764
2238
|
function isPermanentActivityParseError(error) {
|
|
1765
2239
|
return isInvalidJsonLdError(error) || isValidationTypeError(error);
|
|
@@ -1868,13 +2342,13 @@ function recordCollectionMetrics(meterProvider, base, result, options = {}) {
|
|
|
1868
2342
|
* @param parameters The parameters for handling the collection.
|
|
1869
2343
|
* @returns A promise that resolves to an HTTP response.
|
|
1870
2344
|
*/
|
|
1871
|
-
async function handleCollection(request, { name: name$
|
|
1872
|
-
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, "_");
|
|
1873
2347
|
tracerProvider = tracerProvider ?? _opentelemetry_api.trace.getTracerProvider();
|
|
1874
2348
|
const tracer = tracerProvider.getTracer(require_http.name, require_http.version);
|
|
1875
2349
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
1876
2350
|
const metricBase = {
|
|
1877
|
-
kind: getCollectionMetricKind(name$
|
|
2351
|
+
kind: getCollectionMetricKind(name$1),
|
|
1878
2352
|
page: cursor != null,
|
|
1879
2353
|
dispatcher: "built_in"
|
|
1880
2354
|
};
|
|
@@ -1915,7 +2389,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
|
|
|
1915
2389
|
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
1916
2390
|
return await onNotFound(request);
|
|
1917
2391
|
}
|
|
1918
|
-
const items = filterCollectionItems(page.items, name$
|
|
2392
|
+
const items = filterCollectionItems(page.items, name$1, filterPredicate);
|
|
1919
2393
|
itemCount = items.length;
|
|
1920
2394
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
1921
2395
|
return items;
|
|
@@ -1955,7 +2429,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
|
|
|
1955
2429
|
} else {
|
|
1956
2430
|
const uri = new URL(baseUri);
|
|
1957
2431
|
uri.searchParams.set("cursor", cursor);
|
|
1958
|
-
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$
|
|
2432
|
+
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
|
|
1959
2433
|
kind: _opentelemetry_api.SpanKind.SERVER,
|
|
1960
2434
|
attributes: {
|
|
1961
2435
|
"activitypub.collection.id": uri.href,
|
|
@@ -1971,7 +2445,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
|
|
|
1971
2445
|
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
1972
2446
|
return await onNotFound(request);
|
|
1973
2447
|
}
|
|
1974
|
-
const items = filterCollectionItems(page.items, name$
|
|
2448
|
+
const items = filterCollectionItems(page.items, name$1, filterPredicate);
|
|
1975
2449
|
itemCount = items.length;
|
|
1976
2450
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
1977
2451
|
return {
|
|
@@ -2562,8 +3036,8 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2562
3036
|
tracerProvider,
|
|
2563
3037
|
keyTtl: publicKeyTtl
|
|
2564
3038
|
});
|
|
2565
|
-
const jsonWithoutSig =
|
|
2566
|
-
const hasLdSignature =
|
|
3039
|
+
const jsonWithoutSig = require_owner.detachSignature(json);
|
|
3040
|
+
const hasLdSignature = require_owner.hasSignature(json);
|
|
2567
3041
|
const canAttemptAlternateAuthAfterLdSignatureFailure = skipSignatureVerification || hasHttpSignatureHeaders(request) || hasObjectIntegrityProof(jsonWithoutSig);
|
|
2568
3042
|
let deferredLdSignatureError = void 0;
|
|
2569
3043
|
const respondInvalidActivity = async (error) => {
|
|
@@ -2595,7 +3069,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2595
3069
|
let ldSigVerified = false;
|
|
2596
3070
|
if (hasLdSignature) {
|
|
2597
3071
|
try {
|
|
2598
|
-
compactedJson = await
|
|
3072
|
+
compactedJson = await require_owner.compactJsonLd(json, ctx.contextLoader);
|
|
2599
3073
|
} catch (error) {
|
|
2600
3074
|
if (isInvalidJsonLdError(error)) {
|
|
2601
3075
|
logger.error("Failed to parse JSON-LD:\n{error}", {
|
|
@@ -2615,9 +3089,9 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2615
3089
|
});
|
|
2616
3090
|
}
|
|
2617
3091
|
if (compactedJson !== json) {
|
|
2618
|
-
compactedJsonWithoutSig =
|
|
3092
|
+
compactedJsonWithoutSig = require_owner.detachSignature(compactedJson);
|
|
2619
3093
|
try {
|
|
2620
|
-
ldSigVerified = await
|
|
3094
|
+
ldSigVerified = await require_owner.verifyCompactJsonLd(compactedJson, {
|
|
2621
3095
|
contextLoader: ctx.contextLoader,
|
|
2622
3096
|
documentLoader: ctx.documentLoader,
|
|
2623
3097
|
keyCache,
|
|
@@ -2639,7 +3113,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2639
3113
|
if (!canAttemptAlternateAuthAfterLdSignatureFailure) throw error;
|
|
2640
3114
|
if (!skipSignatureVerification) try {
|
|
2641
3115
|
await _fedify_vocab.Object.fromJsonLd(compactedJson, {
|
|
2642
|
-
contextLoader:
|
|
3116
|
+
contextLoader: require_owner.getNormalizationContextLoader(ctx.contextLoader),
|
|
2643
3117
|
documentLoader: ctx.documentLoader,
|
|
2644
3118
|
tracerProvider
|
|
2645
3119
|
});
|
|
@@ -2671,7 +3145,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2671
3145
|
try {
|
|
2672
3146
|
activity = await _fedify_vocab.Activity.fromJsonLd(compactedJsonWithoutSig, {
|
|
2673
3147
|
...ctx,
|
|
2674
|
-
contextLoader:
|
|
3148
|
+
contextLoader: require_owner.getNormalizationContextLoader(ctx.contextLoader)
|
|
2675
3149
|
});
|
|
2676
3150
|
} catch (error) {
|
|
2677
3151
|
if (error instanceof RangeError && await hasMalformedKnownTemporalLiteral(compactedJsonWithoutSig, ctx.contextLoader)) return await respondInvalidActivity(error);
|
|
@@ -2685,8 +3159,8 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2685
3159
|
json
|
|
2686
3160
|
});
|
|
2687
3161
|
try {
|
|
2688
|
-
activity = await
|
|
2689
|
-
contextLoader:
|
|
3162
|
+
activity = await require_owner.verifyObject(_fedify_vocab.Activity, jsonWithoutSig, {
|
|
3163
|
+
contextLoader: require_owner.wrapContextLoaderForJsonLd(ctx.contextLoader),
|
|
2690
3164
|
documentLoader: ctx.documentLoader,
|
|
2691
3165
|
keyCache,
|
|
2692
3166
|
meterProvider,
|
|
@@ -2831,7 +3305,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2831
3305
|
try {
|
|
2832
3306
|
activity = await _fedify_vocab.Activity.fromJsonLd(jsonWithoutSig, {
|
|
2833
3307
|
...ctx,
|
|
2834
|
-
contextLoader:
|
|
3308
|
+
contextLoader: require_owner.wrapContextLoaderForJsonLd(ctx.contextLoader)
|
|
2835
3309
|
});
|
|
2836
3310
|
} catch (error) {
|
|
2837
3311
|
if (!isPermanentActivityParseError(error)) throw error;
|
|
@@ -2847,7 +3321,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2847
3321
|
"http_signatures.verified": httpSigKey != null,
|
|
2848
3322
|
"http_signatures.key_id": httpSigKey?.id?.href ?? ""
|
|
2849
3323
|
});
|
|
2850
|
-
if (httpSigKey != null && !await
|
|
3324
|
+
if (httpSigKey != null && !await require_owner.doesActorOwnKey(activity, httpSigKey, ctx)) {
|
|
2851
3325
|
if (deferredLdSignatureError != null) throw deferredLdSignatureError;
|
|
2852
3326
|
require_http.getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure("actorKeyMismatch", httpSigKey.id == null ? void 0 : require_http.getRemoteHost(httpSigKey.id));
|
|
2853
3327
|
logger.error("The signer ({keyId}) and the actor ({actorId}) do not match.", {
|
|
@@ -2865,6 +3339,31 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2865
3339
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
2866
3340
|
});
|
|
2867
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
|
+
}
|
|
2868
3367
|
if (pendingNonceLabel != null) {
|
|
2869
3368
|
if (!await verifySignatureNonce(request, kv, kvPrefixes.acceptSignatureNonce, pendingNonceLabel)) {
|
|
2870
3369
|
require_http.getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure("invalidNonce", httpSigKey?.id == null ? void 0 : require_http.getRemoteHost(httpSigKey.id));
|
|
@@ -3039,8 +3538,8 @@ var CustomCollectionHandler = class {
|
|
|
3039
3538
|
* @param CollectionPage The CollectionPage constructor.
|
|
3040
3539
|
* @param filterPredicate Optional filter predicate for items.
|
|
3041
3540
|
*/
|
|
3042
|
-
constructor(name$
|
|
3043
|
-
this.name = name$
|
|
3541
|
+
constructor(name$2, values, context, callbacks, tracerProvider = _opentelemetry_api.trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate) {
|
|
3542
|
+
this.name = name$2;
|
|
3044
3543
|
this.values = values;
|
|
3045
3544
|
this.context = context;
|
|
3046
3545
|
this.callbacks = callbacks;
|
|
@@ -4815,10 +5314,10 @@ function isPermanentRemoteContextError(error) {
|
|
|
4815
5314
|
if (!(error instanceof Error) || error.name !== "jsonld.InvalidUrl") return false;
|
|
4816
5315
|
const details = error.details;
|
|
4817
5316
|
if (details?.code === "invalid remote context") return true;
|
|
4818
|
-
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);
|
|
4819
5318
|
}
|
|
4820
5319
|
function isPermanentInboxParseError(error) {
|
|
4821
|
-
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));
|
|
4822
5321
|
}
|
|
4823
5322
|
function hasLinkedDataSignatureJsonLdProcessingError(error) {
|
|
4824
5323
|
if (error.message.startsWith("Maximum deep iterations exceeded")) return true;
|
|
@@ -5670,22 +6169,22 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5670
6169
|
let parseInput = void 0;
|
|
5671
6170
|
let parseContextLoader = context.contextLoader;
|
|
5672
6171
|
try {
|
|
5673
|
-
const hasSignatureField =
|
|
6172
|
+
const hasSignatureField = require_owner.hasSignature(message.activity);
|
|
5674
6173
|
const shouldParseFromNormalizedSignedPayload = message.ldSignatureVerified === true || message.normalizedActivity != null || message.ldSignatureVerified == null && hasSignatureField;
|
|
5675
6174
|
const parseContext = hasSignatureField ? {
|
|
5676
6175
|
...context,
|
|
5677
|
-
contextLoader:
|
|
6176
|
+
contextLoader: require_owner.getNormalizationContextLoader(context.contextLoader)
|
|
5678
6177
|
} : {
|
|
5679
6178
|
...context,
|
|
5680
|
-
contextLoader:
|
|
6179
|
+
contextLoader: require_owner.wrapContextLoaderForJsonLd(context.contextLoader)
|
|
5681
6180
|
};
|
|
5682
6181
|
parseContextLoader = parseContext.contextLoader;
|
|
5683
6182
|
let normalizedActivity;
|
|
5684
6183
|
if (shouldParseFromNormalizedSignedPayload) {
|
|
5685
|
-
normalizedActivity = message.normalizedActivity ?? await
|
|
5686
|
-
|
|
6184
|
+
normalizedActivity = message.normalizedActivity ?? await require_owner.compactJsonLd(message.activity, context.contextLoader);
|
|
6185
|
+
require_owner.assertSafeJsonLd(normalizedActivity);
|
|
5687
6186
|
}
|
|
5688
|
-
parseInput = shouldParseFromNormalizedSignedPayload ?
|
|
6187
|
+
parseInput = shouldParseFromNormalizedSignedPayload ? require_owner.detachSignature(normalizedActivity) : hasSignatureField ? require_owner.detachSignature(message.activity) : message.activity;
|
|
5689
6188
|
activity = await _fedify_vocab.Activity.fromJsonLd(parseInput, parseContext);
|
|
5690
6189
|
activityType = (0, _fedify_vocab.getTypeId)(activity).href;
|
|
5691
6190
|
span.setAttribute("activitypub.activity.type", activityType);
|
|
@@ -5954,7 +6453,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5954
6453
|
}
|
|
5955
6454
|
if (!hasProof) {
|
|
5956
6455
|
for (const { keyId, privateKey } of keys) if (privateKey.algorithm.name === "Ed25519") {
|
|
5957
|
-
activity = await
|
|
6456
|
+
activity = await require_owner.signObject(activity, privateKey, keyId, {
|
|
5958
6457
|
contextLoader,
|
|
5959
6458
|
tracerProvider: this.tracerProvider
|
|
5960
6459
|
});
|
|
@@ -5966,7 +6465,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5966
6465
|
format: "compact",
|
|
5967
6466
|
contextLoader
|
|
5968
6467
|
});
|
|
5969
|
-
if (proofCreated || !hasProof || options.normalizeExistingProofs) jsonLd = await
|
|
6468
|
+
if (proofCreated || !hasProof || options.normalizeExistingProofs) jsonLd = await require_owner.normalizeOutgoingActivityJsonLd(jsonLd, contextLoader);
|
|
5970
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.", {
|
|
5971
6470
|
activityId,
|
|
5972
6471
|
keys: keys.map((pair) => ({
|
|
@@ -5975,7 +6474,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5975
6474
|
}))
|
|
5976
6475
|
});
|
|
5977
6476
|
else try {
|
|
5978
|
-
jsonLd = await
|
|
6477
|
+
jsonLd = await require_owner.signJsonLd(jsonLd, rsaKey.privateKey, rsaKey.keyId, {
|
|
5979
6478
|
contextLoader,
|
|
5980
6479
|
tracerProvider: this.tracerProvider
|
|
5981
6480
|
});
|
|
@@ -6943,7 +7442,7 @@ var ContextImpl = class ContextImpl {
|
|
|
6943
7442
|
const contextLoader = this.contextLoader;
|
|
6944
7443
|
for (const kp of actorKeyPairs) {
|
|
6945
7444
|
if (kp.privateKey.algorithm.name !== "Ed25519" || kp.multikey.id == null) continue;
|
|
6946
|
-
activity = await
|
|
7445
|
+
activity = await require_owner.signObject(activity, kp.privateKey, kp.multikey.id, {
|
|
6947
7446
|
contextLoader,
|
|
6948
7447
|
tracerProvider: this.tracerProvider
|
|
6949
7448
|
});
|
|
@@ -7073,7 +7572,7 @@ var ContextImpl = class ContextImpl {
|
|
|
7073
7572
|
tracerProvider: this.tracerProvider,
|
|
7074
7573
|
keyTtl: this.federation.publicKeyTtl
|
|
7075
7574
|
});
|
|
7076
|
-
if (await
|
|
7575
|
+
if (await require_owner.verifyObject(_fedify_vocab.Activity, json, {
|
|
7077
7576
|
contextLoader,
|
|
7078
7577
|
documentLoader: options.documentLoader ?? this.documentLoader,
|
|
7079
7578
|
meterProvider: this.meterProvider,
|
|
@@ -7230,7 +7729,7 @@ var RequestContextImpl = class RequestContextImpl extends ContextImpl {
|
|
|
7230
7729
|
const key = await this.getSignedKey(options);
|
|
7231
7730
|
if (key == null) return this.#signedKeyOwner = null;
|
|
7232
7731
|
try {
|
|
7233
|
-
return this.#signedKeyOwner = await
|
|
7732
|
+
return this.#signedKeyOwner = await require_owner.getKeyOwner(key, {
|
|
7234
7733
|
contextLoader: options.contextLoader ?? this.contextLoader,
|
|
7235
7734
|
documentLoader: options.documentLoader ?? this.documentLoader,
|
|
7236
7735
|
tracerProvider: options.tracerProvider ?? this.tracerProvider
|
|
@@ -7300,8 +7799,8 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
|
|
|
7300
7799
|
if (forwarder.length < 1) throw new Error("The forwarder's key pairs are empty.");
|
|
7301
7800
|
keys = forwarder;
|
|
7302
7801
|
} else keys = [forwarder];
|
|
7303
|
-
if (!
|
|
7304
|
-
if (!
|
|
7802
|
+
if (!require_owner.hasSignatureLike(ctx.activity)) {
|
|
7803
|
+
if (!require_owner.hasProofLike(ctx.activity)) {
|
|
7305
7804
|
if (options?.skipIfUnsigned) return false;
|
|
7306
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.", {
|
|
7307
7806
|
activityId: ctx.activityId,
|