@fedify/fedify 2.3.12-dev.2365 → 2.3.13
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/{assert_rejects-DN60FHPX.mjs → assert_rejects-D1HYAik3.mjs} +2 -20
- package/dist/{assert_throws-BOkhLGYc.mjs → assert_throws-BbSMEFKo.mjs} +19 -1
- package/dist/{builder-BOLaWLNy.mjs → builder-BagNDcQw.mjs} +2 -2
- package/dist/compat/transformers.test.mjs +2 -2
- package/dist/{deno-DSS6EkPl.mjs → deno-XpcjbHwj.mjs} +1 -1
- package/dist/{docloader-Ds5k4A6d.mjs → docloader-QDpF5t9M.mjs} +4 -2
- package/dist/federation/builder.test.mjs +3 -3
- package/dist/federation/circuit-breaker.test.mjs +3 -3
- package/dist/federation/collection.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +262 -9
- package/dist/federation/idempotency.test.mjs +3 -3
- package/dist/federation/inbox.test.mjs +25 -1
- package/dist/federation/keycache.test.mjs +1 -1
- package/dist/federation/kv.test.mjs +1 -1
- package/dist/federation/metrics.test.mjs +3 -3
- package/dist/federation/middleware.test.mjs +177 -15
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.js +1 -1
- package/dist/federation/mq.test.mjs +4 -3
- package/dist/federation/negotiation.test.mjs +4 -4
- package/dist/federation/retry.test.mjs +1 -1
- package/dist/federation/router.test.mjs +3 -4
- package/dist/federation/send.test.mjs +7 -6
- package/dist/federation/temporal.test.mjs +4 -4
- package/dist/federation/webfinger.test.mjs +2 -2
- package/dist/{http-D9h6mQdq.mjs → http-BRrpIDS1.mjs} +3 -3
- package/dist/{http-DdaLQHim.cjs → http-DwPnG87d.cjs} +109 -11
- package/dist/{http-LMsqGo8j.js → http-GHVGCeb5.js} +110 -12
- package/dist/inbox-BzOuCPLY.mjs +180 -0
- package/dist/{key-vnmAGZ3_.mjs → key-PdEu1lDF.mjs} +111 -13
- package/dist/{kv-cache-Dz7_SbVI.js → kv-cache-BmqdF048.js} +3 -1
- package/dist/{kv-cache-CQuscHxa.mjs → kv-cache-Clx3SwMp.mjs} +1 -1
- package/dist/{kv-cache-ClCz-B0L.cjs → kv-cache-poF6Tqnz.cjs} +3 -1
- package/dist/{ld-BRqKkOSf.mjs → ld-D6UlzNnG.mjs} +3 -3
- package/dist/{metrics-Z0UkrR_1.mjs → metrics-62qolVUY.mjs} +1 -1
- package/dist/{middleware-C_kPmXE6.mjs → middleware-C3Q3CoR8.mjs} +1 -1
- package/dist/{middleware-RTcKhytV.mjs → middleware-CfbFdEO-.mjs} +96 -194
- package/dist/{middleware-DanzltB1.cjs → middleware-DkrXqZO_.cjs} +106 -34
- package/dist/{middleware-B-CIN962.js → middleware-xw9fBZoB.js} +106 -34
- package/dist/mod.cjs +4 -4
- package/dist/mod.js +4 -4
- package/dist/nodeinfo/client.test.mjs +2 -2
- package/dist/nodeinfo/handler.test.mjs +2 -2
- package/dist/nodeinfo/types.test.mjs +2 -2
- package/dist/otel/exporter.test.mjs +1 -1
- package/dist/{owner-B0rmuoQB.mjs → owner-DWnLg-vk.mjs} +2 -2
- package/dist/{proof-Bau45ZUZ.js → proof-CUSzBztF.js} +1 -1
- package/dist/{proof-CKczQTG0.cjs → proof-DF6CU-SU.cjs} +1 -1
- package/dist/{proof-B7mAFVed.mjs → proof-mf6h7n4_.mjs} +3 -3
- package/dist/{send-BFukz_kE.mjs → send-LJUzNpVF.mjs} +3 -3
- package/dist/sig/http.test.mjs +6 -6
- package/dist/sig/key.test.mjs +213 -7
- package/dist/sig/ld.test.mjs +5 -5
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +4 -4
- package/dist/sig/proof.test.mjs +5 -4
- package/dist/{std__assert-BvGuO4xO.mjs → std__assert-BjJn2daJ.mjs} +2 -2
- package/dist/{temporal-n6j0MNF9.mjs → temporal-_3yIqdvy.mjs} +1 -1
- package/dist/utils/docloader.test.mjs +114 -39
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +7 -7
- /package/dist/{assert-jSdZMYam.mjs → assert-CEO06XCw.mjs} +0 -0
- /package/dist/{circuit-breaker-test-utils-Dm5MM6l9.mjs → circuit-breaker-test-utils-CAdwjgMi.mjs} +0 -0
- /package/dist/{negotiation-CDW-_gUU.mjs → negotiation-DDstyBvc.mjs} +0 -0
- /package/dist/{retry-_VvV0h9f.mjs → retry-CXg_MBI-.mjs} +0 -0
|
@@ -3,23 +3,23 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as esm_default } from "../esm-vrlUxr60.mjs";
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-C-ZRDbaf.mjs";
|
|
6
|
-
import { n as assertExists } from "../std__assert-
|
|
7
|
-
import { r as assertFalse, t as
|
|
8
|
-
import {
|
|
9
|
-
import { t as
|
|
6
|
+
import { n as assertExists } from "../std__assert-BjJn2daJ.mjs";
|
|
7
|
+
import { r as assertFalse, t as assertThrows } from "../assert_throws-BbSMEFKo.mjs";
|
|
8
|
+
import { t as assertRejects } from "../assert_rejects-D1HYAik3.mjs";
|
|
9
|
+
import { n as assertInstanceOf, t as assert } from "../assert-CEO06XCw.mjs";
|
|
10
10
|
import { t as assertNotEquals } from "../assert_not_equals-DkVK8oqV.mjs";
|
|
11
11
|
import { t as assertStrictEquals } from "../assert_strict_equals-XEgZAlrj.mjs";
|
|
12
|
-
import { g as recordInboxActivity } from "../metrics-
|
|
13
|
-
import { l as verifyRequest, s as signRequest } from "../http-
|
|
12
|
+
import { g as recordInboxActivity } from "../metrics-62qolVUY.mjs";
|
|
13
|
+
import { l as verifyRequest, s as signRequest } from "../http-BRrpIDS1.mjs";
|
|
14
14
|
import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.mjs";
|
|
15
|
-
import { t as getAuthenticatedDocumentLoader } from "../docloader-
|
|
15
|
+
import { t as getAuthenticatedDocumentLoader } from "../docloader-QDpF5t9M.mjs";
|
|
16
16
|
import { t as MemoryKvStore } from "../kv-mI4Ix2EU.mjs";
|
|
17
|
-
import { a as compactJsonLd, h as verifyJsonLd, p as signJsonLd, s as detachSignature } from "../ld-
|
|
18
|
-
import { t as doesActorOwnKey } from "../owner-
|
|
19
|
-
import { i as verifyObject, r as signObject } from "../proof-
|
|
20
|
-
import { g as handleBenchmarkTrigger, i as KvSpecDeterminer, n as FederationImpl, o as createFederation, r as InboxContextImpl, t as ContextImpl } from "../middleware-
|
|
17
|
+
import { a as compactJsonLd, h as verifyJsonLd, p as signJsonLd, s as detachSignature } from "../ld-D6UlzNnG.mjs";
|
|
18
|
+
import { t as doesActorOwnKey } from "../owner-DWnLg-vk.mjs";
|
|
19
|
+
import { i as verifyObject, r as signObject } from "../proof-mf6h7n4_.mjs";
|
|
20
|
+
import { g as handleBenchmarkTrigger, i as KvSpecDeterminer, n as FederationImpl, o as createFederation, r as InboxContextImpl, t as ContextImpl } from "../middleware-CfbFdEO-.mjs";
|
|
21
21
|
import { t as CircuitBreaker } from "../circuit-breaker-D1fxthDI.mjs";
|
|
22
|
-
import { t as markCircuitBreakerLegacySweepDone } from "../circuit-breaker-test-utils-
|
|
22
|
+
import { t as markCircuitBreakerLegacySweepDone } from "../circuit-breaker-test-utils-CAdwjgMi.mjs";
|
|
23
23
|
import { configure, reset } from "@logtape/logtape";
|
|
24
24
|
import { RouterError } from "@fedify/uri-template";
|
|
25
25
|
import * as vocab from "@fedify/vocab";
|
|
@@ -2916,7 +2916,7 @@ test("FederationImpl.processQueuedTask()", async (t) => {
|
|
|
2916
2916
|
activity: {
|
|
2917
2917
|
"@context": "https://www.w3.org/ns/activitystreams",
|
|
2918
2918
|
type: "Create",
|
|
2919
|
-
id: "https://example
|
|
2919
|
+
id: "https://remote.example/activities/queued-processed",
|
|
2920
2920
|
actor: "https://remote.example/users/alice",
|
|
2921
2921
|
object: {
|
|
2922
2922
|
type: "Note",
|
|
@@ -2934,6 +2934,50 @@ test("FederationImpl.processQueuedTask()", async (t) => {
|
|
|
2934
2934
|
assertEquals(inboxLifecycle[0].attributes["activitypub.processing.result"], "processed");
|
|
2935
2935
|
assertEquals(inboxLifecycle[0].attributes["activitypub.activity.type"], "https://www.w3.org/ns/activitystreams#Create");
|
|
2936
2936
|
});
|
|
2937
|
+
await t.step("records activitypub.inbox.activity rejected for a queued activity whose ID has another origin than its actor", async () => {
|
|
2938
|
+
const kv = new MemoryKvStore();
|
|
2939
|
+
const [meterProvider, recorder] = createTestMeterProvider();
|
|
2940
|
+
const federation = new FederationImpl({
|
|
2941
|
+
kv,
|
|
2942
|
+
meterProvider,
|
|
2943
|
+
queue: {
|
|
2944
|
+
enqueue(_message, _options) {
|
|
2945
|
+
return Promise.resolve();
|
|
2946
|
+
},
|
|
2947
|
+
listen(_handler, _options) {
|
|
2948
|
+
return Promise.resolve();
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
});
|
|
2952
|
+
let dispatched = false;
|
|
2953
|
+
federation.setInboxListeners("/users/{identifier}/inbox", "/inbox").on(vocab.Create, () => {
|
|
2954
|
+
dispatched = true;
|
|
2955
|
+
});
|
|
2956
|
+
await federation.processQueuedTask(void 0, {
|
|
2957
|
+
type: "inbox",
|
|
2958
|
+
id: crypto.randomUUID(),
|
|
2959
|
+
baseUrl: "https://example.com",
|
|
2960
|
+
activity: {
|
|
2961
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
2962
|
+
type: "Create",
|
|
2963
|
+
id: "https://victim.example/activities/queued-forged",
|
|
2964
|
+
actor: "https://remote.example/users/alice",
|
|
2965
|
+
object: {
|
|
2966
|
+
type: "Note",
|
|
2967
|
+
content: "Hello world"
|
|
2968
|
+
}
|
|
2969
|
+
},
|
|
2970
|
+
started: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2971
|
+
attempt: 0,
|
|
2972
|
+
identifier: null,
|
|
2973
|
+
traceContext: {}
|
|
2974
|
+
});
|
|
2975
|
+
assertFalse(dispatched);
|
|
2976
|
+
const inboxLifecycle = recorder.getMeasurements("activitypub.inbox.activity");
|
|
2977
|
+
assertEquals(inboxLifecycle.length, 1);
|
|
2978
|
+
assertEquals(inboxLifecycle[0].attributes["activitypub.processing.result"], "rejected");
|
|
2979
|
+
assertEquals(inboxLifecycle[0].attributes["activitypub.activity.type"], "https://www.w3.org/ns/activitystreams#Create");
|
|
2980
|
+
});
|
|
2937
2981
|
await t.step("records activitypub.inbox.activity retried on transient listener failure", async () => {
|
|
2938
2982
|
const kv = new MemoryKvStore();
|
|
2939
2983
|
const [meterProvider, recorder] = createTestMeterProvider();
|
|
@@ -2959,7 +3003,7 @@ test("FederationImpl.processQueuedTask()", async (t) => {
|
|
|
2959
3003
|
activity: {
|
|
2960
3004
|
"@context": "https://www.w3.org/ns/activitystreams",
|
|
2961
3005
|
type: "Create",
|
|
2962
|
-
id: "https://example
|
|
3006
|
+
id: "https://remote.example/activities/queued-retried",
|
|
2963
3007
|
actor: "https://remote.example/users/alice",
|
|
2964
3008
|
object: {
|
|
2965
3009
|
type: "Note",
|
|
@@ -3002,7 +3046,7 @@ test("FederationImpl.processQueuedTask()", async (t) => {
|
|
|
3002
3046
|
activity: {
|
|
3003
3047
|
"@context": "https://www.w3.org/ns/activitystreams",
|
|
3004
3048
|
type: "Create",
|
|
3005
|
-
id: "https://example
|
|
3049
|
+
id: "https://remote.example/activities/queued-abandoned",
|
|
3006
3050
|
actor: "https://remote.example/users/alice",
|
|
3007
3051
|
object: {
|
|
3008
3052
|
type: "Note",
|
|
@@ -6938,6 +6982,124 @@ test("ContextImpl.routeActivity() marks queued signed activities as non-LDS", as
|
|
|
6938
6982
|
assertEquals(inboxMessage.ldSignatureVerified, false);
|
|
6939
6983
|
assertEquals(inboxMessage.normalizedActivity, void 0);
|
|
6940
6984
|
});
|
|
6985
|
+
for (const queued of [false, true]) test(`ContextImpl.routeActivity() rejects a proof-signed cross-origin ID (queued: ${queued})`, async () => {
|
|
6986
|
+
const messages = [];
|
|
6987
|
+
const queue = {
|
|
6988
|
+
enqueue(message) {
|
|
6989
|
+
messages.push(message);
|
|
6990
|
+
return Promise.resolve();
|
|
6991
|
+
},
|
|
6992
|
+
async listen() {}
|
|
6993
|
+
};
|
|
6994
|
+
const federation = createFederation({
|
|
6995
|
+
kv: new MemoryKvStore(),
|
|
6996
|
+
documentLoaderFactory: () => mockDocumentLoader,
|
|
6997
|
+
contextLoaderFactory: () => mockDocumentLoader,
|
|
6998
|
+
queue: queued ? {
|
|
6999
|
+
inbox: queue,
|
|
7000
|
+
outbox: queue
|
|
7001
|
+
} : void 0,
|
|
7002
|
+
manuallyStartQueue: true
|
|
7003
|
+
});
|
|
7004
|
+
let listenerCalls = 0;
|
|
7005
|
+
federation.setInboxListeners("/users/{identifier}/inbox", "/inbox").on(Create, () => {
|
|
7006
|
+
listenerCalls++;
|
|
7007
|
+
});
|
|
7008
|
+
const signed = await signObject(new Create({
|
|
7009
|
+
id: new URL("https://victim.example/activities/1"),
|
|
7010
|
+
actor: ed25519Multikey.controllerId
|
|
7011
|
+
}), ed25519PrivateKey, ed25519Multikey.id, {
|
|
7012
|
+
contextLoader: mockDocumentLoader,
|
|
7013
|
+
documentLoader: mockDocumentLoader
|
|
7014
|
+
});
|
|
7015
|
+
assertFalse(await federation.createContext(new URL("https://local.example/")).routeActivity(null, signed));
|
|
7016
|
+
assertEquals(listenerCalls, 0);
|
|
7017
|
+
assertEquals(messages, []);
|
|
7018
|
+
});
|
|
7019
|
+
test("ContextImpl.routeActivity() rejects a missing actor before routing", async () => {
|
|
7020
|
+
const federation = createFederation({
|
|
7021
|
+
kv: new MemoryKvStore(),
|
|
7022
|
+
documentLoaderFactory: () => mockDocumentLoader,
|
|
7023
|
+
contextLoaderFactory: () => mockDocumentLoader
|
|
7024
|
+
});
|
|
7025
|
+
let listenerCalls = 0;
|
|
7026
|
+
federation.setInboxListeners("/users/{identifier}/inbox", "/inbox").on(Create, () => {
|
|
7027
|
+
listenerCalls++;
|
|
7028
|
+
});
|
|
7029
|
+
assertFalse(await federation.createContext(new URL("https://local.example/")).routeActivity(null, new Create({ id: new URL("https://remote.example/activities/1") })));
|
|
7030
|
+
assertEquals(listenerCalls, 0);
|
|
7031
|
+
});
|
|
7032
|
+
test("FederationImpl.processQueuedTask() rejects untrusted activity origins before KV access", async () => {
|
|
7033
|
+
class TrackingKvStore extends MemoryKvStore {
|
|
7034
|
+
reads = 0;
|
|
7035
|
+
writes = 0;
|
|
7036
|
+
get(key) {
|
|
7037
|
+
this.reads++;
|
|
7038
|
+
return super.get(key);
|
|
7039
|
+
}
|
|
7040
|
+
set(key, value, options) {
|
|
7041
|
+
this.writes++;
|
|
7042
|
+
return super.set(key, value, options);
|
|
7043
|
+
}
|
|
7044
|
+
}
|
|
7045
|
+
for (const activity of [{
|
|
7046
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
7047
|
+
id: "https://victim.example/activities/1",
|
|
7048
|
+
type: "Create",
|
|
7049
|
+
actor: "https://attacker.example/actor"
|
|
7050
|
+
}, {
|
|
7051
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
7052
|
+
id: "https://victim.example/activities/2",
|
|
7053
|
+
type: "Create"
|
|
7054
|
+
}]) {
|
|
7055
|
+
const kv = new TrackingKvStore();
|
|
7056
|
+
const federation = new FederationImpl({ kv });
|
|
7057
|
+
let listenerCalls = 0;
|
|
7058
|
+
federation.setInboxListeners("/users/{identifier}/inbox", "/inbox").on(Create, () => {
|
|
7059
|
+
listenerCalls++;
|
|
7060
|
+
});
|
|
7061
|
+
await federation.processQueuedTask(void 0, {
|
|
7062
|
+
type: "inbox",
|
|
7063
|
+
id: crypto.randomUUID(),
|
|
7064
|
+
baseUrl: "https://local.example",
|
|
7065
|
+
activity,
|
|
7066
|
+
started: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7067
|
+
attempt: 0,
|
|
7068
|
+
identifier: null,
|
|
7069
|
+
traceContext: {}
|
|
7070
|
+
});
|
|
7071
|
+
assertEquals(listenerCalls, 0);
|
|
7072
|
+
assertEquals(kv.reads, 0);
|
|
7073
|
+
assertEquals(kv.writes, 0);
|
|
7074
|
+
}
|
|
7075
|
+
const kv = new TrackingKvStore();
|
|
7076
|
+
const federation = new FederationImpl({
|
|
7077
|
+
kv,
|
|
7078
|
+
skipSignatureVerification: true
|
|
7079
|
+
});
|
|
7080
|
+
let listenerCalls = 0;
|
|
7081
|
+
federation.setInboxListeners("/users/{identifier}/inbox", "/inbox").on(Create, () => {
|
|
7082
|
+
listenerCalls++;
|
|
7083
|
+
});
|
|
7084
|
+
await federation.processQueuedTask(void 0, {
|
|
7085
|
+
type: "inbox",
|
|
7086
|
+
id: crypto.randomUUID(),
|
|
7087
|
+
baseUrl: "https://local.example",
|
|
7088
|
+
activity: {
|
|
7089
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
7090
|
+
id: "https://victim.example/activities/opt-out",
|
|
7091
|
+
type: "Create",
|
|
7092
|
+
actor: "https://attacker.example/actor"
|
|
7093
|
+
},
|
|
7094
|
+
started: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7095
|
+
attempt: 0,
|
|
7096
|
+
identifier: null,
|
|
7097
|
+
traceContext: {}
|
|
7098
|
+
});
|
|
7099
|
+
assertEquals(listenerCalls, 1);
|
|
7100
|
+
assertEquals(kv.reads, 1);
|
|
7101
|
+
assertEquals(kv.writes, 1);
|
|
7102
|
+
});
|
|
6941
7103
|
test("ContextImpl.getCollectionUri()", () => {
|
|
6942
7104
|
const federation = new FederationImpl({ kv: new MemoryKvStore() });
|
|
6943
7105
|
const base = "https://example.com";
|
package/dist/federation/mod.cjs
CHANGED
|
@@ -2,7 +2,7 @@ const { Temporal } = require("@js-temporal/polyfill");
|
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
4
|
require("../chunk-DDcVe30Y.cjs");
|
|
5
|
-
const require_middleware = require("../middleware-
|
|
5
|
+
const require_middleware = require("../middleware-DkrXqZO_.cjs");
|
|
6
6
|
let _logtape_logtape = require("@logtape/logtape");
|
|
7
7
|
let _fedify_uri_template = require("@fedify/uri-template");
|
|
8
8
|
let es_toolkit = require("es-toolkit");
|
package/dist/federation/mod.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { a as SendActivityError, c as buildCollectionSynchronizationHeader, d as normalizeCircuitBreakerOptions, f as parseCircuitBreakerKvState, i as createExponentialBackoffPolicy, l as digest, o as respondWithObject, p as createFederationBuilder, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as CircuitBreaker } from "../middleware-
|
|
3
|
+
import { a as SendActivityError, c as buildCollectionSynchronizationHeader, d as normalizeCircuitBreakerOptions, f as parseCircuitBreakerKvState, i as createExponentialBackoffPolicy, l as digest, o as respondWithObject, p as createFederationBuilder, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as CircuitBreaker } from "../middleware-xw9fBZoB.js";
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
5
|
import { Router as Router$1, RouterError as RouterError$1, assertPath, isPath } from "@fedify/uri-template";
|
|
6
6
|
import { isEqual } from "es-toolkit";
|
|
@@ -2,9 +2,10 @@ import { Temporal } from "@js-temporal/polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as assertEquals } from "../assert_equals-C-ZRDbaf.mjs";
|
|
5
|
-
import "../std__assert-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
5
|
+
import "../std__assert-BjJn2daJ.mjs";
|
|
6
|
+
import { r as assertFalse } from "../assert_throws-BbSMEFKo.mjs";
|
|
7
|
+
import { n as assertGreaterOrEqual } from "../assert_rejects-D1HYAik3.mjs";
|
|
8
|
+
import { t as assert } from "../assert-CEO06XCw.mjs";
|
|
8
9
|
import { test } from "@fedify/fixture";
|
|
9
10
|
import { delay } from "es-toolkit";
|
|
10
11
|
//#region src/federation/mq.ts
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import "../std__assert-
|
|
5
|
-
import { r as assertFalse } from "../
|
|
6
|
-
import { t as assert } from "../assert-
|
|
7
|
-
import { t as acceptsJsonLd } from "../negotiation-
|
|
4
|
+
import "../std__assert-BjJn2daJ.mjs";
|
|
5
|
+
import { r as assertFalse } from "../assert_throws-BbSMEFKo.mjs";
|
|
6
|
+
import { t as assert } from "../assert-CEO06XCw.mjs";
|
|
7
|
+
import { t as acceptsJsonLd } from "../negotiation-DDstyBvc.mjs";
|
|
8
8
|
import { test } from "@fedify/fixture";
|
|
9
9
|
//#region src/federation/negotiation.test.ts
|
|
10
10
|
test("acceptsJsonLd()", () => {
|
|
@@ -3,7 +3,7 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { l as AssertionError, t as assertEquals } from "../assert_equals-C-ZRDbaf.mjs";
|
|
5
5
|
import { t as assertNotEquals } from "../assert_not_equals-DkVK8oqV.mjs";
|
|
6
|
-
import { t as createExponentialBackoffPolicy } from "../retry-
|
|
6
|
+
import { t as createExponentialBackoffPolicy } from "../retry-CXg_MBI-.mjs";
|
|
7
7
|
import { test } from "@fedify/fixture";
|
|
8
8
|
//#region src/federation/retry.test.ts
|
|
9
9
|
test("createExponentialBackoffPolicy()", () => {
|
|
@@ -2,10 +2,9 @@ import "@js-temporal/polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as assertEquals } from "../assert_equals-C-ZRDbaf.mjs";
|
|
5
|
-
import "../std__assert-
|
|
6
|
-
import { r as assertFalse } from "../
|
|
7
|
-
import { t as assert } from "../assert-
|
|
8
|
-
import { t as assertThrows } from "../assert_throws-BOkhLGYc.mjs";
|
|
5
|
+
import "../std__assert-BjJn2daJ.mjs";
|
|
6
|
+
import { r as assertFalse, t as assertThrows } from "../assert_throws-BbSMEFKo.mjs";
|
|
7
|
+
import { t as assert } from "../assert-CEO06XCw.mjs";
|
|
9
8
|
import { getLogger } from "@logtape/logtape";
|
|
10
9
|
import { Router, RouterError, assertPath, isPath } from "@fedify/uri-template";
|
|
11
10
|
import { test } from "@fedify/fixture";
|
|
@@ -3,14 +3,15 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as esm_default } from "../esm-vrlUxr60.mjs";
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-C-ZRDbaf.mjs";
|
|
6
|
-
import "../std__assert-
|
|
7
|
-
import {
|
|
8
|
-
import { n as
|
|
6
|
+
import "../std__assert-BjJn2daJ.mjs";
|
|
7
|
+
import { r as assertFalse } from "../assert_throws-BbSMEFKo.mjs";
|
|
8
|
+
import { n as assertGreaterOrEqual, t as assertRejects } from "../assert_rejects-D1HYAik3.mjs";
|
|
9
|
+
import { n as assertInstanceOf, t as assert } from "../assert-CEO06XCw.mjs";
|
|
9
10
|
import { t as assertNotEquals } from "../assert_not_equals-DkVK8oqV.mjs";
|
|
10
|
-
import { l as verifyRequest } from "../http-
|
|
11
|
+
import { l as verifyRequest } from "../http-BRrpIDS1.mjs";
|
|
11
12
|
import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.mjs";
|
|
12
|
-
import { t as doesActorOwnKey } from "../owner-
|
|
13
|
-
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-
|
|
13
|
+
import { t as doesActorOwnKey } from "../owner-DWnLg-vk.mjs";
|
|
14
|
+
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-LJUzNpVF.mjs";
|
|
14
15
|
import { Activity, Application, Endpoints, Group, Person, Service } from "@fedify/vocab";
|
|
15
16
|
import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
16
17
|
import { FetchError, UrlError } from "@fedify/vocab-runtime";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import "../std__assert-
|
|
5
|
-
import { r as assertFalse } from "../
|
|
6
|
-
import { t as assert } from "../assert-
|
|
7
|
-
import { t as hasMalformedKnownTemporalLiteral } from "../temporal-
|
|
4
|
+
import "../std__assert-BjJn2daJ.mjs";
|
|
5
|
+
import { r as assertFalse } from "../assert_throws-BbSMEFKo.mjs";
|
|
6
|
+
import { t as assert } from "../assert-CEO06XCw.mjs";
|
|
7
|
+
import { t as hasMalformedKnownTemporalLiteral } from "../temporal-_3yIqdvy.mjs";
|
|
8
8
|
import { test } from "@fedify/fixture";
|
|
9
9
|
//#region src/federation/temporal.test.ts
|
|
10
10
|
test("hasMalformedKnownTemporalLiteral() detects expanded proof timestamps", async () => {
|
|
@@ -3,10 +3,10 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { r as createRequestContext } from "../context-CxbCIptr.mjs";
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-C-ZRDbaf.mjs";
|
|
6
|
-
import "../std__assert-
|
|
6
|
+
import "../std__assert-BjJn2daJ.mjs";
|
|
7
7
|
import { t as assertNotEquals } from "../assert_not_equals-DkVK8oqV.mjs";
|
|
8
8
|
import { t as MemoryKvStore } from "../kv-mI4Ix2EU.mjs";
|
|
9
|
-
import { o as createFederation, s as handleWebFinger } from "../middleware-
|
|
9
|
+
import { o as createFederation, s as handleWebFinger } from "../middleware-CfbFdEO-.mjs";
|
|
10
10
|
import { Image, Link, Person, Tombstone } from "@fedify/vocab";
|
|
11
11
|
import { createTestMeterProvider, test } from "@fedify/fixture";
|
|
12
12
|
//#region src/federation/webfinger.test.ts
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-
|
|
4
|
+
import { n as version, t as name } from "./deno-XpcjbHwj.mjs";
|
|
5
|
+
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-62qolVUY.mjs";
|
|
6
6
|
import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-Dd__NiUL.mjs";
|
|
7
|
-
import { i as fetchKeyDetailed, s as validateCryptoKey } from "./key-
|
|
7
|
+
import { i as fetchKeyDetailed, s as validateCryptoKey } from "./key-PdEu1lDF.mjs";
|
|
8
8
|
import { getLogger } from "@logtape/logtape";
|
|
9
9
|
import { CryptographicKey } from "@fedify/vocab";
|
|
10
10
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -11,7 +11,7 @@ let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conve
|
|
|
11
11
|
let byte_encodings_base64 = require("byte-encodings/base64");
|
|
12
12
|
//#region deno.json
|
|
13
13
|
var name = "@fedify/fedify";
|
|
14
|
-
var version = "2.3.
|
|
14
|
+
var version = "2.3.13";
|
|
15
15
|
//#endregion
|
|
16
16
|
//#region src/sig/accept.ts
|
|
17
17
|
/**
|
|
@@ -961,6 +961,65 @@ function getDurationMs(start) {
|
|
|
961
961
|
}
|
|
962
962
|
//#endregion
|
|
963
963
|
//#region src/sig/key.ts
|
|
964
|
+
/** Classifies decoding failures without hiding unexpected loader errors. */
|
|
965
|
+
function classifyKeyJsonLdError(error, seen = /* @__PURE__ */ new Set()) {
|
|
966
|
+
if (!(error instanceof Error) || !error.name.startsWith("jsonld.")) return null;
|
|
967
|
+
if (seen.has(error)) throw error;
|
|
968
|
+
seen.add(error);
|
|
969
|
+
const details = error.details;
|
|
970
|
+
if (typeof details?.code !== "string") return null;
|
|
971
|
+
if (details.code !== "loading remote context failed" || !("cause" in details) && !("cause" in error)) return "invalid";
|
|
972
|
+
const cause = "cause" in details ? details.cause : error.cause;
|
|
973
|
+
const nestedFailure = classifyKeyJsonLdError(cause, seen);
|
|
974
|
+
if (nestedFailure != null) return nestedFailure;
|
|
975
|
+
if (cause instanceof SyntaxError) return "invalid";
|
|
976
|
+
if (cause instanceof _fedify_vocab_runtime.FetchError || cause instanceof _fedify_vocab_runtime.UrlError) return "fetch";
|
|
977
|
+
if (cause instanceof Error && [
|
|
978
|
+
"AbortError",
|
|
979
|
+
"TimeoutError",
|
|
980
|
+
"NetworkError"
|
|
981
|
+
].includes(cause.name)) return "fetch";
|
|
982
|
+
if (cause instanceof TypeError) {
|
|
983
|
+
const urlCode = cause.code;
|
|
984
|
+
if (cause.name === "InvalidContextReferenceError") return "invalid";
|
|
985
|
+
if (urlCode === "ERR_INVALID_URL" || cause.message === "Invalid URL string." || /^Invalid URL(?::|$)/.test(cause.message) || / cannot be parsed as a URL\.?$/.test(cause.message)) return typeof details.url === "string" && /^[A-Za-z][A-Za-z0-9+.-]*:/.test(details.url) && !URL.canParse(details.url) ? "invalid" : "fetch";
|
|
986
|
+
const networkCause = cause.cause;
|
|
987
|
+
const code = cause.code ?? networkCause?.code;
|
|
988
|
+
if (typeof code === "string" && [
|
|
989
|
+
"ECONNREFUSED",
|
|
990
|
+
"ECONNRESET",
|
|
991
|
+
"ECONNABORTED",
|
|
992
|
+
"ETIMEDOUT",
|
|
993
|
+
"EHOSTUNREACH",
|
|
994
|
+
"ENETUNREACH",
|
|
995
|
+
"ENOTFOUND",
|
|
996
|
+
"EAI_AGAIN",
|
|
997
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
998
|
+
"UND_ERR_HEADERS_TIMEOUT",
|
|
999
|
+
"UND_ERR_BODY_TIMEOUT",
|
|
1000
|
+
"UND_ERR_SOCKET"
|
|
1001
|
+
].includes(code) || /^(fetch failed|Failed to fetch|error sending request|error reading a body from connection|Unable to connect|ConnectionRefused|Network connection lost|The socket connection was closed unexpectedly)/.test(cause.message)) return "fetch";
|
|
1002
|
+
}
|
|
1003
|
+
throw cause;
|
|
1004
|
+
}
|
|
1005
|
+
/** Carries a context transport failure through the key decoding boundary. */
|
|
1006
|
+
var KeyContextFetchError = class extends Error {
|
|
1007
|
+
error;
|
|
1008
|
+
constructor(error) {
|
|
1009
|
+
super("Failed to fetch a key's JSON-LD context.", { cause: error });
|
|
1010
|
+
this.error = error;
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
function contextFetchError(error) {
|
|
1014
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1015
|
+
while (error instanceof Error && !seen.has(error)) {
|
|
1016
|
+
seen.add(error);
|
|
1017
|
+
const details = error.details;
|
|
1018
|
+
if (!error.name.startsWith("jsonld.") || details?.code !== "loading remote context failed") break;
|
|
1019
|
+
error = "cause" in details ? details.cause : error.cause;
|
|
1020
|
+
}
|
|
1021
|
+
return new KeyContextFetchError(error);
|
|
1022
|
+
}
|
|
964
1023
|
/**
|
|
965
1024
|
* Checks if the given key is valid and supported. No-op if the key is valid,
|
|
966
1025
|
* otherwise throws an error.
|
|
@@ -1055,6 +1114,9 @@ async function importJwk(jwk, type) {
|
|
|
1055
1114
|
* @internal
|
|
1056
1115
|
*/
|
|
1057
1116
|
async function fetchActorDocument(actorId, options = {}) {
|
|
1117
|
+
return await fetchActorDocumentInternal(actorId, options, false);
|
|
1118
|
+
}
|
|
1119
|
+
async function fetchActorDocumentInternal(actorId, options, propagateContextFetchErrors) {
|
|
1058
1120
|
const logger = (0, _logtape_logtape.getLogger)([
|
|
1059
1121
|
"fedify",
|
|
1060
1122
|
"sig",
|
|
@@ -1085,9 +1147,12 @@ async function fetchActorDocument(actorId, options = {}) {
|
|
|
1085
1147
|
baseUrl: documentUrl
|
|
1086
1148
|
});
|
|
1087
1149
|
} catch (error) {
|
|
1088
|
-
|
|
1089
|
-
|
|
1150
|
+
const failure = classifyKeyJsonLdError(error);
|
|
1151
|
+
if (failure === "fetch" && propagateContextFetchErrors) throw contextFetchError(error);
|
|
1152
|
+
if (failure == null && !(error instanceof TypeError)) throw error;
|
|
1153
|
+
logger.debug("Failed to decode the actor document at {documentUrl}: {error}", {
|
|
1090
1154
|
documentUrl: documentUrl.href,
|
|
1155
|
+
failure: failure ?? "invalid",
|
|
1091
1156
|
error
|
|
1092
1157
|
});
|
|
1093
1158
|
return null;
|
|
@@ -1126,6 +1191,9 @@ async function fetchActorDocument(actorId, options = {}) {
|
|
|
1126
1191
|
* @internal
|
|
1127
1192
|
*/
|
|
1128
1193
|
async function verifyKeyOwnership(key, options = {}) {
|
|
1194
|
+
return await verifyKeyOwnershipInternal(key, options, false);
|
|
1195
|
+
}
|
|
1196
|
+
async function verifyKeyOwnershipInternal(key, options, propagateContextFetchErrors) {
|
|
1129
1197
|
const logger = (0, _logtape_logtape.getLogger)([
|
|
1130
1198
|
"fedify",
|
|
1131
1199
|
"sig",
|
|
@@ -1135,7 +1203,7 @@ async function verifyKeyOwnership(key, options = {}) {
|
|
|
1135
1203
|
if (keyId == null) return null;
|
|
1136
1204
|
const claimedOwnerId = key instanceof _fedify_vocab.CryptographicKey ? key.ownerId : key.controllerId;
|
|
1137
1205
|
if (claimedOwnerId == null) return null;
|
|
1138
|
-
const owner = await
|
|
1206
|
+
const owner = await fetchActorDocumentInternal(claimedOwnerId, options, propagateContextFetchErrors);
|
|
1139
1207
|
if (owner == null) {
|
|
1140
1208
|
logger.debug("The owner ({claimedOwnerId}) that key {keyId} claims could not be resolved.", {
|
|
1141
1209
|
keyId: keyId.href,
|
|
@@ -1287,6 +1355,21 @@ async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, {
|
|
|
1287
1355
|
tracerProvider
|
|
1288
1356
|
});
|
|
1289
1357
|
} catch (e) {
|
|
1358
|
+
const failure = classifyKeyJsonLdError(e);
|
|
1359
|
+
if (failure === "fetch") throw contextFetchError(e);
|
|
1360
|
+
if (failure != null) {
|
|
1361
|
+
logger.debug("Failed to decode key {keyId}: {error}", {
|
|
1362
|
+
keyId,
|
|
1363
|
+
failure,
|
|
1364
|
+
error: e
|
|
1365
|
+
});
|
|
1366
|
+
await keyCache?.set(cacheKey, null);
|
|
1367
|
+
await clearFetchErrorMetadata(cacheKey, keyCache);
|
|
1368
|
+
return {
|
|
1369
|
+
key: null,
|
|
1370
|
+
cached: false
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1290
1373
|
if (!(e instanceof TypeError)) throw e;
|
|
1291
1374
|
try {
|
|
1292
1375
|
object = await cls.fromJsonLd(document, {
|
|
@@ -1295,8 +1378,14 @@ async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, {
|
|
|
1295
1378
|
tracerProvider
|
|
1296
1379
|
});
|
|
1297
1380
|
} catch (e) {
|
|
1298
|
-
|
|
1299
|
-
|
|
1381
|
+
const failure = classifyKeyJsonLdError(e);
|
|
1382
|
+
if (failure === "fetch") throw contextFetchError(e);
|
|
1383
|
+
if (failure != null || e instanceof TypeError) {
|
|
1384
|
+
logger.debug("Failed to decode key {keyId}: {error}", {
|
|
1385
|
+
keyId,
|
|
1386
|
+
failure: failure ?? "invalid",
|
|
1387
|
+
error: e
|
|
1388
|
+
});
|
|
1300
1389
|
await keyCache?.set(cacheKey, null);
|
|
1301
1390
|
await clearFetchErrorMetadata(cacheKey, keyCache);
|
|
1302
1391
|
return {
|
|
@@ -1388,16 +1477,17 @@ async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, {
|
|
|
1388
1477
|
const claimedOwnerId = key instanceof _fedify_vocab.CryptographicKey ? key.ownerId : key.controllerId;
|
|
1389
1478
|
if (ownerDocument != null && claimedOwnerId == null) key = key instanceof _fedify_vocab.CryptographicKey ? key.clone({ owner: ownerDocument.id }) : key.clone({ controller: ownerDocument.id });
|
|
1390
1479
|
else if (claimedOwnerId != null && claimedOwnerId.href !== ownerDocument?.id?.href) {
|
|
1391
|
-
if (await
|
|
1480
|
+
if (await verifyKeyOwnershipInternal(key, {
|
|
1392
1481
|
documentLoader,
|
|
1393
1482
|
contextLoader,
|
|
1394
1483
|
tracerProvider
|
|
1395
|
-
}) == null) {
|
|
1484
|
+
}, true) == null) {
|
|
1396
1485
|
logger.debug("Failed to verify; the owner {claimedOwnerId} that key {keyId} claims does not list the key as its own.", {
|
|
1397
1486
|
keyId,
|
|
1398
1487
|
claimedOwnerId: claimedOwnerId.href
|
|
1399
1488
|
});
|
|
1400
1489
|
await keyCache?.set(cacheKey, null);
|
|
1490
|
+
await clearFetchErrorMetadata(cacheKey, keyCache);
|
|
1401
1491
|
return {
|
|
1402
1492
|
key: null,
|
|
1403
1493
|
cached: false
|
|
@@ -1448,9 +1538,17 @@ async function fetchKeyWithResult(cacheKey, cls, options, onCachedUnavailable, o
|
|
|
1448
1538
|
outcome = classified;
|
|
1449
1539
|
return errored;
|
|
1450
1540
|
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1541
|
+
try {
|
|
1542
|
+
const resolved = await resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, options, logger);
|
|
1543
|
+
outcome = { result: resolved.key != null ? "fetched" : "invalid" };
|
|
1544
|
+
return resolved;
|
|
1545
|
+
} catch (error) {
|
|
1546
|
+
if (!(error instanceof KeyContextFetchError)) throw error;
|
|
1547
|
+
const classified = classifyFetchError(error.error);
|
|
1548
|
+
const errored = await onFetchError(error.error, cacheKey, keyId, keyCache, logger);
|
|
1549
|
+
outcome = classified;
|
|
1550
|
+
return errored;
|
|
1551
|
+
}
|
|
1454
1552
|
} finally {
|
|
1455
1553
|
recordKeyLookup(options.meterProvider, {
|
|
1456
1554
|
durationMs: getDurationMs(start),
|