@fedify/fedify 2.5.0-dev.2378 → 2.5.0-dev.2420
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-J1K0IJj6.mjs → builder-Cwc3Eu59.mjs} +2 -2
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{compound-proof-DtmVrMV7.mjs → compound-proof-Dtwrhs1I.mjs} +2 -2
- package/dist/{context-C2-UDo2c.d.ts → context-2wLkQrjb.d.ts} +11 -0
- package/dist/{context-BjD_CTxh.d.cts → context-DPocjp1l.d.cts} +11 -0
- package/dist/{deno-Ci6tSK9-.mjs → deno-D4J5fszd.mjs} +1 -1
- package/dist/{docloader-DZ9h6KJS.mjs → docloader-ChK1DQkj.mjs} +4 -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 +5 -5
- package/dist/federation/handler.test.mjs +258 -5
- package/dist/federation/hashlink-media.test.mjs +2 -2
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/inbox-report.test.mjs +30 -5
- package/dist/federation/inbox.test.mjs +43 -0
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +172 -10
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +2 -2
- package/dist/federation/mod.d.ts +2 -2
- package/dist/federation/mod.js +1 -1
- package/dist/federation/outgoing-proof.test.mjs +4 -4
- 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 +4 -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 +4 -4
- 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-lzy7M3hT.cjs → federation-DxQI9dSY.cjs} +125 -20
- package/dist/{http-CFyizTHa.mjs → http--kHQomKT.mjs} +4 -4
- package/dist/{http-Cmz7x6Iw.js → http-C8rIQ1pK.js} +1 -1
- package/dist/{http-D1RPHoq3.cjs → http-SBTDzPkh.cjs} +1 -1
- package/dist/inbox-BGD7K-Ra.mjs +188 -0
- package/dist/{kv-cache-rOQX3I3c.mjs → kv-cache-B8LMKVe8.mjs} +1 -1
- package/dist/{kv-cache-C0-HuvwP.js → kv-cache-DSUypZWS.js} +3 -1
- package/dist/{kv-cache-Jym5nP3J.cjs → kv-cache-Dp_dDR1f.cjs} +3 -1
- package/dist/{ld-DJ--ZUpr.mjs → ld-BeBdBDAY.mjs} +2 -2
- package/dist/{metrics-Dwgav7s_.mjs → metrics-Dtb81JxK.mjs} +1 -1
- package/dist/{middleware-CqgRIsWM.js → middleware-DNjv5rBL.js} +125 -20
- package/dist/{middleware-CJWxuUy5.mjs → middleware-DhI-75xh.mjs} +1 -1
- package/dist/{middleware-BbBsa5iR.mjs → middleware-rQqAHzIo.mjs} +107 -179
- package/dist/{mod-BBPd4M_0.d.cts → mod-DKGoPoQC.d.cts} +1 -1
- package/dist/{mod-CUYBGKof.d.ts → mod-Dm-7RdhR.d.ts} +1 -1
- package/dist/mod.cjs +4 -4
- package/dist/mod.d.cts +2 -2
- package/dist/mod.d.ts +2 -2
- package/dist/mod.js +4 -4
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/{owner-Btd7SwMj.mjs → owner-u_-HQrgE.mjs} +3 -3
- package/dist/{portable-collection-BvWxS1sL.cjs → portable-collection-B-x4XwxP.cjs} +1 -1
- package/dist/{portable-collection-gb9V8XEO.mjs → portable-collection-BKkTJQTd.mjs} +2 -2
- package/dist/{portable-collection-DwQT28O2.js → portable-collection-DReoGwZQ.js} +1 -1
- package/dist/{portable-key-Cwti99nP.mjs → portable-key-Bkm6sXJB.mjs} +1 -1
- package/dist/{proof-Bwzv6mXZ.mjs → proof-DOV4ZiAo.mjs} +3 -3
- package/dist/{send-BrQYUSb4.mjs → send-C_Fffu0I.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 +2 -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 +1 -1
- 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.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 +5 -5
- package/dist/sig/proof.test.mjs +3 -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.mjs +3 -3
- package/dist/{temporal-BRaCTxVe.mjs → temporal-BRgOZRRr.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- package/dist/testing/mod.d.mts +11 -0
- package/dist/utils/docloader.test.mjs +112 -37
- 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-SBTDzPkh.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-B-x4XwxP.cjs");
|
|
7
|
+
const require_kv_cache = require("./kv-cache-Dp_dDR1f.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");
|
|
@@ -2807,12 +2807,41 @@ async function isInAudience(object, actor, options = {}) {
|
|
|
2807
2807
|
//#endregion
|
|
2808
2808
|
//#region src/federation/inbox.ts
|
|
2809
2809
|
const Temporal$10 = require_http.Temporal;
|
|
2810
|
+
/**
|
|
2811
|
+
* Checks whether an activity's ID and all of its actor IDs have the same
|
|
2812
|
+
* [FEP-fe34] origin. Activities without an ID have no origin to authenticate.
|
|
2813
|
+
*
|
|
2814
|
+
* Origins are compared by `getAuthenticationOrigin()`, so a portable activity
|
|
2815
|
+
* and its portable actors, including compatible identifiers on any gateway,
|
|
2816
|
+
* are compared by their DIDs. An ID that has no supported origin, such as an
|
|
2817
|
+
* opaque URN, never matches.
|
|
2818
|
+
*
|
|
2819
|
+
* The caller is responsible for rejecting a missing primary actor ID before
|
|
2820
|
+
* relying on this check.
|
|
2821
|
+
*
|
|
2822
|
+
* [FEP-fe34]: https://w3id.org/fep/fe34
|
|
2823
|
+
* @internal
|
|
2824
|
+
*/
|
|
2825
|
+
function actorsHaveSameOrigin(activity) {
|
|
2826
|
+
if (activity.id == null) return true;
|
|
2827
|
+
const origin = require_http.getAuthenticationOrigin(activity.id);
|
|
2828
|
+
return origin != null && activity.actorIds.every((actor) => require_http.getAuthenticationOrigin(actor) === origin);
|
|
2829
|
+
}
|
|
2810
2830
|
async function routeActivity({ context: ctx, json, originalJson, normalizedActivity, ldSignatureVerified, activity, recipient, inboxListeners, inboxContextFactory, listenerInboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, meterProvider, tracerProvider, idempotencyStrategy }) {
|
|
2811
2831
|
const logger = (0, _logtape_logtape.getLogger)([
|
|
2812
2832
|
"fedify",
|
|
2813
2833
|
"federation",
|
|
2814
2834
|
"inbox"
|
|
2815
2835
|
]);
|
|
2836
|
+
if (activity.actorId == null) {
|
|
2837
|
+
logger.error("Missing actor.", { activity: json });
|
|
2838
|
+
span.setStatus({
|
|
2839
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
2840
|
+
message: "Missing actor."
|
|
2841
|
+
});
|
|
2842
|
+
require_http.recordInboxActivity(meterProvider, "rejected", (0, _fedify_vocab.getTypeId)(activity).href);
|
|
2843
|
+
return "missingActor";
|
|
2844
|
+
}
|
|
2816
2845
|
let cacheKey = null;
|
|
2817
2846
|
if (activity.id != null) {
|
|
2818
2847
|
const inboxContext = inboxContextFactory(recipient, json, activity.id?.href, (0, _fedify_vocab.getTypeId)(activity).href);
|
|
@@ -2848,15 +2877,6 @@ async function routeActivity({ context: ctx, json, originalJson, normalizedActiv
|
|
|
2848
2877
|
return "alreadyProcessed";
|
|
2849
2878
|
}
|
|
2850
2879
|
}
|
|
2851
|
-
if (activity.actorId == null) {
|
|
2852
|
-
logger.error("Missing actor.", { activity: json });
|
|
2853
|
-
span.setStatus({
|
|
2854
|
-
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
2855
|
-
message: "Missing actor."
|
|
2856
|
-
});
|
|
2857
|
-
require_http.recordInboxActivity(meterProvider, "rejected", (0, _fedify_vocab.getTypeId)(activity).href);
|
|
2858
|
-
return "missingActor";
|
|
2859
|
-
}
|
|
2860
2880
|
span.setAttribute("activitypub.actor.id", activity.actorId.href);
|
|
2861
2881
|
if (queue != null) {
|
|
2862
2882
|
const carrier = {};
|
|
@@ -4778,13 +4798,13 @@ function recordCollectionMetrics(meterProvider, base, result, options = {}) {
|
|
|
4778
4798
|
* @param parameters The parameters for handling the collection.
|
|
4779
4799
|
* @returns A promise that resolves to an HTTP response.
|
|
4780
4800
|
*/
|
|
4781
|
-
async function handleCollection(request, { name: name$
|
|
4782
|
-
const spanName = name$
|
|
4801
|
+
async function handleCollection(request, { name: name$2, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, portable, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
|
|
4802
|
+
const spanName = name$2.trim().replace(/\s+/g, "_");
|
|
4783
4803
|
tracerProvider = tracerProvider ?? _opentelemetry_api.trace.getTracerProvider();
|
|
4784
4804
|
const tracer = tracerProvider.getTracer(require_http.name, require_http.version);
|
|
4785
4805
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
4786
4806
|
const metricBase = {
|
|
4787
|
-
kind: getCollectionMetricKind(name$
|
|
4807
|
+
kind: getCollectionMetricKind(name$2),
|
|
4788
4808
|
page: cursor != null,
|
|
4789
4809
|
dispatcher: "built_in"
|
|
4790
4810
|
};
|
|
@@ -4830,7 +4850,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
4830
4850
|
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
4831
4851
|
return await onNotFound(request);
|
|
4832
4852
|
}
|
|
4833
|
-
const items = filterCollectionItems(page.items, name$
|
|
4853
|
+
const items = filterCollectionItems(page.items, name$2, filterPredicate);
|
|
4834
4854
|
itemCount = items.length;
|
|
4835
4855
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
4836
4856
|
return items;
|
|
@@ -4872,7 +4892,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
4872
4892
|
} else {
|
|
4873
4893
|
const uri = new URL(portable == null ? baseUri : pageBase);
|
|
4874
4894
|
uri.searchParams.set("cursor", cursor);
|
|
4875
|
-
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$
|
|
4895
|
+
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$2}`, {
|
|
4876
4896
|
kind: _opentelemetry_api.SpanKind.SERVER,
|
|
4877
4897
|
attributes: {
|
|
4878
4898
|
"activitypub.collection.id": uri.href,
|
|
@@ -4888,7 +4908,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
4888
4908
|
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
4889
4909
|
return await onNotFound(request);
|
|
4890
4910
|
}
|
|
4891
|
-
const items = filterCollectionItems(page.items, name$
|
|
4911
|
+
const items = filterCollectionItems(page.items, name$2, filterPredicate);
|
|
4892
4912
|
itemCount = items.length;
|
|
4893
4913
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
4894
4914
|
return {
|
|
@@ -6041,11 +6061,53 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
6041
6061
|
return await getFailedSignatureResponse(inboxChallengePolicy, kv, kvPrefixes);
|
|
6042
6062
|
}
|
|
6043
6063
|
}
|
|
6064
|
+
if (!skipSignatureVerification && activity.id != null && !actorsHaveSameOrigin(activity)) {
|
|
6065
|
+
observation.authentication = {
|
|
6066
|
+
status: "rejected",
|
|
6067
|
+
reason: {
|
|
6068
|
+
type: "activityOriginMismatch",
|
|
6069
|
+
activityId: new URL(activity.id.href),
|
|
6070
|
+
actorIds: activity.actorIds.map((id) => new URL(id.href))
|
|
6071
|
+
}
|
|
6072
|
+
};
|
|
6073
|
+
logger.error("The activity ({activityId}) and its actors do not have the same origin.", {
|
|
6074
|
+
activity: json,
|
|
6075
|
+
recipient,
|
|
6076
|
+
activityId: activity.id.href,
|
|
6077
|
+
actorIds: activity.actorIds.map((actor) => actor.href)
|
|
6078
|
+
});
|
|
6079
|
+
span.setStatus({
|
|
6080
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
6081
|
+
message: `The activity (${activity.id.href}) and its actors do not have the same origin.`
|
|
6082
|
+
});
|
|
6083
|
+
return new Response("The activity and its actors do not have the same origin.", {
|
|
6084
|
+
status: 401,
|
|
6085
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
6086
|
+
});
|
|
6087
|
+
}
|
|
6044
6088
|
observation.authentication = skipSignatureVerification ? { status: "skipped" } : {
|
|
6045
6089
|
status: "verified",
|
|
6046
6090
|
attempts: observation.verification.attempts.filter((attempt) => attempt.status === "verified")
|
|
6047
6091
|
};
|
|
6048
6092
|
observation.stage = "dispatch";
|
|
6093
|
+
if (activity.actorId == null) {
|
|
6094
|
+
observation.result = {
|
|
6095
|
+
disposition: "rejected",
|
|
6096
|
+
reason: "missingActor"
|
|
6097
|
+
};
|
|
6098
|
+
logger.error("Missing actor.", {
|
|
6099
|
+
activity: json,
|
|
6100
|
+
recipient
|
|
6101
|
+
});
|
|
6102
|
+
span.setStatus({
|
|
6103
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
6104
|
+
message: "Missing actor."
|
|
6105
|
+
});
|
|
6106
|
+
return new Response("Missing actor.", {
|
|
6107
|
+
status: 400,
|
|
6108
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
6109
|
+
});
|
|
6110
|
+
}
|
|
6049
6111
|
const routeResult = await routeActivity({
|
|
6050
6112
|
context: ctx,
|
|
6051
6113
|
json,
|
|
@@ -6266,8 +6328,8 @@ var CustomCollectionHandler = class {
|
|
|
6266
6328
|
* @param CollectionPage The CollectionPage constructor.
|
|
6267
6329
|
* @param filterPredicate Optional filter predicate for items.
|
|
6268
6330
|
*/
|
|
6269
|
-
constructor(name$
|
|
6270
|
-
this.name = name$
|
|
6331
|
+
constructor(name$1, values, context, callbacks, tracerProvider = _opentelemetry_api.trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate, portable) {
|
|
6332
|
+
this.name = name$1;
|
|
6271
6333
|
this.values = values;
|
|
6272
6334
|
this.context = context;
|
|
6273
6335
|
this.callbacks = callbacks;
|
|
@@ -9393,6 +9455,35 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
9393
9455
|
span.setAttribute("activitypub.activity.id", activity.id.href);
|
|
9394
9456
|
listenerSpan.setAttribute("activitypub.activity.id", activity.id.href);
|
|
9395
9457
|
}
|
|
9458
|
+
if (activity.actorId == null) {
|
|
9459
|
+
logger.error("Missing actor in queued incoming activity.", {
|
|
9460
|
+
activityId: activity.id?.href,
|
|
9461
|
+
activity: message.activity,
|
|
9462
|
+
recipient: message.identifier
|
|
9463
|
+
});
|
|
9464
|
+
listenerSpan.setStatus({
|
|
9465
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
9466
|
+
message: "Missing actor."
|
|
9467
|
+
});
|
|
9468
|
+
require_http.recordInboxActivity(this.meterProvider, "rejected", activityType);
|
|
9469
|
+
listenerSpan.end();
|
|
9470
|
+
return;
|
|
9471
|
+
}
|
|
9472
|
+
if (!this.skipSignatureVerification && activity.id != null && !actorsHaveSameOrigin(activity)) {
|
|
9473
|
+
logger.error("The queued activity ({activityId}) and its actors do not have the same origin.", {
|
|
9474
|
+
activityId: activity.id.href,
|
|
9475
|
+
actorIds: activity.actorIds.map((actor) => actor.href),
|
|
9476
|
+
activity: message.activity,
|
|
9477
|
+
recipient: message.identifier
|
|
9478
|
+
});
|
|
9479
|
+
listenerSpan.setStatus({
|
|
9480
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
9481
|
+
message: `The activity (${activity.id.href}) and its actors do not have the same origin.`
|
|
9482
|
+
});
|
|
9483
|
+
require_http.recordInboxActivity(this.meterProvider, "rejected", activityType);
|
|
9484
|
+
listenerSpan.end();
|
|
9485
|
+
return;
|
|
9486
|
+
}
|
|
9396
9487
|
cacheKey = activity.id == null ? null : [
|
|
9397
9488
|
...this.kvPrefixes.activityIdempotence,
|
|
9398
9489
|
context.origin,
|
|
@@ -11469,6 +11560,20 @@ var ContextImpl = class ContextImpl {
|
|
|
11469
11560
|
recipient,
|
|
11470
11561
|
activity: json
|
|
11471
11562
|
});
|
|
11563
|
+
if (activity.actorId == null) {
|
|
11564
|
+
logger.debug("Activity is missing an actor; unable to verify.", {
|
|
11565
|
+
recipient,
|
|
11566
|
+
activity: json
|
|
11567
|
+
});
|
|
11568
|
+
return false;
|
|
11569
|
+
}
|
|
11570
|
+
if (activity.id != null && !actorsHaveSameOrigin(activity)) {
|
|
11571
|
+
logger.debug("Activity has actors from different origins; unable to verify.", {
|
|
11572
|
+
recipient,
|
|
11573
|
+
activity: json
|
|
11574
|
+
});
|
|
11575
|
+
return false;
|
|
11576
|
+
}
|
|
11472
11577
|
const routeResult = await routeActivity({
|
|
11473
11578
|
context: this,
|
|
11474
11579
|
json,
|
|
@@ -3,12 +3,12 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { m as parseKeyIdString } from "./portable-key-id-Ca30-hOa.mjs";
|
|
5
5
|
import { a as verificationObservation, i as triedKey, n as observeCheck, t as observeAttempt } from "./verification-Dpfcw8ml.mjs";
|
|
6
|
-
import { n as version, t as name } from "./deno-
|
|
7
|
-
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-
|
|
6
|
+
import { n as version, t as name } from "./deno-D4J5fszd.mjs";
|
|
7
|
+
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-Dtb81JxK.mjs";
|
|
8
8
|
import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-CPVqki78.mjs";
|
|
9
9
|
import { a as promoteKeyOwnerEvidence } from "./key-owner-evidence-APB6NpSk.mjs";
|
|
10
|
-
import { S as fetchKeyDetailed, T as validateCryptoKey, v as bypassKeyCacheReads } from "./ld-
|
|
11
|
-
import { n as resolvePortableActorKey, r as verifyPortableGatewayKeyDocument } from "./portable-key-
|
|
10
|
+
import { S as fetchKeyDetailed, T as validateCryptoKey, v as bypassKeyCacheReads } from "./ld-BeBdBDAY.mjs";
|
|
11
|
+
import { n as resolvePortableActorKey, r as verifyPortableGatewayKeyDocument } from "./portable-key-Bkm6sXJB.mjs";
|
|
12
12
|
import { getLogger } from "@logtape/logtape";
|
|
13
13
|
import { CryptographicKey } from "@fedify/vocab";
|
|
14
14
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -15,7 +15,7 @@ import serialize from "json-canon";
|
|
|
15
15
|
import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
|
|
16
16
|
//#region deno.json
|
|
17
17
|
var name = "@fedify/fedify";
|
|
18
|
-
var version = "2.5.0-dev.
|
|
18
|
+
var version = "2.5.0-dev.2420+4db1db92";
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region src/sig/portable-key-id.ts
|
|
21
21
|
const COMPATIBLE_KEY_ID_PATH_PATTERN = /^\/\.well-known\/apgateway\/did(?::|%3A)/i;
|
|
@@ -17,7 +17,7 @@ json_canon = require_rolldown_runtime.__toESM(json_canon, 1);
|
|
|
17
17
|
let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
18
18
|
//#region deno.json
|
|
19
19
|
var name = "@fedify/fedify";
|
|
20
|
-
var version = "2.5.0-dev.
|
|
20
|
+
var version = "2.5.0-dev.2420+4db1db92";
|
|
21
21
|
//#endregion
|
|
22
22
|
//#region src/sig/portable-key-id.ts
|
|
23
23
|
const COMPATIBLE_KEY_ID_PATH_PATTERN = /^\/\.well-known\/apgateway\/did(?::|%3A)/i;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { Temporal } from "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { t as getAuthenticationOrigin } from "./portable-key-id-Ca30-hOa.mjs";
|
|
5
|
+
import { n as version, t as name } from "./deno-D4J5fszd.mjs";
|
|
6
|
+
import { g as recordInboxActivity, n as getDurationMs, r as getFederationMetrics } from "./metrics-Dtb81JxK.mjs";
|
|
7
|
+
import { getLogger } from "@logtape/logtape";
|
|
8
|
+
import { getTypeId } from "@fedify/vocab";
|
|
9
|
+
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
10
|
+
//#region src/federation/inbox.ts
|
|
11
|
+
/**
|
|
12
|
+
* Checks whether an activity's ID and all of its actor IDs have the same
|
|
13
|
+
* [FEP-fe34] origin. Activities without an ID have no origin to authenticate.
|
|
14
|
+
*
|
|
15
|
+
* Origins are compared by `getAuthenticationOrigin()`, so a portable activity
|
|
16
|
+
* and its portable actors, including compatible identifiers on any gateway,
|
|
17
|
+
* are compared by their DIDs. An ID that has no supported origin, such as an
|
|
18
|
+
* opaque URN, never matches.
|
|
19
|
+
*
|
|
20
|
+
* The caller is responsible for rejecting a missing primary actor ID before
|
|
21
|
+
* relying on this check.
|
|
22
|
+
*
|
|
23
|
+
* [FEP-fe34]: https://w3id.org/fep/fe34
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
function actorsHaveSameOrigin(activity) {
|
|
27
|
+
if (activity.id == null) return true;
|
|
28
|
+
const origin = getAuthenticationOrigin(activity.id);
|
|
29
|
+
return origin != null && activity.actorIds.every((actor) => getAuthenticationOrigin(actor) === origin);
|
|
30
|
+
}
|
|
31
|
+
async function routeActivity({ context: ctx, json, originalJson, normalizedActivity, ldSignatureVerified, activity, recipient, inboxListeners, inboxContextFactory, listenerInboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, meterProvider, tracerProvider, idempotencyStrategy }) {
|
|
32
|
+
const logger = getLogger([
|
|
33
|
+
"fedify",
|
|
34
|
+
"federation",
|
|
35
|
+
"inbox"
|
|
36
|
+
]);
|
|
37
|
+
if (activity.actorId == null) {
|
|
38
|
+
logger.error("Missing actor.", { activity: json });
|
|
39
|
+
span.setStatus({
|
|
40
|
+
code: SpanStatusCode.ERROR,
|
|
41
|
+
message: "Missing actor."
|
|
42
|
+
});
|
|
43
|
+
recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
|
|
44
|
+
return "missingActor";
|
|
45
|
+
}
|
|
46
|
+
let cacheKey = null;
|
|
47
|
+
if (activity.id != null) {
|
|
48
|
+
const inboxContext = inboxContextFactory(recipient, json, activity.id?.href, getTypeId(activity).href);
|
|
49
|
+
const strategy = idempotencyStrategy ?? "per-inbox";
|
|
50
|
+
let keyString;
|
|
51
|
+
if (typeof strategy === "function") keyString = await strategy(inboxContext, activity);
|
|
52
|
+
else switch (strategy) {
|
|
53
|
+
case "global":
|
|
54
|
+
keyString = activity.id.href;
|
|
55
|
+
break;
|
|
56
|
+
case "per-origin":
|
|
57
|
+
keyString = `${ctx.origin}\n${activity.id.href}`;
|
|
58
|
+
break;
|
|
59
|
+
case "per-inbox":
|
|
60
|
+
keyString = `${ctx.origin}\n${activity.id.href}\n${recipient == null ? "sharedInbox" : `inbox\n${recipient}`}`;
|
|
61
|
+
break;
|
|
62
|
+
default: keyString = `${ctx.origin}\n${activity.id.href}`;
|
|
63
|
+
}
|
|
64
|
+
if (keyString != null) cacheKey = [...kvPrefixes.activityIdempotence, keyString];
|
|
65
|
+
}
|
|
66
|
+
if (cacheKey != null) {
|
|
67
|
+
if (await kv.get(cacheKey) === true) {
|
|
68
|
+
logger.debug("Activity {activityId} has already been processed.", {
|
|
69
|
+
activityId: activity.id?.href,
|
|
70
|
+
activity: json,
|
|
71
|
+
recipient
|
|
72
|
+
});
|
|
73
|
+
span.setStatus({
|
|
74
|
+
code: SpanStatusCode.UNSET,
|
|
75
|
+
message: `Activity ${activity.id?.href} has already been processed.`
|
|
76
|
+
});
|
|
77
|
+
recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
|
|
78
|
+
return "alreadyProcessed";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
span.setAttribute("activitypub.actor.id", activity.actorId.href);
|
|
82
|
+
if (queue != null) {
|
|
83
|
+
const carrier = {};
|
|
84
|
+
propagation.inject(context.active(), carrier);
|
|
85
|
+
try {
|
|
86
|
+
await queue.enqueue({
|
|
87
|
+
type: "inbox",
|
|
88
|
+
id: crypto.randomUUID(),
|
|
89
|
+
baseUrl: ctx.origin,
|
|
90
|
+
activity: originalJson ?? json,
|
|
91
|
+
...normalizedActivity == null ? {} : { normalizedActivity },
|
|
92
|
+
...ldSignatureVerified == null ? {} : { ldSignatureVerified },
|
|
93
|
+
identifier: recipient,
|
|
94
|
+
attempt: 0,
|
|
95
|
+
started: (/* @__PURE__ */ new Date()).toISOString(),
|
|
96
|
+
traceContext: carrier
|
|
97
|
+
});
|
|
98
|
+
} catch (error) {
|
|
99
|
+
logger.error("Failed to enqueue the incoming activity {activityId}:\n{error}", {
|
|
100
|
+
error,
|
|
101
|
+
activityId: activity.id?.href,
|
|
102
|
+
activity: json,
|
|
103
|
+
recipient
|
|
104
|
+
});
|
|
105
|
+
span.setStatus({
|
|
106
|
+
code: SpanStatusCode.ERROR,
|
|
107
|
+
message: `Failed to enqueue the incoming activity ${activity.id?.href}.`
|
|
108
|
+
});
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
getFederationMetrics(meterProvider).recordQueueTaskEnqueued({
|
|
112
|
+
role: "inbox",
|
|
113
|
+
queue,
|
|
114
|
+
activityType: getTypeId(activity).href
|
|
115
|
+
}, 0);
|
|
116
|
+
recordInboxActivity(meterProvider, "queued", getTypeId(activity).href);
|
|
117
|
+
logger.info("Activity {activityId} is enqueued.", {
|
|
118
|
+
activityId: activity.id?.href,
|
|
119
|
+
activity: json,
|
|
120
|
+
recipient
|
|
121
|
+
});
|
|
122
|
+
return "enqueued";
|
|
123
|
+
}
|
|
124
|
+
tracerProvider = tracerProvider ?? trace.getTracerProvider();
|
|
125
|
+
return await tracerProvider.getTracer(name, version).startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span) => {
|
|
126
|
+
const dispatched = inboxListeners?.dispatchWithClass(activity);
|
|
127
|
+
if (dispatched == null) {
|
|
128
|
+
logger.error("Unsupported activity type:\n{activity}", {
|
|
129
|
+
activity: json,
|
|
130
|
+
recipient
|
|
131
|
+
});
|
|
132
|
+
span.setStatus({
|
|
133
|
+
code: SpanStatusCode.UNSET,
|
|
134
|
+
message: `Unsupported activity type: ${getTypeId(activity).href}`
|
|
135
|
+
});
|
|
136
|
+
recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
|
|
137
|
+
span.end();
|
|
138
|
+
return "unsupportedActivity";
|
|
139
|
+
}
|
|
140
|
+
const { class: cls, listener } = dispatched;
|
|
141
|
+
span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
|
|
142
|
+
try {
|
|
143
|
+
const activityType = getTypeId(activity).href;
|
|
144
|
+
const started = performance.now();
|
|
145
|
+
try {
|
|
146
|
+
const contextFactory = listenerInboxContextFactory ?? inboxContextFactory;
|
|
147
|
+
await listener(contextFactory(recipient, contextFactory === inboxContextFactory ? json : originalJson ?? json, activity.id?.href, activityType), activity);
|
|
148
|
+
} finally {
|
|
149
|
+
getFederationMetrics(meterProvider).recordInboxProcessingDuration(activityType, getDurationMs(started));
|
|
150
|
+
}
|
|
151
|
+
} catch (error) {
|
|
152
|
+
try {
|
|
153
|
+
await inboxErrorHandler?.(ctx, error);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
156
|
+
error,
|
|
157
|
+
activityId: activity.id?.href,
|
|
158
|
+
activity: json,
|
|
159
|
+
recipient
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
logger.error("Failed to process the incoming activity {activityId}:\n{error}", {
|
|
163
|
+
error,
|
|
164
|
+
activityId: activity.id?.href,
|
|
165
|
+
activity: json,
|
|
166
|
+
recipient
|
|
167
|
+
});
|
|
168
|
+
span.setStatus({
|
|
169
|
+
code: SpanStatusCode.ERROR,
|
|
170
|
+
message: String(error)
|
|
171
|
+
});
|
|
172
|
+
recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
|
|
173
|
+
span.end();
|
|
174
|
+
return "error";
|
|
175
|
+
}
|
|
176
|
+
recordInboxActivity(meterProvider, "processed", getTypeId(activity).href);
|
|
177
|
+
if (cacheKey != null) await kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
|
|
178
|
+
logger.info("Activity {activityId} has been processed.", {
|
|
179
|
+
activityId: activity.id?.href,
|
|
180
|
+
activity: json,
|
|
181
|
+
recipient
|
|
182
|
+
});
|
|
183
|
+
span.end();
|
|
184
|
+
return "success";
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
//#endregion
|
|
188
|
+
export { routeActivity as n, actorsHaveSameOrigin as t };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { p as recordDocumentCache } from "./metrics-
|
|
4
|
+
import { p as recordDocumentCache } from "./metrics-Dtb81JxK.mjs";
|
|
5
5
|
import { getLogger } from "@logtape/logtape";
|
|
6
6
|
import { preloadedContexts } from "@fedify/vocab-runtime";
|
|
7
7
|
//#region src/utils/kv-cache.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { ct as recordDocumentCache, q as validateCryptoKey, t as doubleKnock } from "./http-
|
|
3
|
+
import { ct as recordDocumentCache, q as validateCryptoKey, t as doubleKnock } from "./http-C8rIQ1pK.js";
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
5
|
import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, resolveDocumentLoaderTimeout, validatePublicUrl, withDocumentLoaderTimeout } from "@fedify/vocab-runtime";
|
|
6
6
|
import { curry } from "es-toolkit";
|
|
@@ -62,6 +62,8 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedi
|
|
|
62
62
|
}, options);
|
|
63
63
|
}
|
|
64
64
|
async function validateUrl(url, options) {
|
|
65
|
+
const protocol = new URL(url).protocol;
|
|
66
|
+
if (protocol !== "http:" && protocol !== "https:") throw new UrlError(`Unsupported protocol: ${protocol}`);
|
|
65
67
|
if (!allowPrivateAddress) {
|
|
66
68
|
try {
|
|
67
69
|
await validatePublicUrl(url);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
|
-
const require_http = require("./http-
|
|
2
|
+
const require_http = require("./http-SBTDzPkh.cjs");
|
|
3
3
|
let _logtape_logtape = require("@logtape/logtape");
|
|
4
4
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
5
5
|
let es_toolkit = require("es-toolkit");
|
|
@@ -61,6 +61,8 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedi
|
|
|
61
61
|
}, options);
|
|
62
62
|
}
|
|
63
63
|
async function validateUrl(url, options) {
|
|
64
|
+
const protocol = new URL(url).protocol;
|
|
65
|
+
if (protocol !== "http:" && protocol !== "https:") throw new _fedify_vocab_runtime.UrlError(`Unsupported protocol: ${protocol}`);
|
|
64
66
|
if (!allowPrivateAddress) {
|
|
65
67
|
try {
|
|
66
68
|
await (0, _fedify_vocab_runtime.validatePublicUrl)(url);
|
|
@@ -3,8 +3,8 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { c as isPortableActorDocument, d as isPortableUri, l as isPortableId, m as parseKeyIdString, s as isCompatibleKeyId } from "./portable-key-id-Ca30-hOa.mjs";
|
|
5
5
|
import { a as verificationObservation, i as triedKey, n as observeCheck, t as observeAttempt } from "./verification-Dpfcw8ml.mjs";
|
|
6
|
-
import { n as version, t as name } from "./deno-
|
|
7
|
-
import { _ as recordKeyLookup, n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch, t as classifyFetchError } from "./metrics-
|
|
6
|
+
import { n as version, t as name } from "./deno-D4J5fszd.mjs";
|
|
7
|
+
import { _ as recordKeyLookup, n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch, t as classifyFetchError } from "./metrics-Dtb81JxK.mjs";
|
|
8
8
|
import { n as attachKeyOwnerEvidence, t as MAX_PORTABLE_KEY_TTL } from "./key-owner-evidence-APB6NpSk.mjs";
|
|
9
9
|
import { getLogger } from "@logtape/logtape";
|
|
10
10
|
import { Activity, CryptographicKey, Multikey, Object as Object$1, getTypeId, isActor } from "@fedify/vocab";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
4
|
+
import { n as version, t as name } from "./deno-D4J5fszd.mjs";
|
|
5
5
|
import { metrics } from "@opentelemetry/api";
|
|
6
6
|
import { FetchError } from "@fedify/vocab-runtime";
|
|
7
7
|
//#region src/federation/metrics.ts
|