@fedify/fedify 2.4.0-dev.2256 → 2.4.0-dev.2260
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-DvSQqk2l.mjs → builder-BK8HfSUm.mjs} +8 -2
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{compound-proof-5bg_j_ye.mjs → compound-proof-D--HeIbV.mjs} +41 -4
- package/dist/{context-CtI307_A.d.ts → context-7NyiqIcg.d.ts} +111 -2
- package/dist/{context-B6X-t8gI.d.cts → context-tsYPJ2Ew.d.cts} +111 -2
- package/dist/{deno-AmcRMq5z.mjs → deno-DVP7DGJC.mjs} +1 -1
- package/dist/{docloader-CIP_SG39.mjs → docloader-Dv1JJl37.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/compound-fanout.test.mjs +3 -3
- package/dist/federation/handler-compound-proof.test.mjs +3 -3
- package/dist/federation/handler.test.mjs +76 -5
- package/dist/federation/hashlink-media.test.mjs +2 -2
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/inbox-report.test.d.mts +2 -0
- package/dist/federation/inbox-report.test.mjs +475 -0
- 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.d.cts +4 -3
- package/dist/federation/mod.d.ts +4 -3
- package/dist/federation/mod.js +1 -1
- package/dist/federation/outgoing-proof.test.mjs +54 -10
- package/dist/federation/portable-actor.test.mjs +3 -3
- package/dist/federation/portable-chain.test.mjs +3 -3
- package/dist/federation/portable-collection.test.mjs +66 -4
- package/dist/federation/portable-delivery.test.mjs +2 -2
- package/dist/federation/portable-gateway-keys.test.mjs +4 -4
- package/dist/federation/portable-inbox.test.mjs +67 -6
- package/dist/federation/portable-parse-uri.test.mjs +1 -1
- package/dist/federation/portable-route-activity.test.mjs +2 -2
- package/dist/federation/portable.test.mjs +3 -3
- 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-BDzIgqOd.cjs → federation-Bo5z395X.cjs} +552 -122
- package/dist/{http-1fZ83jj7.cjs → http-BIhWdDf5.cjs} +447 -110
- package/dist/{http-BGb3QioZ.js → http-DRMu1C2T.js} +430 -111
- package/dist/{http-DkqWu-sm.mjs → http-DvpuyDJB.mjs} +141 -98
- package/dist/{key-CEsu7oaD.mjs → key-B7N8mNoY.mjs} +30 -3
- package/dist/{http-BrwKINQn.d.cts → key-C1nv7_jD.d.ts} +638 -229
- package/dist/{http-DGx0KOws.d.ts → key-DYxuyd-s.d.cts} +638 -229
- package/dist/{kv-cache-CJS4mImS.mjs → kv-cache-D0kA0rml.mjs} +1 -1
- package/dist/{kv-cache-CGhEgt98.js → kv-cache-DZLpqhW9.js} +1 -1
- package/dist/{kv-cache-BEWuZSB4.cjs → kv-cache-mF8Zmjix.cjs} +1 -1
- package/dist/{ld-Cf4CPWN_.mjs → ld-BDMNyM2M.mjs} +40 -5
- package/dist/{metrics-CocsZP0E.mjs → metrics-BbBj-VZN.mjs} +2 -1
- package/dist/{middleware-Cne_jMZo.mjs → middleware-CE1X7-UM.mjs} +1 -1
- package/dist/{middleware-Dxn0E9ES.mjs → middleware-DAA7wDdS.mjs} +520 -131
- package/dist/{middleware-BfYke3YQ.js → middleware-DfUWPAa-.js} +552 -122
- package/dist/{mod-C7_2j7VT.d.cts → mod-BojP2Bw3.d.cts} +1 -1
- package/dist/{mod-BlLwewYe.d.ts → mod-CavhAgLw.d.cts} +5 -255
- package/dist/{mod-VHYh1lTK.d.cts → mod-CtpF2BU5.d.ts} +5 -255
- package/dist/{mod-B8MI1mpi.d.ts → mod-DEZXwV6J.d.ts} +1 -1
- package/dist/{mod-DFL6IxYQ.d.cts → mod-Dw-nPxQh.d.cts} +1 -1
- package/dist/{mod-BhTaDR5H.d.ts → mod-Xj5P4s4d.d.ts} +1 -1
- package/dist/mod.cjs +4 -4
- package/dist/mod.d.cts +7 -7
- package/dist/mod.d.ts +7 -7
- package/dist/mod.js +4 -4
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/{owner-DSJ7nFgy.mjs → owner-CzUycuhd.mjs} +3 -3
- package/dist/{portable-collection-BuBV6xTo.js → portable-collection-COcJxZg_.js} +1 -1
- package/dist/{portable-collection-qskqXJrH.mjs → portable-collection-CTcNJiAa.mjs} +2 -2
- package/dist/{portable-collection-r-mHg1PV.cjs → portable-collection-cPMffcHJ.cjs} +1 -1
- package/dist/{portable-key-woGH_1nn.mjs → portable-key-B4QN3OzR.mjs} +1 -1
- package/dist/{proof-8WiH_-Gq.mjs → proof-nce4pf5S.mjs} +133 -16
- package/dist/{send-JKzZBgPU.mjs → send-4Idpe2z0.mjs} +3 -3
- package/dist/sig/compound-proof-discovery.test.mjs +1 -1
- package/dist/sig/compound-proof-producer.test.mjs +1 -1
- package/dist/sig/compound-proof-verification.test.mjs +19 -2
- package/dist/sig/compound-proof.test.mjs +2 -2
- 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/mitra-receive-interop.test.mjs +4 -4
- package/dist/sig/mitra-send-interop.test.mjs +3 -3
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.d.cts +2 -2
- package/dist/sig/mod.d.ts +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/portable-collection.test.mjs +1 -1
- package/dist/sig/portable-interop.test.mjs +3 -3
- package/dist/sig/portable-key.test.mjs +6 -6
- package/dist/sig/proof.test.mjs +76 -3
- package/dist/sig/tootik-request-interop.test.mjs +4 -4
- package/dist/sig/tootik-send-interop.test.mjs +3 -3
- package/dist/sig/verification.test.d.mts +2 -0
- package/dist/sig/verification.test.mjs +310 -0
- package/dist/{temporal-CT3fRaMH.mjs → temporal-BbjmPHYn.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- package/dist/testing/mod.d.mts +315 -28
- 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.d.cts +1 -1
- package/dist/utils/mod.d.ts +1 -1
- package/dist/utils/mod.js +1 -1
- package/dist/verification-C3954hQh.mjs +5 -0
- package/dist/verification-Dpfcw8ml.mjs +105 -0
- package/package.json +7 -7
|
@@ -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-BIhWdDf5.cjs");
|
|
5
5
|
const require_types = require("./types-poIao40f.cjs");
|
|
6
|
-
const require_portable_collection = require("./portable-collection-
|
|
7
|
-
const require_kv_cache = require("./kv-cache-
|
|
6
|
+
const require_portable_collection = require("./portable-collection-cPMffcHJ.cjs");
|
|
7
|
+
const require_kv_cache = require("./kv-cache-mF8Zmjix.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");
|
|
@@ -100,6 +100,7 @@ var FederationBuilderImpl = class {
|
|
|
100
100
|
featuredTagsCallbacks;
|
|
101
101
|
inboxListeners;
|
|
102
102
|
outboxListeners;
|
|
103
|
+
inboxRequestFinishedHandler;
|
|
103
104
|
inboxErrorHandler;
|
|
104
105
|
outboxListenerErrorHandler;
|
|
105
106
|
outboxAuthorizePredicate;
|
|
@@ -161,6 +162,7 @@ var FederationBuilderImpl = class {
|
|
|
161
162
|
f.featuredTagsCallbacks = this.featuredTagsCallbacks == null ? void 0 : { ...this.featuredTagsCallbacks };
|
|
162
163
|
f.inboxListeners = this.inboxListeners?.clone();
|
|
163
164
|
f.outboxListeners = this.outboxListeners?.clone();
|
|
165
|
+
f.inboxRequestFinishedHandler = this.inboxRequestFinishedHandler;
|
|
164
166
|
f.inboxErrorHandler = this.inboxErrorHandler;
|
|
165
167
|
f.outboxListenerErrorHandler = this.outboxListenerErrorHandler;
|
|
166
168
|
f.outboxAuthorizePredicate = this.outboxAuthorizePredicate;
|
|
@@ -641,6 +643,10 @@ var FederationBuilderImpl = class {
|
|
|
641
643
|
this.inboxErrorHandler = handler;
|
|
642
644
|
return setters;
|
|
643
645
|
},
|
|
646
|
+
onRequestFinished: (handler) => {
|
|
647
|
+
this.inboxRequestFinishedHandler = handler;
|
|
648
|
+
return setters;
|
|
649
|
+
},
|
|
644
650
|
onUnverifiedActivity: (handler) => {
|
|
645
651
|
this.unverifiedActivityHandler = handler;
|
|
646
652
|
return setters;
|
|
@@ -1447,6 +1453,111 @@ async function buildCollectionSynchronizationHeader(collectionId, actorIds) {
|
|
|
1447
1453
|
return `collectionId="${collectionId}", url="${url}", digest="${(0, byte_encodings_hex.encodeHex)(await digest(actorIds))}"`;
|
|
1448
1454
|
}
|
|
1449
1455
|
//#endregion
|
|
1456
|
+
//#region src/federation/inbox-observation.ts
|
|
1457
|
+
/** Internal state owned by the ingress boundary, never serialized into queues. */
|
|
1458
|
+
var InboxObservation = class {
|
|
1459
|
+
inbox;
|
|
1460
|
+
payload = { status: "unavailable" };
|
|
1461
|
+
activity = null;
|
|
1462
|
+
authentication = { status: "notDetermined" };
|
|
1463
|
+
hasException = false;
|
|
1464
|
+
stage = "prepare";
|
|
1465
|
+
result = {
|
|
1466
|
+
disposition: "rejected",
|
|
1467
|
+
reason: "recipientNotFound"
|
|
1468
|
+
};
|
|
1469
|
+
verification = {
|
|
1470
|
+
attempts: [],
|
|
1471
|
+
subject: {
|
|
1472
|
+
id: null,
|
|
1473
|
+
pointer: ""
|
|
1474
|
+
},
|
|
1475
|
+
parsedObject: (object) => {
|
|
1476
|
+
if (object instanceof _fedify_vocab.Activity) {
|
|
1477
|
+
this.activity = object;
|
|
1478
|
+
this.verification.subject.id = object.id == null ? null : new URL(object.id.href);
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
constructor(inbox) {
|
|
1483
|
+
this.inbox = inbox;
|
|
1484
|
+
}
|
|
1485
|
+
/** Run an ingress operation and project telemetry; fetch owns completion. */
|
|
1486
|
+
async run(operation, span) {
|
|
1487
|
+
let response;
|
|
1488
|
+
let outcome;
|
|
1489
|
+
let threw = false;
|
|
1490
|
+
let originalError;
|
|
1491
|
+
try {
|
|
1492
|
+
response = await operation();
|
|
1493
|
+
outcome = {
|
|
1494
|
+
type: "response",
|
|
1495
|
+
status: response.status,
|
|
1496
|
+
...this.result
|
|
1497
|
+
};
|
|
1498
|
+
} catch (error) {
|
|
1499
|
+
threw = true;
|
|
1500
|
+
this.hasException = true;
|
|
1501
|
+
originalError = error;
|
|
1502
|
+
outcome = {
|
|
1503
|
+
type: "exception",
|
|
1504
|
+
stage: this.stage,
|
|
1505
|
+
error
|
|
1506
|
+
};
|
|
1507
|
+
}
|
|
1508
|
+
if (span != null) this.project(span, outcome);
|
|
1509
|
+
if (threw) throw originalError;
|
|
1510
|
+
return response;
|
|
1511
|
+
}
|
|
1512
|
+
/** Complete standalone handler calls that have no enclosing fetch boundary. */
|
|
1513
|
+
async runAndFinish(getContext, handler, operation) {
|
|
1514
|
+
let response;
|
|
1515
|
+
try {
|
|
1516
|
+
response = await this.run(operation);
|
|
1517
|
+
} catch (error) {
|
|
1518
|
+
await this.finish(getContext(), handler, {
|
|
1519
|
+
type: "exception",
|
|
1520
|
+
stage: this.stage,
|
|
1521
|
+
error
|
|
1522
|
+
});
|
|
1523
|
+
throw error;
|
|
1524
|
+
}
|
|
1525
|
+
await this.finish(getContext(), handler, {
|
|
1526
|
+
type: "response",
|
|
1527
|
+
status: response.status,
|
|
1528
|
+
...this.result
|
|
1529
|
+
});
|
|
1530
|
+
return response;
|
|
1531
|
+
}
|
|
1532
|
+
project(span, outcome) {
|
|
1533
|
+
span.setAttribute("activitypub.authentication.status", this.authentication.status);
|
|
1534
|
+
if (this.authentication.status === "rejected") span.setAttribute("activitypub.verification.failure_reason", this.authentication.reason.type);
|
|
1535
|
+
span.setAttribute("activitypub.inbox.disposition", outcome?.type === "exception" || this.hasException ? "exception" : this.result.disposition);
|
|
1536
|
+
}
|
|
1537
|
+
async finish(context, handler, outcome) {
|
|
1538
|
+
if (handler == null) return;
|
|
1539
|
+
const report = {
|
|
1540
|
+
inbox: this.inbox,
|
|
1541
|
+
payload: this.payload,
|
|
1542
|
+
activity: this.activity,
|
|
1543
|
+
attempts: this.verification.attempts,
|
|
1544
|
+
authentication: this.authentication,
|
|
1545
|
+
outcome
|
|
1546
|
+
};
|
|
1547
|
+
try {
|
|
1548
|
+
await handler(context, report);
|
|
1549
|
+
} catch (error) {
|
|
1550
|
+
try {
|
|
1551
|
+
(0, _logtape_logtape.getLogger)([
|
|
1552
|
+
"fedify",
|
|
1553
|
+
"federation",
|
|
1554
|
+
"inbox"
|
|
1555
|
+
]).error("An unexpected error occurred in inbox request finished handler:\n{error}", { error });
|
|
1556
|
+
} catch {}
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
};
|
|
1560
|
+
//#endregion
|
|
1450
1561
|
//#region src/sig/compound-proof.ts
|
|
1451
1562
|
const textEncoder = new TextEncoder();
|
|
1452
1563
|
/**
|
|
@@ -1881,6 +1992,26 @@ function findUnsupportedCompoundProofShape(json) {
|
|
|
1881
1992
|
return findInJsonMaps(json, (map, path) => Object.hasOwn(map, "proof") && !isJsonMap$1(map.proof) ? childPath(path, "proof") : void 0) ?? null;
|
|
1882
1993
|
}
|
|
1883
1994
|
/**
|
|
1995
|
+
* Finds the first embedded map that carries a direct `proof` but not its own
|
|
1996
|
+
* `@context`. The map-local compound-proof profile verifies each proof-bearing
|
|
1997
|
+
* map as a self-contained document, so the inbox rejects such a map with
|
|
1998
|
+
* `missingContext` whatever its proof. An object embedded with its captured
|
|
1999
|
+
* signed representation, e.g., by {@link signObject}, always keeps its own
|
|
2000
|
+
* `@context`; one rebuilt under its parent's context, e.g., an object parsed
|
|
2001
|
+
* from a received document, never does, and its proof no longer covers what
|
|
2002
|
+
* it has become anyway.
|
|
2003
|
+
*
|
|
2004
|
+
* The input must be a finite, already-materialized JSON tree; see
|
|
2005
|
+
* {@link containsCompoundPortableObject}.
|
|
2006
|
+
*
|
|
2007
|
+
* @returns The RFC 6901 JSON Pointer to the map, or `null` if every embedded
|
|
2008
|
+
* proof-bearing map has its own `@context`.
|
|
2009
|
+
* @internal
|
|
2010
|
+
*/
|
|
2011
|
+
function findEmbeddedProofWithoutContext(json) {
|
|
2012
|
+
return findInJsonMaps(json, (map, path) => path !== "" && Object.hasOwn(map, "proof") && !Object.hasOwn(map, "@context") ? path : void 0) ?? null;
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
1884
2015
|
* Discovers direct literal proof-bearing maps in an immutable JSON snapshot.
|
|
1885
2016
|
*
|
|
1886
2017
|
* Discovery is bounded and atomic. Unsupported proof shapes, non-JSON input,
|
|
@@ -1935,7 +2066,23 @@ async function verifyDiscoveredProofDocuments(discovered, options) {
|
|
|
1935
2066
|
verified: false,
|
|
1936
2067
|
reason: { type: "missingContext" }
|
|
1937
2068
|
});
|
|
1938
|
-
const
|
|
2069
|
+
const inherited = options[require_http.verificationObservation];
|
|
2070
|
+
let subjectId = null;
|
|
2071
|
+
if (inherited != null && document.id != null) try {
|
|
2072
|
+
subjectId = (0, _fedify_vocab_runtime.parseIri)(document.id);
|
|
2073
|
+
} catch {}
|
|
2074
|
+
const key = await require_http.observeAttempt({ [require_http.verificationObservation]: inherited == null ? void 0 : {
|
|
2075
|
+
...inherited,
|
|
2076
|
+
attempt: void 0,
|
|
2077
|
+
check: void 0,
|
|
2078
|
+
subject: {
|
|
2079
|
+
id: subjectId,
|
|
2080
|
+
pointer: document.path
|
|
2081
|
+
}
|
|
2082
|
+
} }, "objectIntegrity", (observation) => require_http.verifyMapLocalProof(document.securedDocument, {
|
|
2083
|
+
...options,
|
|
2084
|
+
[require_http.verificationObservation]: inherited == null ? void 0 : observation
|
|
2085
|
+
}), (key) => key != null);
|
|
1939
2086
|
return key == null ? Object.freeze({
|
|
1940
2087
|
...metadata,
|
|
1941
2088
|
verified: false,
|
|
@@ -4579,13 +4726,13 @@ function recordCollectionMetrics(meterProvider, base, result, options = {}) {
|
|
|
4579
4726
|
* @param parameters The parameters for handling the collection.
|
|
4580
4727
|
* @returns A promise that resolves to an HTTP response.
|
|
4581
4728
|
*/
|
|
4582
|
-
async function handleCollection(request, { name: name$
|
|
4583
|
-
const spanName = name$
|
|
4729
|
+
async function handleCollection(request, { name: name$2, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, portable, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
|
|
4730
|
+
const spanName = name$2.trim().replace(/\s+/g, "_");
|
|
4584
4731
|
tracerProvider = tracerProvider ?? _opentelemetry_api.trace.getTracerProvider();
|
|
4585
4732
|
const tracer = tracerProvider.getTracer(require_http.name, require_http.version);
|
|
4586
4733
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
4587
4734
|
const metricBase = {
|
|
4588
|
-
kind: getCollectionMetricKind(name$
|
|
4735
|
+
kind: getCollectionMetricKind(name$2),
|
|
4589
4736
|
page: cursor != null,
|
|
4590
4737
|
dispatcher: "built_in"
|
|
4591
4738
|
};
|
|
@@ -4631,7 +4778,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
4631
4778
|
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
4632
4779
|
return await onNotFound(request);
|
|
4633
4780
|
}
|
|
4634
|
-
const items = filterCollectionItems(page.items, name$
|
|
4781
|
+
const items = filterCollectionItems(page.items, name$2, filterPredicate);
|
|
4635
4782
|
itemCount = items.length;
|
|
4636
4783
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
4637
4784
|
return items;
|
|
@@ -4650,7 +4797,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
4650
4797
|
collection = new _fedify_vocab.OrderedCollection({
|
|
4651
4798
|
id: baseUri,
|
|
4652
4799
|
attribution,
|
|
4653
|
-
totalItems: totalItemCount ?? null,
|
|
4800
|
+
totalItems: totalItemCount ?? (portable == null ? null : itemsOrResponse.length),
|
|
4654
4801
|
items: itemsOrResponse
|
|
4655
4802
|
});
|
|
4656
4803
|
} else {
|
|
@@ -4673,7 +4820,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
4673
4820
|
} else {
|
|
4674
4821
|
const uri = new URL(portable == null ? baseUri : pageBase);
|
|
4675
4822
|
uri.searchParams.set("cursor", cursor);
|
|
4676
|
-
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$
|
|
4823
|
+
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$2}`, {
|
|
4677
4824
|
kind: _opentelemetry_api.SpanKind.SERVER,
|
|
4678
4825
|
attributes: {
|
|
4679
4826
|
"activitypub.collection.id": uri.href,
|
|
@@ -4689,7 +4836,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
4689
4836
|
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
4690
4837
|
return await onNotFound(request);
|
|
4691
4838
|
}
|
|
4692
|
-
const items = filterCollectionItems(page.items, name$
|
|
4839
|
+
const items = filterCollectionItems(page.items, name$2, filterPredicate);
|
|
4693
4840
|
itemCount = items.length;
|
|
4694
4841
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
4695
4842
|
return {
|
|
@@ -5170,6 +5317,16 @@ async function handleMediaUpload(request, { identifier, context: ctx, mediaUploa
|
|
|
5170
5317
|
* @returns A promise that resolves to an HTTP response.
|
|
5171
5318
|
*/
|
|
5172
5319
|
async function handleInbox(request, options) {
|
|
5320
|
+
if (options.observation == null) {
|
|
5321
|
+
const observation = new InboxObservation({
|
|
5322
|
+
kind: options.portableInbox != null ? "portable" : options.recipient == null ? "shared" : "personal",
|
|
5323
|
+
recipient: options.recipient
|
|
5324
|
+
});
|
|
5325
|
+
return await observation.runAndFinish(() => options.context, options.inboxRequestFinishedHandler, () => handleInbox(request, {
|
|
5326
|
+
...options,
|
|
5327
|
+
observation
|
|
5328
|
+
}));
|
|
5329
|
+
}
|
|
5173
5330
|
return await (options.tracerProvider ?? _opentelemetry_api.trace.getTracerProvider()).getTracer(require_http.name, require_http.version).startActiveSpan("activitypub.inbox", {
|
|
5174
5331
|
kind: options.queue == null ? _opentelemetry_api.SpanKind.SERVER : _opentelemetry_api.SpanKind.PRODUCER,
|
|
5175
5332
|
attributes: { "activitypub.shared_inbox": options.recipient == null }
|
|
@@ -5178,12 +5335,14 @@ async function handleInbox(request, options) {
|
|
|
5178
5335
|
try {
|
|
5179
5336
|
return await handleInboxInternal(request, options, span);
|
|
5180
5337
|
} catch (e) {
|
|
5338
|
+
options.observation.hasException = true;
|
|
5181
5339
|
span.setStatus({
|
|
5182
5340
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
5183
5341
|
message: String(e)
|
|
5184
5342
|
});
|
|
5185
5343
|
throw e;
|
|
5186
5344
|
} finally {
|
|
5345
|
+
options.observation.project(span);
|
|
5187
5346
|
span.end();
|
|
5188
5347
|
}
|
|
5189
5348
|
});
|
|
@@ -5198,6 +5357,8 @@ async function handleInbox(request, options) {
|
|
|
5198
5357
|
*/
|
|
5199
5358
|
async function handleInboxInternal(request, parameters, span) {
|
|
5200
5359
|
const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, publicKeyTtl, queue, actorDispatcher, inboxListeners, inboxErrorHandler, unverifiedActivityHandler, onNotFound, signatureTimeWindow, maxHttpSignatures, skipSignatureVerification, inboxChallengePolicy, meterProvider, tracerProvider, portableInbox } = parameters;
|
|
5360
|
+
const observation = parameters.observation;
|
|
5361
|
+
const signatureObservation = { [require_http.verificationObservation]: observation.verification };
|
|
5201
5362
|
const logger = (0, _logtape_logtape.getLogger)([
|
|
5202
5363
|
"fedify",
|
|
5203
5364
|
"federation",
|
|
@@ -5222,6 +5383,10 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5222
5383
|
}
|
|
5223
5384
|
}
|
|
5224
5385
|
if (request.bodyUsed) {
|
|
5386
|
+
observation.result = {
|
|
5387
|
+
disposition: "failed",
|
|
5388
|
+
reason: "bodyUnavailable"
|
|
5389
|
+
};
|
|
5225
5390
|
logger.error("Request body has already been read.", { recipient });
|
|
5226
5391
|
span.setStatus({
|
|
5227
5392
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
@@ -5232,6 +5397,10 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5232
5397
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
5233
5398
|
});
|
|
5234
5399
|
} else if (request.body?.locked) {
|
|
5400
|
+
observation.result = {
|
|
5401
|
+
disposition: "failed",
|
|
5402
|
+
reason: "bodyUnavailable"
|
|
5403
|
+
};
|
|
5235
5404
|
logger.error("Request body is locked.", { recipient });
|
|
5236
5405
|
span.setStatus({
|
|
5237
5406
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
@@ -5242,11 +5411,20 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5242
5411
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
5243
5412
|
});
|
|
5244
5413
|
}
|
|
5414
|
+
observation.stage = "parse";
|
|
5415
|
+
observation.result = {
|
|
5416
|
+
disposition: "rejected",
|
|
5417
|
+
reason: "invalidJson"
|
|
5418
|
+
};
|
|
5245
5419
|
let json;
|
|
5246
5420
|
try {
|
|
5247
5421
|
json = JSON.parse(await require_types.readBoundedText(request.clone(), require_types.MAX_BODY_SIZE, request.url));
|
|
5248
5422
|
} catch (error) {
|
|
5249
5423
|
if (error instanceof require_types.BodyTooLargeError) {
|
|
5424
|
+
observation.result = {
|
|
5425
|
+
disposition: "rejected",
|
|
5426
|
+
reason: "bodyTooLarge"
|
|
5427
|
+
};
|
|
5250
5428
|
request.body?.cancel(error).catch(() => {});
|
|
5251
5429
|
span.setStatus({
|
|
5252
5430
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
@@ -5276,6 +5454,15 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5276
5454
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
5277
5455
|
});
|
|
5278
5456
|
}
|
|
5457
|
+
observation.payload = {
|
|
5458
|
+
status: "parsed",
|
|
5459
|
+
value: structuredClone(json)
|
|
5460
|
+
};
|
|
5461
|
+
observation.result = {
|
|
5462
|
+
disposition: "rejected",
|
|
5463
|
+
reason: "invalidActivity"
|
|
5464
|
+
};
|
|
5465
|
+
observation.stage = "verify";
|
|
5279
5466
|
const keyCache = new KvKeyCache(kv, kvPrefixes.publicKey, {
|
|
5280
5467
|
documentLoader: ctx.documentLoader,
|
|
5281
5468
|
contextLoader: ctx.contextLoader,
|
|
@@ -5305,6 +5492,10 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5305
5492
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
5306
5493
|
message: `Failed to parse activity:\n${error}`
|
|
5307
5494
|
});
|
|
5495
|
+
observation.result = {
|
|
5496
|
+
disposition: "rejected",
|
|
5497
|
+
reason: "invalidActivity"
|
|
5498
|
+
};
|
|
5308
5499
|
return new Response("Invalid activity.", {
|
|
5309
5500
|
status: 400,
|
|
5310
5501
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
@@ -5322,11 +5513,25 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5322
5513
|
recipient,
|
|
5323
5514
|
error
|
|
5324
5515
|
});
|
|
5516
|
+
observation.result = {
|
|
5517
|
+
disposition: "rejected",
|
|
5518
|
+
reason: "invalidJsonLd"
|
|
5519
|
+
};
|
|
5325
5520
|
return new Response("Invalid JSON-LD.", {
|
|
5326
5521
|
status: 400,
|
|
5327
5522
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
5328
5523
|
});
|
|
5329
5524
|
}
|
|
5525
|
+
observation.verification.attempts.push({
|
|
5526
|
+
mechanism: "linkedData",
|
|
5527
|
+
subject: {
|
|
5528
|
+
id: null,
|
|
5529
|
+
pointer: ""
|
|
5530
|
+
},
|
|
5531
|
+
checks: [],
|
|
5532
|
+
status: "error",
|
|
5533
|
+
error
|
|
5534
|
+
});
|
|
5330
5535
|
if (!canAttemptAlternateAuthAfterLdSignatureFailure) throw error;
|
|
5331
5536
|
if (!skipSignatureVerification) deferredLdSignatureError = error;
|
|
5332
5537
|
logger.debug("Failed to normalize JSON-LD for Linked Data Signatures; deferring to another authentication path only if it verifies:\n{error}", {
|
|
@@ -5338,6 +5543,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5338
5543
|
compactedJsonWithoutSig = require_http.detachSignature(compactedJson);
|
|
5339
5544
|
try {
|
|
5340
5545
|
ldSigVerified = await require_http.verifyCompactJsonLd(compactedJson, {
|
|
5546
|
+
...signatureObservation,
|
|
5341
5547
|
contextLoader: ctx.contextLoader,
|
|
5342
5548
|
documentLoader: ctx.documentLoader,
|
|
5343
5549
|
keyCache,
|
|
@@ -5351,6 +5557,10 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5351
5557
|
recipient,
|
|
5352
5558
|
error
|
|
5353
5559
|
});
|
|
5560
|
+
observation.result = {
|
|
5561
|
+
disposition: "rejected",
|
|
5562
|
+
reason: "invalidJsonLd"
|
|
5563
|
+
};
|
|
5354
5564
|
return new Response("Invalid JSON-LD.", {
|
|
5355
5565
|
status: 400,
|
|
5356
5566
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
@@ -5370,6 +5580,10 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5370
5580
|
recipient,
|
|
5371
5581
|
error: parseError
|
|
5372
5582
|
});
|
|
5583
|
+
observation.result = {
|
|
5584
|
+
disposition: "rejected",
|
|
5585
|
+
reason: "invalidJsonLd"
|
|
5586
|
+
};
|
|
5373
5587
|
return new Response("Invalid JSON-LD.", {
|
|
5374
5588
|
status: 400,
|
|
5375
5589
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
@@ -5390,7 +5604,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5390
5604
|
json
|
|
5391
5605
|
});
|
|
5392
5606
|
try {
|
|
5393
|
-
activity = await _fedify_vocab.Activity.fromJsonLd(compactedJsonWithoutSig, {
|
|
5607
|
+
activity = observation.activity = await _fedify_vocab.Activity.fromJsonLd(compactedJsonWithoutSig, {
|
|
5394
5608
|
...ctx,
|
|
5395
5609
|
contextLoader: require_http.getNormalizationContextLoader(ctx.contextLoader)
|
|
5396
5610
|
});
|
|
@@ -5402,6 +5616,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5402
5616
|
activityVerified = true;
|
|
5403
5617
|
if (!skipSignatureVerification && isPortableActivity(activity)) try {
|
|
5404
5618
|
proofVerified = await require_http.verifyObject(_fedify_vocab.Activity, jsonWithoutSig, {
|
|
5619
|
+
...signatureObservation,
|
|
5405
5620
|
contextLoader: require_http.wrapContextLoaderForJsonLd(ctx.contextLoader),
|
|
5406
5621
|
documentLoader: ctx.documentLoader,
|
|
5407
5622
|
keyCache,
|
|
@@ -5422,6 +5637,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5422
5637
|
});
|
|
5423
5638
|
try {
|
|
5424
5639
|
activity = await require_http.verifyObject(_fedify_vocab.Activity, jsonWithoutSig, {
|
|
5640
|
+
...signatureObservation,
|
|
5425
5641
|
contextLoader: require_http.wrapContextLoaderForJsonLd(ctx.contextLoader),
|
|
5426
5642
|
documentLoader: ctx.documentLoader,
|
|
5427
5643
|
keyCache,
|
|
@@ -5457,6 +5673,10 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5457
5673
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
5458
5674
|
message: `Failed to parse activity:\n${error}`
|
|
5459
5675
|
});
|
|
5676
|
+
observation.result = {
|
|
5677
|
+
disposition: "rejected",
|
|
5678
|
+
reason: "invalidActivity"
|
|
5679
|
+
};
|
|
5460
5680
|
return new Response("Invalid activity.", {
|
|
5461
5681
|
status: 400,
|
|
5462
5682
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
@@ -5480,6 +5700,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5480
5700
|
if (activity == null) {
|
|
5481
5701
|
if (!skipSignatureVerification) {
|
|
5482
5702
|
const verification = await require_http.verifyRequestDetailed(request, {
|
|
5703
|
+
...signatureObservation,
|
|
5483
5704
|
contextLoader: ctx.contextLoader,
|
|
5484
5705
|
documentLoader: ctx.documentLoader,
|
|
5485
5706
|
timeWindow: signatureTimeWindow,
|
|
@@ -5490,6 +5711,14 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5490
5711
|
});
|
|
5491
5712
|
if (verification.verified === false) {
|
|
5492
5713
|
if (deferredLdSignatureError != null) throw deferredLdSignatureError;
|
|
5714
|
+
observation.authentication = {
|
|
5715
|
+
status: "rejected",
|
|
5716
|
+
reason: { type: "verificationFailed" }
|
|
5717
|
+
};
|
|
5718
|
+
observation.result = {
|
|
5719
|
+
disposition: "rejected",
|
|
5720
|
+
reason: "authentication"
|
|
5721
|
+
};
|
|
5493
5722
|
const reason = verification.reason;
|
|
5494
5723
|
const remoteHost = "keyId" in reason && reason.keyId != null ? require_http.getRemoteHost(reason.keyId) : void 0;
|
|
5495
5724
|
require_http.getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure(reason.type, remoteHost);
|
|
@@ -5504,7 +5733,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5504
5733
|
});
|
|
5505
5734
|
if (unverifiedActivityHandler == null) return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
|
|
5506
5735
|
try {
|
|
5507
|
-
activity = await _fedify_vocab.Activity.fromJsonLd(jsonWithoutSig, ctx);
|
|
5736
|
+
activity = observation.activity = await _fedify_vocab.Activity.fromJsonLd(jsonWithoutSig, ctx);
|
|
5508
5737
|
} catch (error) {
|
|
5509
5738
|
logger.error("Failed to parse activity:\n{error}", {
|
|
5510
5739
|
recipient,
|
|
@@ -5520,6 +5749,10 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5520
5749
|
recipient
|
|
5521
5750
|
});
|
|
5522
5751
|
}
|
|
5752
|
+
observation.result = {
|
|
5753
|
+
disposition: "rejected",
|
|
5754
|
+
reason: "invalidActivity"
|
|
5755
|
+
};
|
|
5523
5756
|
return new Response("Invalid activity.", {
|
|
5524
5757
|
status: 400,
|
|
5525
5758
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
@@ -5542,6 +5775,11 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5542
5775
|
try {
|
|
5543
5776
|
response = await unverifiedActivityHandler(ctx, activity, reason);
|
|
5544
5777
|
} catch (error) {
|
|
5778
|
+
observation.result = {
|
|
5779
|
+
disposition: "failed",
|
|
5780
|
+
reason: "listenerError",
|
|
5781
|
+
error
|
|
5782
|
+
};
|
|
5545
5783
|
logger.error("An unexpected error occurred in unverified activity handler:\n{error}", {
|
|
5546
5784
|
error,
|
|
5547
5785
|
activity: json,
|
|
@@ -5558,7 +5796,10 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5558
5796
|
}
|
|
5559
5797
|
return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
|
|
5560
5798
|
}
|
|
5561
|
-
if (response instanceof Response)
|
|
5799
|
+
if (response instanceof Response) {
|
|
5800
|
+
observation.result = { disposition: "customResponse" };
|
|
5801
|
+
return response;
|
|
5802
|
+
}
|
|
5562
5803
|
return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
|
|
5563
5804
|
} else {
|
|
5564
5805
|
if (inboxChallengePolicy?.enabled && inboxChallengePolicy.requestNonce) pendingNonceLabel = verification.signatureLabel;
|
|
@@ -5568,7 +5809,7 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5568
5809
|
httpSigKey = verification.key;
|
|
5569
5810
|
}
|
|
5570
5811
|
try {
|
|
5571
|
-
activity = await _fedify_vocab.Activity.fromJsonLd(jsonWithoutSig, {
|
|
5812
|
+
activity = observation.activity = await _fedify_vocab.Activity.fromJsonLd(jsonWithoutSig, {
|
|
5572
5813
|
...ctx,
|
|
5573
5814
|
contextLoader: require_http.wrapContextLoaderForJsonLd(ctx.contextLoader)
|
|
5574
5815
|
});
|
|
@@ -5577,6 +5818,12 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5577
5818
|
return await respondInvalidActivity(error);
|
|
5578
5819
|
}
|
|
5579
5820
|
}
|
|
5821
|
+
observation.activity = activity;
|
|
5822
|
+
observation.stage = "policy";
|
|
5823
|
+
observation.result = {
|
|
5824
|
+
disposition: "rejected",
|
|
5825
|
+
reason: "authentication"
|
|
5826
|
+
};
|
|
5580
5827
|
if (activity.id != null) span.setAttribute("activitypub.activity.id", activity.id.href);
|
|
5581
5828
|
span.setAttribute("activitypub.activity.type", (0, _fedify_vocab.getTypeId)(activity).href);
|
|
5582
5829
|
span.addEvent("activitypub.activity.received", {
|
|
@@ -5588,6 +5835,13 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5588
5835
|
});
|
|
5589
5836
|
if (!skipSignatureVerification && !proofVerified && (isPortableActivity(activity) || isPortableActorKey(httpSigKey))) {
|
|
5590
5837
|
if (deferredLdSignatureError != null) throw deferredLdSignatureError;
|
|
5838
|
+
observation.authentication = {
|
|
5839
|
+
status: "rejected",
|
|
5840
|
+
reason: {
|
|
5841
|
+
type: "proofPolicy",
|
|
5842
|
+
policy: "portableActor"
|
|
5843
|
+
}
|
|
5844
|
+
};
|
|
5591
5845
|
logger.error("The activity {activityId} of the portable actor {actorId} is not authenticated by a valid Object Integrity Proof.", {
|
|
5592
5846
|
activity: json,
|
|
5593
5847
|
recipient,
|
|
@@ -5605,20 +5859,36 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5605
5859
|
});
|
|
5606
5860
|
}
|
|
5607
5861
|
if (!skipSignatureVerification && activity.id != null && require_http.isPortableId(activity.id)) {
|
|
5608
|
-
const rejection = await
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5862
|
+
const rejection = await require_http.observeAttempt(signatureObservation, "objectIntegrity", async (verification) => {
|
|
5863
|
+
const rejection = await verifyPortableActivityId(activity.id, jsonWithoutSig, {
|
|
5864
|
+
[require_http.verificationObservation]: verification,
|
|
5865
|
+
contextLoader: require_http.wrapContextLoaderForJsonLd(ctx.contextLoader),
|
|
5866
|
+
documentLoader: ctx.documentLoader,
|
|
5867
|
+
keyCache,
|
|
5868
|
+
meterProvider,
|
|
5869
|
+
tracerProvider
|
|
5870
|
+
});
|
|
5871
|
+
if (rejection != null) verification.attempt.reason = {
|
|
5872
|
+
type: "proofPolicy",
|
|
5873
|
+
reason: rejection
|
|
5874
|
+
};
|
|
5875
|
+
return rejection;
|
|
5876
|
+
}, (value) => value == null);
|
|
5615
5877
|
if (rejection != null) {
|
|
5616
5878
|
if (deferredLdSignatureError != null) throw deferredLdSignatureError;
|
|
5879
|
+
observation.authentication = {
|
|
5880
|
+
status: "rejected",
|
|
5881
|
+
reason: {
|
|
5882
|
+
type: "proofPolicy",
|
|
5883
|
+
policy: "portableActivity",
|
|
5884
|
+
detail: rejection
|
|
5885
|
+
}
|
|
5886
|
+
};
|
|
5617
5887
|
logger.error("The portable activity {activityId} is not authenticated by an Object Integrity Proof of its own DID: {reason}", {
|
|
5618
5888
|
activity: json,
|
|
5619
5889
|
recipient,
|
|
5620
5890
|
activityId: activity.id.href,
|
|
5621
|
-
reason: rejection
|
|
5891
|
+
reason: rejection.type
|
|
5622
5892
|
});
|
|
5623
5893
|
span.setStatus({
|
|
5624
5894
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
@@ -5632,6 +5902,14 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5632
5902
|
}
|
|
5633
5903
|
if (httpSigKey != null && !await require_portable_collection.doesActorOwnKey(activity, httpSigKey, ctx)) {
|
|
5634
5904
|
if (deferredLdSignatureError != null) throw deferredLdSignatureError;
|
|
5905
|
+
observation.authentication = {
|
|
5906
|
+
status: "rejected",
|
|
5907
|
+
reason: {
|
|
5908
|
+
type: "actorKeyMismatch",
|
|
5909
|
+
key: require_http.snapshotKey(httpSigKey),
|
|
5910
|
+
actorIds: activity.actorIds.map((id) => new URL(id.href))
|
|
5911
|
+
}
|
|
5912
|
+
};
|
|
5635
5913
|
require_http.getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure("actorKeyMismatch", httpSigKey.id == null ? void 0 : require_http.getRemoteHost(httpSigKey.id));
|
|
5636
5914
|
logger.error("The signer ({keyId}) and the actor ({actorId}) do not match.", {
|
|
5637
5915
|
activity: json,
|
|
@@ -5651,13 +5929,35 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5651
5929
|
if (!skipSignatureVerification) {
|
|
5652
5930
|
const compoundJson = Array.isArray(json) ? json : jsonWithoutSig;
|
|
5653
5931
|
if (inspectCompoundPortableObjectApplicability(compoundJson, INBOX_COMPOUND_PROOF_LIMITS) !== "absent") {
|
|
5654
|
-
const compoundProof = await
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5932
|
+
const compoundProof = await require_http.observeAttempt(signatureObservation, "objectIntegrity", async (verification) => {
|
|
5933
|
+
const result = await verifyCompoundPortableObjectProofs(compoundJson, INBOX_COMPOUND_PROOF_LIMITS, {
|
|
5934
|
+
[require_http.verificationObservation]: verification,
|
|
5935
|
+
documentLoader: ctx.documentLoader,
|
|
5936
|
+
keyCache,
|
|
5937
|
+
meterProvider,
|
|
5938
|
+
tracerProvider
|
|
5939
|
+
});
|
|
5940
|
+
if (result.status === "unsupported") verification.attempt.reason = {
|
|
5941
|
+
type: "proofPolicy",
|
|
5942
|
+
reason: result.reason
|
|
5943
|
+
};
|
|
5944
|
+
else if (!result.verified) {
|
|
5945
|
+
const failed = result.portableObjects.find((object) => !object.verified);
|
|
5946
|
+
verification.attempt.reason = {
|
|
5947
|
+
type: "proofPolicy",
|
|
5948
|
+
reason: failed?.verified === false ? failed.reason : { type: "invalidProof" }
|
|
5949
|
+
};
|
|
5950
|
+
}
|
|
5951
|
+
return result;
|
|
5952
|
+
}, (result) => result.status === "ok" && result.verified);
|
|
5660
5953
|
if (compoundProof.status !== "ok" || !compoundProof.verified) {
|
|
5954
|
+
observation.authentication = {
|
|
5955
|
+
status: "rejected",
|
|
5956
|
+
reason: {
|
|
5957
|
+
type: "proofPolicy",
|
|
5958
|
+
policy: "compound"
|
|
5959
|
+
}
|
|
5960
|
+
};
|
|
5661
5961
|
logger.error("Failed to verify compound portable Object Integrity Proofs.", {
|
|
5662
5962
|
recipient,
|
|
5663
5963
|
activity: json,
|
|
@@ -5676,11 +5976,20 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5676
5976
|
}
|
|
5677
5977
|
if (pendingNonceLabel != null) {
|
|
5678
5978
|
if (!await verifySignatureNonce(request, kv, kvPrefixes.acceptSignatureNonce, pendingNonceLabel)) {
|
|
5979
|
+
observation.authentication = {
|
|
5980
|
+
status: "rejected",
|
|
5981
|
+
reason: { type: "invalidNonce" }
|
|
5982
|
+
};
|
|
5679
5983
|
require_http.getFederationMetrics(parameters.meterProvider).recordSignatureVerificationFailure("invalidNonce", httpSigKey?.id == null ? void 0 : require_http.getRemoteHost(httpSigKey.id));
|
|
5680
5984
|
logger.error("Signature nonce verification failed (missing, expired, or replayed).", { recipient });
|
|
5681
5985
|
return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
|
|
5682
5986
|
}
|
|
5683
5987
|
}
|
|
5988
|
+
observation.authentication = skipSignatureVerification ? { status: "skipped" } : {
|
|
5989
|
+
status: "verified",
|
|
5990
|
+
attempts: observation.verification.attempts.filter((attempt) => attempt.status === "verified")
|
|
5991
|
+
};
|
|
5992
|
+
observation.stage = "dispatch";
|
|
5684
5993
|
const routeResult = await routeActivity({
|
|
5685
5994
|
context: ctx,
|
|
5686
5995
|
json,
|
|
@@ -5692,7 +6001,14 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5692
6001
|
inboxListeners,
|
|
5693
6002
|
inboxContextFactory,
|
|
5694
6003
|
listenerInboxContextFactory: ldSigVerified ? inboxContextFactory[rawInboxContextFactorySymbol] : void 0,
|
|
5695
|
-
inboxErrorHandler,
|
|
6004
|
+
inboxErrorHandler: async (context, error) => {
|
|
6005
|
+
observation.result = {
|
|
6006
|
+
disposition: "failed",
|
|
6007
|
+
reason: "listenerError",
|
|
6008
|
+
error
|
|
6009
|
+
};
|
|
6010
|
+
await inboxErrorHandler?.(context, error);
|
|
6011
|
+
},
|
|
5696
6012
|
kv,
|
|
5697
6013
|
kvPrefixes,
|
|
5698
6014
|
queue,
|
|
@@ -5728,30 +6044,44 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
5728
6044
|
error
|
|
5729
6045
|
});
|
|
5730
6046
|
}
|
|
5731
|
-
if (routeResult === "alreadyProcessed")
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
})
|
|
5747
|
-
|
|
6047
|
+
if (routeResult === "alreadyProcessed") {
|
|
6048
|
+
observation.result = { disposition: "duplicate" };
|
|
6049
|
+
return new Response(`Activity <${activity.id}> has already been processed.`, {
|
|
6050
|
+
status: 202,
|
|
6051
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
6052
|
+
});
|
|
6053
|
+
} else if (routeResult === "missingActor") {
|
|
6054
|
+
observation.result = {
|
|
6055
|
+
disposition: "rejected",
|
|
6056
|
+
reason: "missingActor"
|
|
6057
|
+
};
|
|
6058
|
+
return new Response("Missing actor.", {
|
|
6059
|
+
status: 400,
|
|
6060
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
6061
|
+
});
|
|
6062
|
+
} else if (routeResult === "enqueued") {
|
|
6063
|
+
observation.result = { disposition: "enqueued" };
|
|
6064
|
+
return new Response("Activity is enqueued.", {
|
|
6065
|
+
status: 202,
|
|
6066
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
6067
|
+
});
|
|
6068
|
+
} else if (routeResult === "unsupportedActivity") {
|
|
6069
|
+
observation.result = { disposition: "unhandled" };
|
|
6070
|
+
return new Response("", {
|
|
6071
|
+
status: 202,
|
|
6072
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
6073
|
+
});
|
|
6074
|
+
} else if (routeResult === "error") return new Response("Internal server error.", {
|
|
5748
6075
|
status: 500,
|
|
5749
6076
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
5750
6077
|
});
|
|
5751
|
-
else
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
6078
|
+
else {
|
|
6079
|
+
observation.result = { disposition: "processed" };
|
|
6080
|
+
return new Response("", {
|
|
6081
|
+
status: 202,
|
|
6082
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
6083
|
+
});
|
|
6084
|
+
}
|
|
5755
6085
|
}
|
|
5756
6086
|
const PORTABLE_INBOX_FORWARDABLE_RESULTS = /* @__PURE__ */ new Set([
|
|
5757
6087
|
"success",
|
|
@@ -5880,8 +6210,8 @@ var CustomCollectionHandler = class {
|
|
|
5880
6210
|
* @param CollectionPage The CollectionPage constructor.
|
|
5881
6211
|
* @param filterPredicate Optional filter predicate for items.
|
|
5882
6212
|
*/
|
|
5883
|
-
constructor(name$
|
|
5884
|
-
this.name = name$
|
|
6213
|
+
constructor(name$1, values, context, callbacks, tracerProvider = _opentelemetry_api.trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate, portable) {
|
|
6214
|
+
this.name = name$1;
|
|
5885
6215
|
this.values = values;
|
|
5886
6216
|
this.context = context;
|
|
5887
6217
|
this.callbacks = callbacks;
|
|
@@ -6417,19 +6747,19 @@ function isPortableActivity(activity) {
|
|
|
6417
6747
|
*/
|
|
6418
6748
|
async function verifyPortableActivityId(activityId, jsonLd, options) {
|
|
6419
6749
|
const expectedId = require_http.getCanonicalPortableId(activityId);
|
|
6420
|
-
if (expectedId == null) return
|
|
6750
|
+
if (expectedId == null) return { type: "invalidObjectId" };
|
|
6421
6751
|
let verification;
|
|
6422
6752
|
try {
|
|
6423
6753
|
verification = await require_http.verifyPortableObjectProofWithRoot(jsonLd, options);
|
|
6424
6754
|
} catch (error) {
|
|
6425
|
-
if (error instanceof require_http.InvalidPortableObjectIdError) return
|
|
6755
|
+
if (error instanceof require_http.InvalidPortableObjectIdError) return { type: "invalidObjectId" };
|
|
6426
6756
|
if (!isPermanentActivityParseError(error)) throw error;
|
|
6427
|
-
return "
|
|
6757
|
+
return { type: "invalidDocument" };
|
|
6428
6758
|
}
|
|
6429
6759
|
const { result, root } = verification;
|
|
6430
|
-
if (!result.verified) return result.reason
|
|
6760
|
+
if (!result.verified) return result.reason;
|
|
6431
6761
|
const rootId = root?.["@id"];
|
|
6432
|
-
if (typeof rootId !== "string" || require_http.getCanonicalPortableId((0, _fedify_vocab_runtime.parseIri)(rootId)) !== expectedId) return
|
|
6762
|
+
if (typeof rootId !== "string" || require_http.getCanonicalPortableId((0, _fedify_vocab_runtime.parseIri)(rootId)) !== expectedId) return { type: "subjectMismatch" };
|
|
6433
6763
|
return null;
|
|
6434
6764
|
}
|
|
6435
6765
|
//#endregion
|
|
@@ -6978,7 +7308,10 @@ function selectPortableActivityKey(activity, activityId, keys) {
|
|
|
6978
7308
|
/**
|
|
6979
7309
|
* Rejects an outgoing activity whose proofs Fedify's own inbox would reject
|
|
6980
7310
|
* as unsupported: a document with portable objects in which some map carries
|
|
6981
|
-
* a proof set or another value that is not a single proof map
|
|
7311
|
+
* a proof set or another value that is not a single proof map, or in which
|
|
7312
|
+
* an embedded map carries a proof but not its own `@context`, e.g., a signed
|
|
7313
|
+
* object parsed from a received document and rebuilt under the activity's
|
|
7314
|
+
* context.
|
|
6982
7315
|
*
|
|
6983
7316
|
* @param jsonLd The compact JSON-LD document about to be delivered.
|
|
6984
7317
|
* @param activityId The activity ID, for the error message.
|
|
@@ -6988,8 +7321,9 @@ function selectPortableActivityKey(activity, activityId, keys) {
|
|
|
6988
7321
|
function assertSupportedCompoundProofShape(jsonLd, activityId) {
|
|
6989
7322
|
if (!containsCompoundPortableObject(jsonLd)) return;
|
|
6990
7323
|
const path = findUnsupportedCompoundProofShape(jsonLd);
|
|
6991
|
-
if (path
|
|
6992
|
-
|
|
7324
|
+
if (path != null) throw new TypeError(`Cannot send the activity ${activityId}: it embeds portable objects, but its proof at the JSON Pointer ${JSON.stringify(path)} is not a single proof map. The map-local compound-proof profile accepts exactly one direct proof per map, so Fedify inboxes would reject the activity. Sign each object with exactly one key.`);
|
|
7325
|
+
const embedded = findEmbeddedProofWithoutContext(jsonLd);
|
|
7326
|
+
if (embedded != null) throw new TypeError(`Cannot send the activity ${activityId}: it embeds portable objects, but the map at the JSON Pointer ${JSON.stringify(embedded)} carries a proof without its own @context. The map-local compound-proof profile verifies each proof-bearing map on its own, so Fedify inboxes would reject the activity. This happens when a signed object parsed from a received document, e.g., a Follow in an inbox listener, is embedded, as it is rebuilt under the activity's context and its proof no longer covers it. Refer to such an object by its ID instead, e.g., new Accept({ object: follow.id }), or embed an object that you signed with signObject().`);
|
|
6993
7327
|
}
|
|
6994
7328
|
//#endregion
|
|
6995
7329
|
//#region src/federation/retry.ts
|
|
@@ -9409,7 +9743,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
9409
9743
|
return await (0, _logtape_logtape.withContext)({
|
|
9410
9744
|
traceId: spanCtx.traceId,
|
|
9411
9745
|
spanId: spanCtx.spanId
|
|
9412
|
-
}, async () => {
|
|
9746
|
+
}, () => this.#observeInboxFetch(metricState, async () => {
|
|
9413
9747
|
const logger = (0, _logtape_logtape.getLogger)([
|
|
9414
9748
|
"fedify",
|
|
9415
9749
|
"federation",
|
|
@@ -9424,8 +9758,14 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
9424
9758
|
tracer,
|
|
9425
9759
|
metricState
|
|
9426
9760
|
});
|
|
9761
|
+
if (metricState.inboxCompletion != null) metricState.inboxCompletion.observation.stage = "respond";
|
|
9427
9762
|
if (metricState.endpoint !== "hashlink_media" && acceptsJsonLd(request)) response.headers.set("Vary", "Accept");
|
|
9428
9763
|
} catch (error) {
|
|
9764
|
+
metricState.inboxCompletion?.observation.project(span, {
|
|
9765
|
+
type: "exception",
|
|
9766
|
+
stage: metricState.inboxCompletion.observation.stage,
|
|
9767
|
+
error
|
|
9768
|
+
});
|
|
9429
9769
|
this.metrics.recordHttpServerRequest(request.method, metricState.endpoint ?? "error", require_http.getDurationMs(metricStart), { routeTemplate: metricState.routeTemplate });
|
|
9430
9770
|
span.setStatus({
|
|
9431
9771
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
@@ -9464,7 +9804,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
9464
9804
|
else if (response.status >= 400) logger.warn(logTpl, values);
|
|
9465
9805
|
else logger.info(logTpl, values);
|
|
9466
9806
|
return response;
|
|
9467
|
-
});
|
|
9807
|
+
}));
|
|
9468
9808
|
});
|
|
9469
9809
|
});
|
|
9470
9810
|
}
|
|
@@ -9506,8 +9846,17 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
9506
9846
|
metricState.routeTemplate = route.template;
|
|
9507
9847
|
metricState.endpoint = getEndpointCategory(route.name);
|
|
9508
9848
|
span.updateName(`${request.method} ${route.template}`);
|
|
9509
|
-
let context = this.#createContext(request, contextData);
|
|
9510
9849
|
const routeName = route.name.replace(/:.*$/, "");
|
|
9850
|
+
let context;
|
|
9851
|
+
try {
|
|
9852
|
+
context = this.#createContext(request, contextData);
|
|
9853
|
+
} catch (error) {
|
|
9854
|
+
if (request.method !== "POST" || routeName !== "inbox" && routeName !== "sharedInbox") throw error;
|
|
9855
|
+
return await this.#reportInboxPreparationError(request, contextData, {
|
|
9856
|
+
kind: routeName === "inbox" ? "personal" : "shared",
|
|
9857
|
+
recipient: route.values.identifier ?? null
|
|
9858
|
+
}, error, span, metricState);
|
|
9859
|
+
}
|
|
9511
9860
|
switch (routeName) {
|
|
9512
9861
|
case "webfinger": return await handleWebFinger(request, {
|
|
9513
9862
|
context,
|
|
@@ -9566,6 +9915,28 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
9566
9915
|
});
|
|
9567
9916
|
return response;
|
|
9568
9917
|
}
|
|
9918
|
+
if (request.method === "POST" && (routeName === "inbox" || routeName === "sharedInbox")) {
|
|
9919
|
+
const recipient = route.values.identifier ?? null;
|
|
9920
|
+
const observation = new InboxObservation({
|
|
9921
|
+
kind: routeName === "inbox" ? "personal" : "shared",
|
|
9922
|
+
recipient
|
|
9923
|
+
});
|
|
9924
|
+
this.#setInboxCompletion(metricState, observation, () => context);
|
|
9925
|
+
return await observation.run(async () => {
|
|
9926
|
+
if (routeName === "inbox") context = this.#createContext(request, contextData, { documentLoader: await context.getDocumentLoader({ identifier: recipient }) });
|
|
9927
|
+
else if (this.sharedInboxKeyDispatcher != null) {
|
|
9928
|
+
const identity = await this.sharedInboxKeyDispatcher(context);
|
|
9929
|
+
if (identity != null) context = this.#createContext(request, contextData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
9930
|
+
}
|
|
9931
|
+
return await this.#handleInbox(request, {
|
|
9932
|
+
recipient,
|
|
9933
|
+
context,
|
|
9934
|
+
contextData,
|
|
9935
|
+
onNotFound,
|
|
9936
|
+
observation
|
|
9937
|
+
});
|
|
9938
|
+
}, span);
|
|
9939
|
+
}
|
|
9569
9940
|
switch (routeName) {
|
|
9570
9941
|
case "actor":
|
|
9571
9942
|
case "actorAlias": {
|
|
@@ -9641,9 +10012,9 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
9641
10012
|
onUnauthorized,
|
|
9642
10013
|
onNotFound
|
|
9643
10014
|
});
|
|
9644
|
-
|
|
10015
|
+
throw new Error("Unreachable inbox delivery.");
|
|
9645
10016
|
case "sharedInbox":
|
|
9646
|
-
if (
|
|
10017
|
+
if (this.sharedInboxKeyDispatcher != null) {
|
|
9647
10018
|
const identity = await this.sharedInboxKeyDispatcher(context);
|
|
9648
10019
|
if (identity != null) context = this.#createContext(request, contextData, { documentLoader: "identifier" in identity || "username" in identity ? await context.getDocumentLoader(identity) : context.getDocumentLoader(identity) });
|
|
9649
10020
|
}
|
|
@@ -9936,7 +10307,49 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
9936
10307
|
}
|
|
9937
10308
|
return await onNotFound(request);
|
|
9938
10309
|
}
|
|
9939
|
-
|
|
10310
|
+
#setInboxCompletion(metricState, observation, getContext) {
|
|
10311
|
+
const handler = this.inboxRequestFinishedHandler;
|
|
10312
|
+
metricState.inboxCompletion = {
|
|
10313
|
+
observation,
|
|
10314
|
+
finish: (outcome) => observation.finish(getContext(), handler, outcome)
|
|
10315
|
+
};
|
|
10316
|
+
}
|
|
10317
|
+
async #observeInboxFetch(metricState, operation) {
|
|
10318
|
+
let response;
|
|
10319
|
+
try {
|
|
10320
|
+
response = await operation();
|
|
10321
|
+
} catch (error) {
|
|
10322
|
+
const completion = metricState.inboxCompletion;
|
|
10323
|
+
if (completion != null) await completion.finish({
|
|
10324
|
+
type: "exception",
|
|
10325
|
+
stage: completion.observation.stage,
|
|
10326
|
+
error
|
|
10327
|
+
});
|
|
10328
|
+
throw error;
|
|
10329
|
+
}
|
|
10330
|
+
const completion = metricState.inboxCompletion;
|
|
10331
|
+
if (completion != null) await completion.finish({
|
|
10332
|
+
type: "response",
|
|
10333
|
+
status: response.status,
|
|
10334
|
+
...completion.observation.result
|
|
10335
|
+
});
|
|
10336
|
+
return response;
|
|
10337
|
+
}
|
|
10338
|
+
async #reportInboxPreparationError(request, contextData, inbox, error, span, metricState) {
|
|
10339
|
+
const unavailableLoader = () => Promise.reject(error);
|
|
10340
|
+
const context = new RequestContextImpl({
|
|
10341
|
+
url: new URL(request.url),
|
|
10342
|
+
request,
|
|
10343
|
+
federation: this,
|
|
10344
|
+
data: contextData,
|
|
10345
|
+
documentLoader: unavailableLoader,
|
|
10346
|
+
contextLoader: unavailableLoader
|
|
10347
|
+
});
|
|
10348
|
+
const observation = new InboxObservation(inbox);
|
|
10349
|
+
this.#setInboxCompletion(metricState, observation, () => context);
|
|
10350
|
+
return await observation.run(() => Promise.reject(error), span);
|
|
10351
|
+
}
|
|
10352
|
+
async #handleInbox(request, { recipient, context, contextData, onNotFound, portableInbox, observation }) {
|
|
9940
10353
|
if (!this.manuallyStartQueue) this._startQueueInternal(contextData);
|
|
9941
10354
|
const inboxContextFactory = context.toInboxContext.bind(context);
|
|
9942
10355
|
inboxContextFactory[rawInboxContextFactorySymbol] = context.toInboxContext.bind(context);
|
|
@@ -9960,7 +10373,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
9960
10373
|
meterProvider: this.meterProvider,
|
|
9961
10374
|
tracerProvider: this.tracerProvider,
|
|
9962
10375
|
idempotencyStrategy: this.idempotencyStrategy,
|
|
9963
|
-
portableInbox
|
|
10376
|
+
portableInbox,
|
|
10377
|
+
observation
|
|
9964
10378
|
});
|
|
9965
10379
|
}
|
|
9966
10380
|
async #fetchPortableInbox(request, portable, { onNotFound, contextData, span, metricState }) {
|
|
@@ -9989,63 +10403,79 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
9989
10403
|
metricState.endpoint = "inbox";
|
|
9990
10404
|
span.updateName(`${request.method} ${metricState.routeTemplate}`);
|
|
9991
10405
|
const identifier = route.values.identifier;
|
|
9992
|
-
let context
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
|
|
10000
|
-
|
|
10001
|
-
|
|
10002
|
-
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
|
|
10009
|
-
|
|
10010
|
-
|
|
10011
|
-
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
|
|
10016
|
-
|
|
10017
|
-
|
|
10018
|
-
|
|
10019
|
-
|
|
10020
|
-
|
|
10021
|
-
|
|
10022
|
-
|
|
10023
|
-
|
|
10406
|
+
let context;
|
|
10407
|
+
try {
|
|
10408
|
+
context = this.#createContext(request, contextData);
|
|
10409
|
+
} catch (error) {
|
|
10410
|
+
return await this.#reportInboxPreparationError(request, contextData, {
|
|
10411
|
+
kind: "portable",
|
|
10412
|
+
recipient: identifier
|
|
10413
|
+
}, error, span, metricState);
|
|
10414
|
+
}
|
|
10415
|
+
const observation = new InboxObservation({
|
|
10416
|
+
kind: "portable",
|
|
10417
|
+
recipient: identifier
|
|
10418
|
+
});
|
|
10419
|
+
this.#setInboxCompletion(metricState, observation, () => context);
|
|
10420
|
+
return await observation.run(async () => {
|
|
10421
|
+
const actor = this.actorCallbacks?.dispatcher == null ? null : await this.actorCallbacks.dispatcher(context, identifier);
|
|
10422
|
+
const localOrigin = context.canonicalOrigin;
|
|
10423
|
+
const resolution = resolvePortableInboxRecipient(actor == null || actor instanceof _fedify_vocab.Tombstone ? null : actor, {
|
|
10424
|
+
authority: portable.portableRequest.authority,
|
|
10425
|
+
canonicalInboxId: portable.canonicalId,
|
|
10426
|
+
localOrigin
|
|
10427
|
+
});
|
|
10428
|
+
if (resolution.status === "rejected") {
|
|
10429
|
+
logger.debug("Not accepting a delivery to the portable inbox {inbox} on behalf of the actor {identifier}: {reason}.", {
|
|
10430
|
+
inbox: portable.canonicalId,
|
|
10431
|
+
identifier,
|
|
10432
|
+
reason: resolution.reason
|
|
10433
|
+
});
|
|
10434
|
+
return await onNotFound(request);
|
|
10435
|
+
}
|
|
10436
|
+
const { recipient } = resolution;
|
|
10437
|
+
if (this.actorCallbacks?.keyPairsDispatcher != null) context = this.#createContext(request, contextData, { documentLoader: await context.getDocumentLoader({ identifier }) });
|
|
10438
|
+
const excludedOrigins = [localOrigin, new URL(request.url).origin];
|
|
10439
|
+
return await this.#handleInbox(request, {
|
|
10440
|
+
recipient: identifier,
|
|
10441
|
+
observation,
|
|
10442
|
+
context,
|
|
10443
|
+
contextData,
|
|
10444
|
+
onNotFound,
|
|
10445
|
+
portableInbox: {
|
|
10446
|
+
recipient,
|
|
10447
|
+
forward: async (activity, activityId, activityType, signatures) => {
|
|
10448
|
+
if (this.portableInboxForwarding.maxTargets < 1) return;
|
|
10449
|
+
if (this.kv.cas == null) {
|
|
10450
|
+
if (!this.#portableInboxForwardingWarned) {
|
|
10451
|
+
this.#portableInboxForwardingWarned = true;
|
|
10452
|
+
logger.warn("Activities delivered to FEP-ef61 portable inboxes are not forwarded to the other gateways, as the key–value store does not support compare-and-swap (KvStore.cas()), which is needed to forward each activity at most once.");
|
|
10453
|
+
}
|
|
10454
|
+
return;
|
|
10024
10455
|
}
|
|
10025
|
-
|
|
10456
|
+
await forwardPortableInboxActivity({
|
|
10457
|
+
recipient,
|
|
10458
|
+
activity,
|
|
10459
|
+
activityId,
|
|
10460
|
+
activityType,
|
|
10461
|
+
excludedOrigins,
|
|
10462
|
+
baseUrl: context.origin,
|
|
10463
|
+
kv: this.kv,
|
|
10464
|
+
kvPrefix: this.kvPrefixes.portableInboxForwarding,
|
|
10465
|
+
outboxQueue: this.outboxQueue,
|
|
10466
|
+
startQueue: this.manuallyStartQueue ? void 0 : () => this._startQueueInternal(contextData),
|
|
10467
|
+
allowPrivateAddress: this.allowPrivateAddress,
|
|
10468
|
+
getKeys: () => this.#getPortableGatewayKeyPairs(context, identifier, recipient),
|
|
10469
|
+
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock, { specTtl: this.httpMessageSignaturesSpecTtl }),
|
|
10470
|
+
signatures,
|
|
10471
|
+
options: this.portableInboxForwarding,
|
|
10472
|
+
meterProvider: this.meterProvider,
|
|
10473
|
+
tracerProvider: this.tracerProvider
|
|
10474
|
+
});
|
|
10026
10475
|
}
|
|
10027
|
-
await forwardPortableInboxActivity({
|
|
10028
|
-
recipient,
|
|
10029
|
-
activity,
|
|
10030
|
-
activityId,
|
|
10031
|
-
activityType,
|
|
10032
|
-
excludedOrigins,
|
|
10033
|
-
baseUrl: context.origin,
|
|
10034
|
-
kv: this.kv,
|
|
10035
|
-
kvPrefix: this.kvPrefixes.portableInboxForwarding,
|
|
10036
|
-
outboxQueue: this.outboxQueue,
|
|
10037
|
-
startQueue: this.manuallyStartQueue ? void 0 : () => this._startQueueInternal(contextData),
|
|
10038
|
-
allowPrivateAddress: this.allowPrivateAddress,
|
|
10039
|
-
getKeys: () => this.#getPortableGatewayKeyPairs(context, identifier, recipient),
|
|
10040
|
-
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock, { specTtl: this.httpMessageSignaturesSpecTtl }),
|
|
10041
|
-
signatures,
|
|
10042
|
-
options: this.portableInboxForwarding,
|
|
10043
|
-
meterProvider: this.meterProvider,
|
|
10044
|
-
tracerProvider: this.tracerProvider
|
|
10045
|
-
});
|
|
10046
10476
|
}
|
|
10047
|
-
}
|
|
10048
|
-
});
|
|
10477
|
+
});
|
|
10478
|
+
}, span);
|
|
10049
10479
|
}
|
|
10050
10480
|
/**
|
|
10051
10481
|
* Gets this server's gateway key pairs for the portable actor that owns
|