@fedify/fedify 2.4.0-dev.2155 → 2.4.0-dev.2157
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-CxHALSwA.mjs → builder-CLaS4-yA.mjs} +2 -2
- package/dist/{client-DpnpgjyX.mjs → client-CEnNz8O7.mjs} +7 -3
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{compound-proof-nhrXTRQO.mjs → compound-proof-D7K94KPz.mjs} +2 -2
- package/dist/{context-OrnjnuMq.mjs → context-B2rlkkyJ.mjs} +1 -1
- package/dist/{deno-YLLbRq06.mjs → deno-D1gcWWqB.mjs} +1 -1
- package/dist/{dist-BQvArojP.mjs → dist-DJQM4u7i.mjs} +2 -1
- package/dist/docloader-BMqr3hji.mjs +79 -0
- 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 +4 -4
- package/dist/federation/handler.test.mjs +6 -6
- package/dist/federation/hashlink-media.test.mjs +2 -2
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +187 -10
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.js +1 -1
- package/dist/federation/mq.test.mjs +98 -69
- package/dist/federation/outgoing-proof.test.mjs +5 -5
- 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-gateway-keys.test.mjs +4 -4
- package/dist/federation/portable-inbox.test.mjs +4 -4
- package/dist/federation/portable.test.mjs +3 -3
- package/dist/federation/send.test.mjs +84 -3
- package/dist/federation/tasks/enqueue.test.mjs +3 -3
- package/dist/federation/tasks/tasks.test.mjs +4 -4
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +2 -2
- package/dist/{federation-D9TufmIO.cjs → federation-2e8XrN7q.cjs} +19 -5
- package/dist/{http-eqYXHRkz.cjs → http-BObQoB0j.cjs} +7 -3
- package/dist/{http-CXnNbRe_.mjs → http-CGcLv8rh.mjs} +9 -5
- package/dist/{http-Dk4O3WM0.js → http-Dgtt45-K.js} +7 -3
- package/dist/{key-BZ-Z4uez.mjs → key-CPM4r6tP.mjs} +2 -2
- package/dist/{kv-cache-3uKc0G76.js → kv-cache-BweyIZTb.js} +35 -9
- package/dist/{kv-cache-DzClEalR.cjs → kv-cache-D2fnB8qu.cjs} +34 -8
- package/dist/{kv-cache-DZr8HTel.mjs → kv-cache-bdPqTR1k.mjs} +1 -1
- package/dist/{ld-Djxsq6JR.mjs → ld-lU_ZqzsQ.mjs} +4 -4
- package/dist/{metrics-CBHhbHgG.mjs → metrics-B41pRPfd.mjs} +1 -1
- package/dist/{middleware-BDUR99k3.js → middleware-BYWyYjmX.js} +19 -5
- package/dist/{middleware-BahNnLfD.mjs → middleware-TrCVULgs.mjs} +1 -1
- package/dist/{middleware-DDa8pCUa.mjs → middleware-xdukzV3x.mjs} +15 -15
- package/dist/{mod-CZetqT5h.d.ts → mod-DaiBrWDW.d.ts} +2 -0
- package/dist/{mod-D4g9ffEn.d.cts → mod-Mt4aO3DX.d.cts} +2 -0
- package/dist/mod.cjs +5 -5
- package/dist/mod.d.cts +1 -1
- package/dist/mod.d.ts +1 -1
- package/dist/mod.js +5 -5
- package/dist/nodeinfo/client.test.mjs +49 -1
- package/dist/nodeinfo/handler.test.mjs +2 -2
- package/dist/nodeinfo/mod.cjs +1 -1
- package/dist/nodeinfo/mod.js +1 -1
- package/dist/{owner-OdWSE8am.mjs → owner-D63yPo_i.mjs} +3 -3
- package/dist/{portable-collection-wBWbuHOH.cjs → portable-collection-B8ojoQ50.cjs} +1 -1
- package/dist/{portable-collection-BCy06GiS.js → portable-collection-C3xEzYri.js} +1 -1
- package/dist/{portable-collection-DAV7Ho3m.mjs → portable-collection-_lZg-osX.mjs} +2 -2
- package/dist/{portable-key-BL6K88p2.mjs → portable-key-D8uWZF7b.mjs} +1 -1
- package/dist/{proof-vZ04IAjq.mjs → proof-C2YwD8a_.mjs} +4 -4
- package/dist/{send-ylV8KCLx.mjs → send-D9SGhxTB.mjs} +18 -4
- 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 +42 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +5 -2
- 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 +2 -2
- package/dist/sig/portable-key.test.mjs +6 -6
- package/dist/sig/proof.test.mjs +3 -3
- package/dist/{tasks-dbCShlCb.mjs → tasks-IG3pHfvZ.mjs} +1 -1
- package/dist/{temporal-BTD4f_mZ.mjs → temporal-q6FSekcN.mjs} +1 -1
- package/dist/testing/context.test.mjs +1 -1
- package/dist/testing/kv.test.mjs +3 -3
- package/dist/testing/mod.mjs +4 -4
- package/dist/{testing-CKaJhcA0.mjs → testing-C1itIjqW.mjs} +3 -3
- package/dist/{types-C_cNlNVK.js → types-_S2_MeLF.js} +7 -3
- package/dist/{types-Be2zbyeG.cjs → types-poIao40f.cjs} +7 -3
- package/dist/utils/docloader.test.mjs +297 -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/vocab/cjs.test.mjs +1 -1
- package/package.json +7 -7
- package/dist/docloader-vc-pSu9-.mjs +0 -53
|
@@ -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-D1gcWWqB.mjs";
|
|
5
5
|
import { c as isPortableId, r as getPortableDid, t as getCanonicalPortableId } from "./portable-key-id-Bg259c4Z.mjs";
|
|
6
6
|
import { t as ActivityListenerSet } from "./activity-listener-C-BSbKI7.mjs";
|
|
7
7
|
import { getLogger } from "@logtape/logtape";
|
|
@@ -89,7 +89,7 @@ var FederationBuilderImpl = class {
|
|
|
89
89
|
* specified.
|
|
90
90
|
*/
|
|
91
91
|
async build(options) {
|
|
92
|
-
const { FederationImpl } = await import("./middleware-
|
|
92
|
+
const { FederationImpl } = await import("./middleware-TrCVULgs.mjs");
|
|
93
93
|
const f = new FederationImpl(options);
|
|
94
94
|
const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
|
|
95
95
|
f.router = this.router.clone();
|
|
@@ -93,8 +93,8 @@ const DEFAULT_MAX_REDIRECTION = 5;
|
|
|
93
93
|
* bounce the request to an internal address.
|
|
94
94
|
* @param url The URL to fetch.
|
|
95
95
|
* @param headers The request headers.
|
|
96
|
-
* @returns The final response, or `null` if the URL is disallowed
|
|
97
|
-
* are too many redirects.
|
|
96
|
+
* @returns The final response, or `null` if the URL is disallowed, its
|
|
97
|
+
* hostname cannot be resolved, or there are too many redirects.
|
|
98
98
|
*/
|
|
99
99
|
async function fetchPublicUrl(url, headers) {
|
|
100
100
|
let current = url instanceof URL ? url : new URL(url);
|
|
@@ -104,7 +104,11 @@ async function fetchPublicUrl(url, headers) {
|
|
|
104
104
|
await validatePublicUrl(current.href);
|
|
105
105
|
} catch (e) {
|
|
106
106
|
if (e instanceof UrlError) {
|
|
107
|
-
logger.error("
|
|
107
|
+
if (e.reason === "dns") logger.error("DNS lookup failed for {url}: {error}", {
|
|
108
|
+
url: current.href,
|
|
109
|
+
error: e
|
|
110
|
+
});
|
|
111
|
+
else logger.error("Refused to fetch a private or invalid URL {url}: {error}", {
|
|
108
112
|
url: current.href,
|
|
109
113
|
error: e
|
|
110
114
|
});
|
|
@@ -5,7 +5,7 @@ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
6
6
|
import { t as assertInstanceOf } from "../assert_instance_of-mrXWWNY-.mjs";
|
|
7
7
|
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
8
|
-
import { E as autoIdAssigner, T as actorDehydrator, n as FederationImpl } from "../middleware-
|
|
8
|
+
import { E as autoIdAssigner, T as actorDehydrator, n as FederationImpl } from "../middleware-xdukzV3x.mjs";
|
|
9
9
|
import { Follow, Person } from "@fedify/vocab";
|
|
10
10
|
import { test } from "@fedify/fixture";
|
|
11
11
|
//#region src/compat/transformers.test.ts
|
|
@@ -3,8 +3,8 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { c as isPortableId, i as getRawCanonicalPortableId, t as getCanonicalPortableId } from "./portable-key-id-Bg259c4Z.mjs";
|
|
5
5
|
import { n as preloadedOnlyDocumentLoader } from "./public-audience--klBIOk1.mjs";
|
|
6
|
-
import { c as getNormalizationContextLoader } from "./ld-
|
|
7
|
-
import { l as verifyPortableObjectProofPolicy, n as classifyFep2277CoreType, o as verifyMapLocalProof } from "./proof-
|
|
6
|
+
import { c as getNormalizationContextLoader } from "./ld-lU_ZqzsQ.mjs";
|
|
7
|
+
import { l as verifyPortableObjectProofPolicy, n as classifyFep2277CoreType, o as verifyMapLocalProof } from "./proof-C2YwD8a_.mjs";
|
|
8
8
|
import { parseIri, preloadedContexts } from "@fedify/vocab-runtime";
|
|
9
9
|
import jsonld from "@fedify/vocab-runtime/jsonld";
|
|
10
10
|
//#region src/sig/compound-proof.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { t as mockDocumentLoader } from "./dist-
|
|
4
|
+
import { t as mockDocumentLoader } from "./dist-DJQM4u7i.mjs";
|
|
5
5
|
import { RouterError } from "@fedify/uri-template";
|
|
6
6
|
import { lookupObject, traverseCollection } from "@fedify/vocab";
|
|
7
7
|
import { lookupWebFinger } from "@fedify/webfinger";
|
|
@@ -6,6 +6,7 @@ import { configure, getConsoleSink, getLogger, reset } from "@logtape/logtape";
|
|
|
6
6
|
import "@opentelemetry/sdk-trace-base";
|
|
7
7
|
import "@opentelemetry/core";
|
|
8
8
|
//#region ../fixture/dist/mod.js
|
|
9
|
+
const fixtureFetch = globalThis.fetch.bind(globalThis);
|
|
9
10
|
const logger = getLogger(["fixture", "docloader"]);
|
|
10
11
|
/**
|
|
11
12
|
* A mock of the document loader. This does not make any actual HTTP requests
|
|
@@ -20,7 +21,7 @@ async function mockDocumentLoader(resource, _options) {
|
|
|
20
21
|
if ("navigator" in globalThis && navigator.userAgent === "Cloudflare-Workers") {
|
|
21
22
|
const testUrl = new URL(url);
|
|
22
23
|
testUrl.hostname += ".test";
|
|
23
|
-
const resp = await
|
|
24
|
+
const resp = await fixtureFetch(testUrl);
|
|
24
25
|
if (resp.ok) {
|
|
25
26
|
const document = await resp.json();
|
|
26
27
|
logger.debug("Successfully fetched fixture {resource}: {status} {statusText}\n{body}", {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { c as validateCryptoKey } from "./key-CPM4r6tP.mjs";
|
|
5
|
+
import { n as doubleKnock } from "./http-CGcLv8rh.mjs";
|
|
6
|
+
import { getLogger } from "@logtape/logtape";
|
|
7
|
+
import { curry } from "es-toolkit";
|
|
8
|
+
import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
9
|
+
//#region src/utils/docloader.ts
|
|
10
|
+
const logger = getLogger([
|
|
11
|
+
"fedify",
|
|
12
|
+
"utils",
|
|
13
|
+
"docloader"
|
|
14
|
+
]);
|
|
15
|
+
const DEFAULT_MAX_REDIRECTION = 20;
|
|
16
|
+
/**
|
|
17
|
+
* Gets an authenticated {@link DocumentLoader} for the given identity.
|
|
18
|
+
* Note that an authenticated document loader intentionally does not cache
|
|
19
|
+
* the fetched documents.
|
|
20
|
+
* At most 20 HTTP redirects and alternate document links are followed in total
|
|
21
|
+
* per call. Revisiting a URL within that chain throws a {@link FetchError}.
|
|
22
|
+
* @param identity The identity to get the document loader for.
|
|
23
|
+
* The actor's key pair.
|
|
24
|
+
* @param options The options for the document loader.
|
|
25
|
+
* @returns The authenticated document loader.
|
|
26
|
+
* @throws {TypeError} If the key is invalid or unsupported.
|
|
27
|
+
* @since 0.4.0
|
|
28
|
+
*/
|
|
29
|
+
function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedirection, userAgent, specDeterminer, tracerProvider } = {}) {
|
|
30
|
+
validateCryptoKey(identity.privateKey);
|
|
31
|
+
async function load(url, options, redirected = 0, visited = /* @__PURE__ */ new Set()) {
|
|
32
|
+
options?.signal?.throwIfAborted();
|
|
33
|
+
let currentUrl = new URL(url).href;
|
|
34
|
+
await validateUrl(currentUrl, options);
|
|
35
|
+
visited.add(currentUrl);
|
|
36
|
+
const originalRequest = createActivityPubRequest(currentUrl, { userAgent });
|
|
37
|
+
function follow(nextUrl) {
|
|
38
|
+
options?.signal?.throwIfAborted();
|
|
39
|
+
if (redirected >= DEFAULT_MAX_REDIRECTION) throw new FetchError(currentUrl, `Too many redirections (${redirected + 1})`);
|
|
40
|
+
if (visited.has(nextUrl)) throw new FetchError(currentUrl, `Redirect loop detected: ${nextUrl}`);
|
|
41
|
+
redirected++;
|
|
42
|
+
}
|
|
43
|
+
const response = await doubleKnock(originalRequest, identity, {
|
|
44
|
+
maxRedirection,
|
|
45
|
+
specDeterminer,
|
|
46
|
+
log: curry(logRequest)(logger),
|
|
47
|
+
tracerProvider,
|
|
48
|
+
signal: options?.signal,
|
|
49
|
+
validateRedirect: async (nextUrl) => {
|
|
50
|
+
follow(nextUrl);
|
|
51
|
+
await validateUrl(nextUrl, options);
|
|
52
|
+
visited.add(nextUrl);
|
|
53
|
+
currentUrl = nextUrl;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return getRemoteDocument(currentUrl, response, (alternateUrl) => {
|
|
57
|
+
follow(alternateUrl);
|
|
58
|
+
return load(alternateUrl, options, redirected, visited);
|
|
59
|
+
}, options);
|
|
60
|
+
}
|
|
61
|
+
async function validateUrl(url, options) {
|
|
62
|
+
if (!allowPrivateAddress) try {
|
|
63
|
+
await validatePublicUrl(url);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
if (error instanceof UrlError) if (error.reason === "dns") logger.debug("DNS lookup failed for {url}", {
|
|
66
|
+
url,
|
|
67
|
+
error
|
|
68
|
+
});
|
|
69
|
+
else logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
|
|
70
|
+
url,
|
|
71
|
+
error
|
|
72
|
+
});
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return (url, options) => load(url, options);
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
export { getAuthenticatedDocumentLoader as t };
|
|
@@ -6,7 +6,7 @@ import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
|
6
6
|
import { t as assertExists } from "../assert_exists-cffSpJ7X.mjs";
|
|
7
7
|
import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
|
|
8
8
|
import "../std__assert-DvMDRPes.mjs";
|
|
9
|
-
import { r as createFederationBuilder } from "../builder-
|
|
9
|
+
import { r as createFederationBuilder } from "../builder-CLaS4-yA.mjs";
|
|
10
10
|
import { DisallowedOperatorError, DisallowedVarSpecModifierError, DuplicateRouteVariableError, RouteTemplateOptionsNotMatchedError, RouterError } from "@fedify/uri-template";
|
|
11
11
|
import { Activity, Note, Person } from "@fedify/vocab";
|
|
12
12
|
import { test } from "@fedify/fixture";
|
|
@@ -6,11 +6,11 @@ import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
|
6
6
|
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
7
7
|
import "../std__assert-DvMDRPes.mjs";
|
|
8
8
|
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
9
|
-
import { n as exportJwk } from "../key-
|
|
9
|
+
import { n as exportJwk } from "../key-CPM4r6tP.mjs";
|
|
10
10
|
import { r as normalizeOutgoingActivityJsonLd } from "../outgoing-jsonld-4IJqPYos.mjs";
|
|
11
|
-
import { a as signObject, d as verifyProof } from "../proof-
|
|
11
|
+
import { a as signObject, d as verifyProof } from "../proof-C2YwD8a_.mjs";
|
|
12
12
|
import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
|
|
13
|
-
import { n as FederationImpl } from "../middleware-
|
|
13
|
+
import { n as FederationImpl } from "../middleware-xdukzV3x.mjs";
|
|
14
14
|
import { Create, DataIntegrityProof, Note } from "@fedify/vocab";
|
|
15
15
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
16
16
|
import { exportDidKey, parseIri } from "@fedify/vocab-runtime";
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { r as createRequestContext, t as createInboxContext } from "../context-
|
|
4
|
+
import { r as createRequestContext, t as createInboxContext } from "../context-B2rlkkyJ.mjs";
|
|
5
5
|
import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
6
6
|
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
7
7
|
import "../std__assert-DvMDRPes.mjs";
|
|
8
|
-
import { a as compactJsonLd, m as verifyCompactJsonLd, p as signJsonLd } from "../ld-
|
|
9
|
-
import { l as signRequest } from "../http-
|
|
8
|
+
import { a as compactJsonLd, m as verifyCompactJsonLd, p as signJsonLd } from "../ld-lU_ZqzsQ.mjs";
|
|
9
|
+
import { l as signRequest } from "../http-CGcLv8rh.mjs";
|
|
10
10
|
import { a as rsaPrivateKey3, c as rsaPublicKey3, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
|
|
11
|
-
import { f as handleInbox, o as createFederation } from "../middleware-
|
|
11
|
+
import { f as handleInbox, o as createFederation } from "../middleware-xdukzV3x.mjs";
|
|
12
12
|
import { t as ActivityListenerSet } from "../activity-listener-C-BSbKI7.mjs";
|
|
13
13
|
import { t as map_local_create_note_default } from "../map-local-create-note-B0SeXJms.mjs";
|
|
14
14
|
import { Create, CryptographicKey, Multikey, Person, Update } from "@fedify/vocab";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-
|
|
4
|
+
import { n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-B2rlkkyJ.mjs";
|
|
5
5
|
import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
6
6
|
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
7
7
|
import { t as assertGreaterOrEqual } from "../assert_greater_or_equal-BlafOF4-.mjs";
|
|
@@ -10,12 +10,12 @@ import "../std__assert-DvMDRPes.mjs";
|
|
|
10
10
|
import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
|
|
11
11
|
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
12
12
|
import { r as parseAcceptSignature } from "../accept-CPVqki78.mjs";
|
|
13
|
-
import { o as generateCryptoKeyPair } from "../key-
|
|
14
|
-
import { a as compactJsonLd, p as signJsonLd } from "../ld-
|
|
15
|
-
import { a as signObject } from "../proof-
|
|
16
|
-
import { l as signRequest } from "../http-
|
|
13
|
+
import { o as generateCryptoKeyPair } from "../key-CPM4r6tP.mjs";
|
|
14
|
+
import { a as compactJsonLd, p as signJsonLd } from "../ld-lU_ZqzsQ.mjs";
|
|
15
|
+
import { a as signObject } from "../proof-C2YwD8a_.mjs";
|
|
16
|
+
import { l as signRequest } from "../http-CGcLv8rh.mjs";
|
|
17
17
|
import { a as rsaPrivateKey3, c as rsaPublicKey3, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
|
|
18
|
-
import { d as handleCustomCollection, f as handleInbox, g as respondWithObjectIfAcceptable, h as respondWithObject, l as handleActor, m as handleOutbox, o as createFederation, p as handleObject, u as handleCollection } from "../middleware-
|
|
18
|
+
import { d as handleCustomCollection, f as handleInbox, g as respondWithObjectIfAcceptable, h as respondWithObject, l as handleActor, m as handleOutbox, o as createFederation, p as handleObject, u as handleCollection } from "../middleware-xdukzV3x.mjs";
|
|
19
19
|
import { t as ActivityListenerSet } from "../activity-listener-C-BSbKI7.mjs";
|
|
20
20
|
import { Activity, Create, CryptographicKey, Multikey, Note, Person, Tombstone } from "@fedify/vocab";
|
|
21
21
|
import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
@@ -10,8 +10,8 @@ import "../std__assert-DvMDRPes.mjs";
|
|
|
10
10
|
import { t as assertStrictEquals } from "../assert_strict_equals-CYvBmkpC.mjs";
|
|
11
11
|
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
12
12
|
import { r as ed25519PublicKey } from "../keys-DIJNHW-Y.mjs";
|
|
13
|
-
import { o as createFederation, x as parseHashlinkGatewayRequest } from "../middleware-
|
|
14
|
-
import { r as createFederationBuilder } from "../builder-
|
|
13
|
+
import { o as createFederation, x as parseHashlinkGatewayRequest } from "../middleware-xdukzV3x.mjs";
|
|
14
|
+
import { r as createFederationBuilder } from "../builder-CLaS4-yA.mjs";
|
|
15
15
|
import { n as RouterError } from "../router-u5O5KCQr.mjs";
|
|
16
16
|
import { Note } from "@fedify/vocab";
|
|
17
17
|
import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
@@ -4,9 +4,9 @@ globalThis.addEventListener = () => {};
|
|
|
4
4
|
import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
6
6
|
import "../std__assert-DvMDRPes.mjs";
|
|
7
|
-
import { a as signObject } from "../proof-
|
|
7
|
+
import { a as signObject } from "../proof-C2YwD8a_.mjs";
|
|
8
8
|
import { n as ed25519PrivateKey, r as ed25519PublicKey, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
|
|
9
|
-
import { o as createFederation } from "../middleware-
|
|
9
|
+
import { o as createFederation } from "../middleware-xdukzV3x.mjs";
|
|
10
10
|
import { Create, Follow, Person } from "@fedify/vocab";
|
|
11
11
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
12
12
|
//#region src/federation/idempotency.test.ts
|
|
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
|
|
|
4
4
|
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
5
5
|
import "../std__assert-DvMDRPes.mjs";
|
|
6
6
|
import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
|
|
7
|
-
import { _ as recordKeyLookup, a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, m as recordDocumentFetch, p as recordDocumentCache, r as getFederationMetrics, t as classifyFetchError, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "../metrics-
|
|
7
|
+
import { _ as recordKeyLookup, a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, m as recordDocumentFetch, p as recordDocumentCache, r as getFederationMetrics, t as classifyFetchError, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "../metrics-B41pRPfd.mjs";
|
|
8
8
|
import { createTestMeterProvider, test } from "@fedify/fixture";
|
|
9
9
|
import { FetchError } from "@fedify/vocab-runtime";
|
|
10
10
|
import { DataPointType, MeterProvider, MetricReader } from "@opentelemetry/sdk-metrics";
|
|
@@ -4,8 +4,8 @@ globalThis.addEventListener = () => {};
|
|
|
4
4
|
import { t as esm_default } from "../esm-BHXXx4Wx.mjs";
|
|
5
5
|
import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
6
6
|
import { t as ManualClockKvStore } from "../kv-DBRWVx3Q.mjs";
|
|
7
|
-
import { a as numberSchema, r as envelopeSchema, t as MockQueue } from "../tasks-
|
|
8
|
-
import "../testing-
|
|
7
|
+
import { a as numberSchema, r as envelopeSchema, t as MockQueue } from "../tasks-IG3pHfvZ.mjs";
|
|
8
|
+
import "../testing-C1itIjqW.mjs";
|
|
9
9
|
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
10
10
|
import { t as assertExists } from "../assert_exists-cffSpJ7X.mjs";
|
|
11
11
|
import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
|
|
@@ -16,14 +16,14 @@ import "../std__assert-DvMDRPes.mjs";
|
|
|
16
16
|
import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
|
|
17
17
|
import { t as assertStrictEquals } from "../assert_strict_equals-CYvBmkpC.mjs";
|
|
18
18
|
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
19
|
-
import { g as recordInboxActivity } from "../metrics-
|
|
20
|
-
import { a as compactJsonLd, h as verifyJsonLd, p as signJsonLd, s as detachSignature } from "../ld-
|
|
21
|
-
import { a as signObject, s as verifyObject } from "../proof-
|
|
22
|
-
import { d as verifyRequest, l as signRequest } from "../http-
|
|
19
|
+
import { g as recordInboxActivity } from "../metrics-B41pRPfd.mjs";
|
|
20
|
+
import { a as compactJsonLd, h as verifyJsonLd, p as signJsonLd, s as detachSignature } from "../ld-lU_ZqzsQ.mjs";
|
|
21
|
+
import { a as signObject, s as verifyObject } from "../proof-C2YwD8a_.mjs";
|
|
22
|
+
import { d as verifyRequest, l as signRequest } from "../http-CGcLv8rh.mjs";
|
|
23
23
|
import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
|
|
24
|
-
import { t as getAuthenticatedDocumentLoader } from "../docloader-
|
|
25
|
-
import { S as handleBenchmarkTrigger, i as KvSpecDeterminer, n as FederationImpl, o as createFederation, r as InboxContextImpl, t as ContextImpl } from "../middleware-
|
|
26
|
-
import { t as doesActorOwnKey } from "../owner-
|
|
24
|
+
import { t as getAuthenticatedDocumentLoader } from "../docloader-BMqr3hji.mjs";
|
|
25
|
+
import { S as handleBenchmarkTrigger, i as KvSpecDeterminer, n as FederationImpl, o as createFederation, r as InboxContextImpl, t as ContextImpl } from "../middleware-xdukzV3x.mjs";
|
|
26
|
+
import { t as doesActorOwnKey } from "../owner-D63yPo_i.mjs";
|
|
27
27
|
import { t as CircuitBreaker } from "../circuit-breaker-C5NqoLBJ.mjs";
|
|
28
28
|
import { t as TaskCodec } from "../codec-C6rTrpIp.mjs";
|
|
29
29
|
import { t as markCircuitBreakerLegacySweepDone } from "../circuit-breaker-test-utils-DW6YC_Pe.mjs";
|
|
@@ -34,8 +34,9 @@ import { Create, Note, Offer, Person, getTypeId, lookupObject } from "@fedify/vo
|
|
|
34
34
|
import { SpanStatusCode, metrics } from "@opentelemetry/api";
|
|
35
35
|
import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
36
36
|
import { FetchError, UrlError, getDocumentLoader } from "@fedify/vocab-runtime";
|
|
37
|
-
import
|
|
37
|
+
import dns from "node:dns/promises";
|
|
38
38
|
import { deepStrictEqual, ok, rejects, strictEqual } from "node:assert/strict";
|
|
39
|
+
import serialize from "json-canon";
|
|
39
40
|
import { DataPointType, MeterProvider as MeterProvider$1, MetricReader } from "@opentelemetry/sdk-metrics";
|
|
40
41
|
//#region ../fixture/src/fixtures/example.com/create.json
|
|
41
42
|
var create_default = {
|
|
@@ -1175,6 +1176,31 @@ test({
|
|
|
1175
1176
|
esm_default.hardReset();
|
|
1176
1177
|
}
|
|
1177
1178
|
});
|
|
1179
|
+
test("Federation.fetch() [rfc9421] multiple POST signatures", async (t) => {
|
|
1180
|
+
for (const validSecond of [true, false]) await t.step(validSecond ? "valid second signature" : "both signatures invalid", async () => {
|
|
1181
|
+
const inbox = [];
|
|
1182
|
+
const federation = createFederation({
|
|
1183
|
+
kv: new MemoryKvStore(),
|
|
1184
|
+
documentLoaderFactory: () => mockDocumentLoader,
|
|
1185
|
+
contextLoaderFactory: () => mockDocumentLoader
|
|
1186
|
+
});
|
|
1187
|
+
federation.setActorDispatcher("/users/{identifier}", (ctx, identifier) => new vocab.Person({ id: ctx.getActorUri(identifier) }));
|
|
1188
|
+
federation.setInboxListeners("/users/{identifier}/inbox", "/inbox").on(vocab.Create, (_ctx, activity) => {
|
|
1189
|
+
inbox.push(activity.id.href);
|
|
1190
|
+
});
|
|
1191
|
+
const signed = await signRequest(new Request("https://example.com/inbox", {
|
|
1192
|
+
method: "POST",
|
|
1193
|
+
headers: { "Content-Type": "application/activity+json" },
|
|
1194
|
+
body: JSON.stringify(create_default)
|
|
1195
|
+
}), rsaPrivateKey2, rsaPublicKey2.id, { spec: "rfc9421" });
|
|
1196
|
+
const input = signed.headers.get("Signature-Input");
|
|
1197
|
+
const signature = signed.headers.get("Signature");
|
|
1198
|
+
signed.headers.set("Signature-Input", `${input}, ${input.replace(/^sig1=/, "sig2=")}`);
|
|
1199
|
+
signed.headers.set("Signature", `sig1=:AAAAAA==:, ${validSecond ? signature.replace(/^sig1=/, "sig2=") : "sig2=:AAAAAA==:"}`);
|
|
1200
|
+
assertEquals((await federation.fetch(signed, { contextData: void 0 })).status, validSecond ? 202 : 401);
|
|
1201
|
+
assertEquals(inbox, validSecond ? [create_default.id] : []);
|
|
1202
|
+
});
|
|
1203
|
+
});
|
|
1178
1204
|
test("Federation.fetch()", async (t) => {
|
|
1179
1205
|
esm_default.spyGlobal();
|
|
1180
1206
|
esm_default.get("https://example.com/key2", {
|
|
@@ -4943,6 +4969,157 @@ test("FederationImpl.processQueuedTask()", async (t) => {
|
|
|
4943
4969
|
assertEquals(queuedMessages, []);
|
|
4944
4970
|
});
|
|
4945
4971
|
});
|
|
4972
|
+
test({
|
|
4973
|
+
name: "FederationImpl.processQueuedTask() accounts for destination validation failures",
|
|
4974
|
+
ignore: "Deno" in globalThis && (await Deno.permissions.query({ name: "net" })).state !== "granted",
|
|
4975
|
+
async fn(t) {
|
|
4976
|
+
for (const result of [
|
|
4977
|
+
"throws",
|
|
4978
|
+
"empty",
|
|
4979
|
+
"private"
|
|
4980
|
+
]) for (const failureThreshold of [1, 5]) for (const redirected of [false, true]) await t.step(`${result}, threshold: ${failureThreshold}, redirected: ${redirected}`, async () => {
|
|
4981
|
+
const destination = "https://delivery.invalid/inbox";
|
|
4982
|
+
const publicInbox = "https://8.8.8.8/inbox";
|
|
4983
|
+
const queuedMessages = [];
|
|
4984
|
+
const delays = [];
|
|
4985
|
+
const errors = [];
|
|
4986
|
+
const activities = [];
|
|
4987
|
+
const attempts = [];
|
|
4988
|
+
const delay = Temporal.Duration.from({ seconds: 5 });
|
|
4989
|
+
const kv = new MemoryKvStore();
|
|
4990
|
+
await markCircuitBreakerLegacySweepDone(kv);
|
|
4991
|
+
const [meterProvider, recorder] = createTestMeterProvider();
|
|
4992
|
+
const recoveryDelay = Temporal.Duration.from({ minutes: 30 });
|
|
4993
|
+
const federation = new FederationImpl({
|
|
4994
|
+
kv,
|
|
4995
|
+
meterProvider,
|
|
4996
|
+
circuitBreaker: {
|
|
4997
|
+
failureThreshold,
|
|
4998
|
+
recoveryDelay
|
|
4999
|
+
},
|
|
5000
|
+
queue: {
|
|
5001
|
+
enqueue(message, options) {
|
|
5002
|
+
queuedMessages.push(message);
|
|
5003
|
+
delays.push(options?.delay);
|
|
5004
|
+
return Promise.resolve();
|
|
5005
|
+
},
|
|
5006
|
+
listen() {
|
|
5007
|
+
return Promise.resolve();
|
|
5008
|
+
}
|
|
5009
|
+
},
|
|
5010
|
+
documentLoaderFactory: () => mockDocumentLoader,
|
|
5011
|
+
contextLoaderFactory: () => mockDocumentLoader,
|
|
5012
|
+
onOutboxError(error, activity) {
|
|
5013
|
+
errors.push(error);
|
|
5014
|
+
activities.push(activity);
|
|
5015
|
+
},
|
|
5016
|
+
outboxRetryPolicy(options) {
|
|
5017
|
+
attempts.push(options.attempts);
|
|
5018
|
+
return delay;
|
|
5019
|
+
}
|
|
5020
|
+
});
|
|
5021
|
+
const message = {
|
|
5022
|
+
type: "outbox",
|
|
5023
|
+
id: crypto.randomUUID(),
|
|
5024
|
+
baseUrl: "https://example.com",
|
|
5025
|
+
keys: [],
|
|
5026
|
+
activity: {
|
|
5027
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
5028
|
+
type: "Create",
|
|
5029
|
+
id: "https://example.com/activities/dns-failure",
|
|
5030
|
+
actor: "https://example.com/users/alice",
|
|
5031
|
+
object: {
|
|
5032
|
+
type: "Note",
|
|
5033
|
+
content: "test"
|
|
5034
|
+
}
|
|
5035
|
+
},
|
|
5036
|
+
activityType: "https://www.w3.org/ns/activitystreams#Create",
|
|
5037
|
+
inbox: redirected ? publicInbox : destination,
|
|
5038
|
+
sharedInbox: false,
|
|
5039
|
+
started: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5040
|
+
attempt: 0,
|
|
5041
|
+
headers: {},
|
|
5042
|
+
traceContext: {}
|
|
5043
|
+
};
|
|
5044
|
+
const originalLookup = dns.lookup;
|
|
5045
|
+
const resolverError = /* @__PURE__ */ new Error("Resolver unavailable");
|
|
5046
|
+
const lookups = [];
|
|
5047
|
+
dns.lookup = ((hostname) => {
|
|
5048
|
+
lookups.push(hostname);
|
|
5049
|
+
assertEquals(hostname, "delivery.invalid");
|
|
5050
|
+
if (result === "throws") return Promise.reject(resolverError);
|
|
5051
|
+
return Promise.resolve(result === "empty" ? [] : [{
|
|
5052
|
+
address: "127.0.0.1",
|
|
5053
|
+
family: 4
|
|
5054
|
+
}]);
|
|
5055
|
+
});
|
|
5056
|
+
try {
|
|
5057
|
+
esm_default.mockGlobal().catch(202);
|
|
5058
|
+
if (redirected) esm_default.route(publicInbox, {
|
|
5059
|
+
status: 307,
|
|
5060
|
+
headers: { Location: destination }
|
|
5061
|
+
});
|
|
5062
|
+
await federation.processQueuedTask(void 0, message);
|
|
5063
|
+
assertEquals(errors.length, 1);
|
|
5064
|
+
const error = errors[0];
|
|
5065
|
+
if (result === "private") {
|
|
5066
|
+
assertInstanceOf(error, UrlError);
|
|
5067
|
+
assertEquals(error.reason, "disallowed");
|
|
5068
|
+
} else {
|
|
5069
|
+
assertInstanceOf(error, FetchError);
|
|
5070
|
+
assertEquals(error.url.href, destination);
|
|
5071
|
+
assertInstanceOf(error.cause, UrlError);
|
|
5072
|
+
assertEquals(error.cause.reason, "dns");
|
|
5073
|
+
assertStrictEquals(error.cause.cause, result === "throws" ? resolverError : void 0);
|
|
5074
|
+
}
|
|
5075
|
+
assertEquals(activities.length, 1);
|
|
5076
|
+
assertInstanceOf(activities[0], Create);
|
|
5077
|
+
assertEquals(activities[0].id?.href, "https://example.com/activities/dns-failure");
|
|
5078
|
+
assertEquals(attempts, [0]);
|
|
5079
|
+
const host = new URL(message.inbox).host;
|
|
5080
|
+
const state = await kv.get([
|
|
5081
|
+
"_fedify",
|
|
5082
|
+
"circuit",
|
|
5083
|
+
host
|
|
5084
|
+
]);
|
|
5085
|
+
if (result === "private") assertEquals(state, void 0);
|
|
5086
|
+
else {
|
|
5087
|
+
assertExists(state);
|
|
5088
|
+
assertEquals(state.failures.length, 1);
|
|
5089
|
+
assertEquals(state.state, failureThreshold === 1 ? "open" : "closed");
|
|
5090
|
+
}
|
|
5091
|
+
if (result !== "private" && failureThreshold === 1) {
|
|
5092
|
+
assertEquals(queuedMessages.length, 1);
|
|
5093
|
+
const held = queuedMessages[0];
|
|
5094
|
+
assertEquals(held.attempt, 0);
|
|
5095
|
+
assertEquals(held.circuitHeld, true);
|
|
5096
|
+
assertExists(held.circuitHeldSince);
|
|
5097
|
+
assertEquals(delays, [recoveryDelay]);
|
|
5098
|
+
} else {
|
|
5099
|
+
assertEquals(queuedMessages, [{
|
|
5100
|
+
...message,
|
|
5101
|
+
attempt: 1
|
|
5102
|
+
}]);
|
|
5103
|
+
assertEquals(delays, [delay]);
|
|
5104
|
+
}
|
|
5105
|
+
const expectedCount = result === "private" && !redirected ? 0 : 1;
|
|
5106
|
+
const sent = recorder.getMeasurements("activitypub.delivery.sent");
|
|
5107
|
+
assertEquals(sent.length, expectedCount);
|
|
5108
|
+
if (expectedCount === 1) {
|
|
5109
|
+
assertEquals(sent[0].value, 1);
|
|
5110
|
+
assertEquals(sent[0].attributes["activitypub.delivery.success"], false);
|
|
5111
|
+
assertEquals(sent[0].attributes["activitypub.remote.host"], host);
|
|
5112
|
+
}
|
|
5113
|
+
assertEquals(lookups, ["delivery.invalid"]);
|
|
5114
|
+
assertEquals(esm_default.callHistory.calls(destination).length, 0);
|
|
5115
|
+
assertEquals(esm_default.callHistory.calls().length, redirected ? 1 : 0);
|
|
5116
|
+
} finally {
|
|
5117
|
+
dns.lookup = originalLookup;
|
|
5118
|
+
esm_default.hardReset();
|
|
5119
|
+
}
|
|
5120
|
+
});
|
|
5121
|
+
}
|
|
5122
|
+
});
|
|
4946
5123
|
test("FederationImpl.processQueuedTask() permanent failure", async (t) => {
|
|
4947
5124
|
esm_default.spyGlobal();
|
|
4948
5125
|
esm_default.post("https://gone.example/inbox", {
|
package/dist/federation/mod.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const require_federation = require("../federation-
|
|
3
|
+
const require_federation = require("../federation-2e8XrN7q.cjs");
|
|
4
4
|
exports.CircuitBreaker = require_federation.CircuitBreaker;
|
|
5
5
|
exports.InProcessMessageQueue = require_federation.InProcessMessageQueue;
|
|
6
6
|
exports.MemoryKvStore = require_federation.MemoryKvStore;
|
package/dist/federation/mod.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { a as respondWithObjectIfAcceptable, c as digest, d as parseCircuitBreakerKvState, f as createFederationBuilder, i as respondWithObject, l as CircuitBreaker, n as handleWebFinger, o as SendActivityError, r as createExponentialBackoffPolicy, s as buildCollectionSynchronizationHeader, t as createFederation, u as normalizeCircuitBreakerOptions } from "../middleware-
|
|
3
|
+
import { a as respondWithObjectIfAcceptable, c as digest, d as parseCircuitBreakerKvState, f as createFederationBuilder, i as respondWithObject, l as CircuitBreaker, n as handleWebFinger, o as SendActivityError, r as createExponentialBackoffPolicy, s as buildCollectionSynchronizationHeader, t as createFederation, u as normalizeCircuitBreakerOptions } from "../middleware-BYWyYjmX.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";
|