@fedify/fedify 2.3.12 → 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-B6ixdT3y.mjs → builder-BagNDcQw.mjs} +2 -2
- package/dist/compat/transformers.test.mjs +2 -2
- package/dist/{deno-D4dcoVfF.mjs → deno-XpcjbHwj.mjs} +1 -1
- package/dist/{docloader-NOKfswJV.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-HjidyDfF.mjs → http-BRrpIDS1.mjs} +3 -3
- package/dist/{http-D_Xrr6kp.cjs → http-DwPnG87d.cjs} +1 -1
- package/dist/{http-DkyUBs_T.js → http-GHVGCeb5.js} +1 -1
- package/dist/inbox-BzOuCPLY.mjs +180 -0
- package/dist/{key-Dg-NXm4K.mjs → key-PdEu1lDF.mjs} +2 -2
- package/dist/{kv-cache-BhGeZk_o.js → kv-cache-BmqdF048.js} +3 -1
- package/dist/{kv-cache-BpVwvcSI.mjs → kv-cache-Clx3SwMp.mjs} +1 -1
- package/dist/{kv-cache-BwnC6JGt.cjs → kv-cache-poF6Tqnz.cjs} +3 -1
- package/dist/{ld-C1wveXXf.mjs → ld-D6UlzNnG.mjs} +3 -3
- package/dist/{metrics-cIaMxG0v.mjs → metrics-62qolVUY.mjs} +1 -1
- package/dist/{middleware-VxPpU0h_.mjs → middleware-C3Q3CoR8.mjs} +1 -1
- package/dist/{middleware-I-XlrRVl.mjs → middleware-CfbFdEO-.mjs} +96 -194
- package/dist/{middleware-DhOFTXmo.cjs → middleware-DkrXqZO_.cjs} +106 -34
- package/dist/{middleware-CnrzVu9i.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-CFKfE85G.mjs → owner-DWnLg-vk.mjs} +2 -2
- package/dist/{proof-HU__qtUD.js → proof-CUSzBztF.js} +1 -1
- package/dist/{proof-DBxu6g2K.cjs → proof-DF6CU-SU.cjs} +1 -1
- package/dist/{proof-DtpGEj0u.mjs → proof-mf6h7n4_.mjs} +3 -3
- package/dist/{send-CwMea5r6.mjs → send-LJUzNpVF.mjs} +3 -3
- package/dist/sig/http.test.mjs +6 -6
- package/dist/sig/key.test.mjs +6 -6
- 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-ClSXyHyu.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 +6 -6
- /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
|
/**
|
|
@@ -10,7 +10,7 @@ import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } fro
|
|
|
10
10
|
import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
|
|
11
11
|
//#region deno.json
|
|
12
12
|
var name = "@fedify/fedify";
|
|
13
|
-
var version = "2.3.
|
|
13
|
+
var version = "2.3.13";
|
|
14
14
|
//#endregion
|
|
15
15
|
//#region src/sig/accept.ts
|
|
16
16
|
/**
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { n as version, t as name } from "./deno-XpcjbHwj.mjs";
|
|
5
|
+
import { g as recordInboxActivity, n as getDurationMs, r as getFederationMetrics } from "./metrics-62qolVUY.mjs";
|
|
6
|
+
import { getLogger } from "@logtape/logtape";
|
|
7
|
+
import { getTypeId } from "@fedify/vocab";
|
|
8
|
+
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
9
|
+
//#region src/federation/inbox.ts
|
|
10
|
+
/**
|
|
11
|
+
* Checks whether an activity's ID and all of its actor IDs have the same
|
|
12
|
+
* non-opaque origin. Activities without an ID have no origin to authenticate.
|
|
13
|
+
*
|
|
14
|
+
* The caller is responsible for rejecting a missing primary actor ID before
|
|
15
|
+
* relying on this check.
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
function actorsHaveSameOrigin(activity) {
|
|
19
|
+
if (activity.id == null) return true;
|
|
20
|
+
const origin = activity.id.origin;
|
|
21
|
+
return origin !== "null" && activity.actorIds.every((actor) => actor.origin === origin);
|
|
22
|
+
}
|
|
23
|
+
async function routeActivity({ context: ctx, json, originalJson, normalizedActivity, ldSignatureVerified, activity, recipient, inboxListeners, inboxContextFactory, listenerInboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, meterProvider, tracerProvider, idempotencyStrategy }) {
|
|
24
|
+
const logger = getLogger([
|
|
25
|
+
"fedify",
|
|
26
|
+
"federation",
|
|
27
|
+
"inbox"
|
|
28
|
+
]);
|
|
29
|
+
if (activity.actorId == null) {
|
|
30
|
+
logger.error("Missing actor.", { activity: json });
|
|
31
|
+
span.setStatus({
|
|
32
|
+
code: SpanStatusCode.ERROR,
|
|
33
|
+
message: "Missing actor."
|
|
34
|
+
});
|
|
35
|
+
recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
|
|
36
|
+
return "missingActor";
|
|
37
|
+
}
|
|
38
|
+
let cacheKey = null;
|
|
39
|
+
if (activity.id != null) {
|
|
40
|
+
const inboxContext = inboxContextFactory(recipient, json, activity.id?.href, getTypeId(activity).href);
|
|
41
|
+
const strategy = idempotencyStrategy ?? "per-inbox";
|
|
42
|
+
let keyString;
|
|
43
|
+
if (typeof strategy === "function") keyString = await strategy(inboxContext, activity);
|
|
44
|
+
else switch (strategy) {
|
|
45
|
+
case "global":
|
|
46
|
+
keyString = activity.id.href;
|
|
47
|
+
break;
|
|
48
|
+
case "per-origin":
|
|
49
|
+
keyString = `${ctx.origin}\n${activity.id.href}`;
|
|
50
|
+
break;
|
|
51
|
+
case "per-inbox":
|
|
52
|
+
keyString = `${ctx.origin}\n${activity.id.href}\n${recipient == null ? "sharedInbox" : `inbox\n${recipient}`}`;
|
|
53
|
+
break;
|
|
54
|
+
default: keyString = `${ctx.origin}\n${activity.id.href}`;
|
|
55
|
+
}
|
|
56
|
+
if (keyString != null) cacheKey = [...kvPrefixes.activityIdempotence, keyString];
|
|
57
|
+
}
|
|
58
|
+
if (cacheKey != null) {
|
|
59
|
+
if (await kv.get(cacheKey) === true) {
|
|
60
|
+
logger.debug("Activity {activityId} has already been processed.", {
|
|
61
|
+
activityId: activity.id?.href,
|
|
62
|
+
activity: json,
|
|
63
|
+
recipient
|
|
64
|
+
});
|
|
65
|
+
span.setStatus({
|
|
66
|
+
code: SpanStatusCode.UNSET,
|
|
67
|
+
message: `Activity ${activity.id?.href} has already been processed.`
|
|
68
|
+
});
|
|
69
|
+
recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
|
|
70
|
+
return "alreadyProcessed";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
span.setAttribute("activitypub.actor.id", activity.actorId.href);
|
|
74
|
+
if (queue != null) {
|
|
75
|
+
const carrier = {};
|
|
76
|
+
propagation.inject(context.active(), carrier);
|
|
77
|
+
try {
|
|
78
|
+
await queue.enqueue({
|
|
79
|
+
type: "inbox",
|
|
80
|
+
id: crypto.randomUUID(),
|
|
81
|
+
baseUrl: ctx.origin,
|
|
82
|
+
activity: originalJson ?? json,
|
|
83
|
+
...normalizedActivity == null ? {} : { normalizedActivity },
|
|
84
|
+
...ldSignatureVerified == null ? {} : { ldSignatureVerified },
|
|
85
|
+
identifier: recipient,
|
|
86
|
+
attempt: 0,
|
|
87
|
+
started: (/* @__PURE__ */ new Date()).toISOString(),
|
|
88
|
+
traceContext: carrier
|
|
89
|
+
});
|
|
90
|
+
} catch (error) {
|
|
91
|
+
logger.error("Failed to enqueue the incoming activity {activityId}:\n{error}", {
|
|
92
|
+
error,
|
|
93
|
+
activityId: activity.id?.href,
|
|
94
|
+
activity: json,
|
|
95
|
+
recipient
|
|
96
|
+
});
|
|
97
|
+
span.setStatus({
|
|
98
|
+
code: SpanStatusCode.ERROR,
|
|
99
|
+
message: `Failed to enqueue the incoming activity ${activity.id?.href}.`
|
|
100
|
+
});
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
getFederationMetrics(meterProvider).recordQueueTaskEnqueued({
|
|
104
|
+
role: "inbox",
|
|
105
|
+
queue,
|
|
106
|
+
activityType: getTypeId(activity).href
|
|
107
|
+
}, 0);
|
|
108
|
+
recordInboxActivity(meterProvider, "queued", getTypeId(activity).href);
|
|
109
|
+
logger.info("Activity {activityId} is enqueued.", {
|
|
110
|
+
activityId: activity.id?.href,
|
|
111
|
+
activity: json,
|
|
112
|
+
recipient
|
|
113
|
+
});
|
|
114
|
+
return "enqueued";
|
|
115
|
+
}
|
|
116
|
+
tracerProvider = tracerProvider ?? trace.getTracerProvider();
|
|
117
|
+
return await tracerProvider.getTracer(name, version).startActiveSpan("activitypub.dispatch_inbox_listener", { kind: SpanKind.INTERNAL }, async (span) => {
|
|
118
|
+
const dispatched = inboxListeners?.dispatchWithClass(activity);
|
|
119
|
+
if (dispatched == null) {
|
|
120
|
+
logger.error("Unsupported activity type:\n{activity}", {
|
|
121
|
+
activity: json,
|
|
122
|
+
recipient
|
|
123
|
+
});
|
|
124
|
+
span.setStatus({
|
|
125
|
+
code: SpanStatusCode.UNSET,
|
|
126
|
+
message: `Unsupported activity type: ${getTypeId(activity).href}`
|
|
127
|
+
});
|
|
128
|
+
recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
|
|
129
|
+
span.end();
|
|
130
|
+
return "unsupportedActivity";
|
|
131
|
+
}
|
|
132
|
+
const { class: cls, listener } = dispatched;
|
|
133
|
+
span.updateName(`activitypub.dispatch_inbox_listener ${cls.name}`);
|
|
134
|
+
try {
|
|
135
|
+
const activityType = getTypeId(activity).href;
|
|
136
|
+
const started = performance.now();
|
|
137
|
+
try {
|
|
138
|
+
const contextFactory = listenerInboxContextFactory ?? inboxContextFactory;
|
|
139
|
+
await listener(contextFactory(recipient, contextFactory === inboxContextFactory ? json : originalJson ?? json, activity.id?.href, activityType), activity);
|
|
140
|
+
} finally {
|
|
141
|
+
getFederationMetrics(meterProvider).recordInboxProcessingDuration(activityType, getDurationMs(started));
|
|
142
|
+
}
|
|
143
|
+
} catch (error) {
|
|
144
|
+
try {
|
|
145
|
+
await inboxErrorHandler?.(ctx, error);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
logger.error("An unexpected error occurred in inbox error handler:\n{error}", {
|
|
148
|
+
error,
|
|
149
|
+
activityId: activity.id?.href,
|
|
150
|
+
activity: json,
|
|
151
|
+
recipient
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
logger.error("Failed to process the incoming activity {activityId}:\n{error}", {
|
|
155
|
+
error,
|
|
156
|
+
activityId: activity.id?.href,
|
|
157
|
+
activity: json,
|
|
158
|
+
recipient
|
|
159
|
+
});
|
|
160
|
+
span.setStatus({
|
|
161
|
+
code: SpanStatusCode.ERROR,
|
|
162
|
+
message: String(error)
|
|
163
|
+
});
|
|
164
|
+
recordInboxActivity(meterProvider, "rejected", getTypeId(activity).href);
|
|
165
|
+
span.end();
|
|
166
|
+
return "error";
|
|
167
|
+
}
|
|
168
|
+
recordInboxActivity(meterProvider, "processed", getTypeId(activity).href);
|
|
169
|
+
if (cacheKey != null) await kv.set(cacheKey, true, { ttl: Temporal.Duration.from({ days: 1 }) });
|
|
170
|
+
logger.info("Activity {activityId} has been processed.", {
|
|
171
|
+
activityId: activity.id?.href,
|
|
172
|
+
activity: json,
|
|
173
|
+
recipient
|
|
174
|
+
});
|
|
175
|
+
span.end();
|
|
176
|
+
return "success";
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
//#endregion
|
|
180
|
+
export { routeActivity as n, actorsHaveSameOrigin as t };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-
|
|
4
|
+
import { n as version, t as name } from "./deno-XpcjbHwj.mjs";
|
|
5
|
+
import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-62qolVUY.mjs";
|
|
6
6
|
import { getLogger } from "@logtape/logtape";
|
|
7
7
|
import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
|
|
8
8
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { T as recordDocumentCache, f as validateCryptoKey, t as doubleKnock } from "./http-
|
|
3
|
+
import { T as recordDocumentCache, f as validateCryptoKey, t as doubleKnock } from "./http-GHVGCeb5.js";
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
5
|
import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
6
6
|
import { curry } from "es-toolkit";
|
|
@@ -57,6 +57,8 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedi
|
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
async function validateUrl(url) {
|
|
60
|
+
const protocol = new URL(url).protocol;
|
|
61
|
+
if (protocol !== "http:" && protocol !== "https:") throw new UrlError(`Unsupported protocol: ${protocol}`);
|
|
60
62
|
if (!allowPrivateAddress) try {
|
|
61
63
|
await validatePublicUrl(url);
|
|
62
64
|
} catch (error) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "@js-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-62qolVUY.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,7 +1,7 @@
|
|
|
1
1
|
const { Temporal } = require("@js-temporal/polyfill");
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
3
|
require("./chunk-DDcVe30Y.cjs");
|
|
4
|
-
const require_http = require("./http-
|
|
4
|
+
const require_http = require("./http-DwPnG87d.cjs");
|
|
5
5
|
let _logtape_logtape = require("@logtape/logtape");
|
|
6
6
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
7
7
|
let es_toolkit = require("es-toolkit");
|
|
@@ -58,6 +58,8 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedi
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
async function validateUrl(url) {
|
|
61
|
+
const protocol = new URL(url).protocol;
|
|
62
|
+
if (protocol !== "http:" && protocol !== "https:") throw new _fedify_vocab_runtime.UrlError(`Unsupported protocol: ${protocol}`);
|
|
61
63
|
if (!allowPrivateAddress) try {
|
|
62
64
|
await (0, _fedify_vocab_runtime.validatePublicUrl)(url);
|
|
63
65
|
} catch (error) {
|