@fedify/fedify 2.0.22-dev.1552 → 2.0.22
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-BGn4fR4T.mjs → builder-BO_JMtJs.mjs} +3 -3
- package/dist/{client-A1UrnX6I.mjs → client-HLLGHiTU.mjs} +63 -5
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{deno-CzWRdvbm.mjs → deno-661NE5Kk.mjs} +1 -1
- package/dist/{docloader-DL03Z6Do.mjs → docloader-Doj2y_GK.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +4 -4
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/inbox.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +6 -6
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.js +1 -1
- package/dist/federation/send.test.mjs +3 -3
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +69 -7
- package/dist/{http-vxO9IEIy.mjs → http-BQL35dN0.mjs} +2 -2
- package/dist/{http-DSQs81GP.js → http-CC2-WkSX.js} +1 -1
- package/dist/{http-CN2DyRdw.cjs → http-DWhQe-I5.cjs} +1 -1
- package/dist/{inbox-hJL9klR1.mjs → inbox-Bqoa4PJZ.mjs} +1 -1
- package/dist/{key-4XtzJ1-9.mjs → key-C0qmhoN-.mjs} +1 -1
- package/dist/{kv-cache-dYvBso-A.js → kv-cache-C7XaTsof.js} +1 -1
- package/dist/{kv-cache-BFV5hAXm.cjs → kv-cache-DY8Q_hte.cjs} +1 -1
- package/dist/{ld-B9yNvtQU.mjs → ld-B2MKYZcj.mjs} +2 -2
- package/dist/{middleware-CNRI-93D.cjs → middleware-BxR2EmWw.cjs} +1 -1
- package/dist/{middleware-BqIso1Ys.cjs → middleware-DJcsKDyA.cjs} +40 -22
- package/dist/{middleware-DDZEjS18.js → middleware-DMsZ7PRo.js} +39 -21
- package/dist/{middleware-CfGAgFCR.mjs → middleware-DPmN82D7.mjs} +1 -1
- package/dist/{middleware-DvBRn8oT.mjs → middleware-DVqurycM.mjs} +47 -29
- package/dist/mod.cjs +5 -5
- package/dist/mod.js +5 -5
- package/dist/nodeinfo/client.test.mjs +61 -1
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/nodeinfo/mod.cjs +1 -1
- package/dist/nodeinfo/mod.js +1 -1
- package/dist/{owner-u-sxpb4s.mjs → owner-BUbV-zsu.mjs} +2 -2
- package/dist/{proof-qW3joN5t.cjs → proof-B8z-9_xo.cjs} +1 -1
- package/dist/{proof-AuTxaSx2.js → proof-CGOJ4Mq3.js} +1 -1
- package/dist/{proof-CU4dSRI6.mjs → proof-pGWMVV0R.mjs} +2 -2
- package/dist/{send-DliU7LA6.mjs → send-DrKWpXWF.mjs} +2 -2
- package/dist/sig/http.test.mjs +2 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +2 -2
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/proof.test.mjs +1 -1
- package/dist/{temporal-BdqleueJ.mjs → temporal-BUr1JyFa.mjs} +1 -1
- package/dist/{types-CAY3OdLq.js → types-DTONwNqL.js} +63 -5
- package/dist/{types-KC4QAoxe.cjs → types-m8u9L86X.cjs} +62 -4
- package/dist/utils/docloader.test.mjs +2 -2
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +5 -5
|
@@ -2,10 +2,10 @@ import { Temporal } from "@js-temporal/polyfill";
|
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
import { t as __exportAll } from "./chunk-CRNNMoPX.js";
|
|
4
4
|
import { r as getDefaultActivityTransformers } from "./transformers-BGMIq1cs.js";
|
|
5
|
-
import { c as validateCryptoKey, i as exportJwk, l as name, r as verifyRequest, s as importJwk, t as doubleKnock, u as version } from "./http-
|
|
6
|
-
import { _ as signJsonLd, a as doesActorOwnKey, c as assertSafeJsonLd, f as detachSignature, g as isInvalidUrlTypeError, h as isClearlyMalformedContextReference, m as hasSignature, n as signObject, o as getKeyOwner, p as getNormalizationContextLoader, r as verifyObject, s as InvalidContextReferenceError, u as compactJsonLd, v as verifyCompactJsonLd, x as wrapContextLoaderForJsonLd } from "./proof-
|
|
7
|
-
import { n as getNodeInfo, t as nodeInfoToJson } from "./types-
|
|
8
|
-
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-
|
|
5
|
+
import { c as validateCryptoKey, i as exportJwk, l as name, r as verifyRequest, s as importJwk, t as doubleKnock, u as version } from "./http-CC2-WkSX.js";
|
|
6
|
+
import { _ as signJsonLd, a as doesActorOwnKey, c as assertSafeJsonLd, f as detachSignature, g as isInvalidUrlTypeError, h as isClearlyMalformedContextReference, m as hasSignature, n as signObject, o as getKeyOwner, p as getNormalizationContextLoader, r as verifyObject, s as InvalidContextReferenceError, u as compactJsonLd, v as verifyCompactJsonLd, x as wrapContextLoaderForJsonLd } from "./proof-CGOJ4Mq3.js";
|
|
7
|
+
import { n as getNodeInfo, t as nodeInfoToJson } from "./types-DTONwNqL.js";
|
|
8
|
+
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-C7XaTsof.js";
|
|
9
9
|
import { getLogger, withContext } from "@logtape/logtape";
|
|
10
10
|
import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
|
|
11
11
|
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
@@ -2354,6 +2354,24 @@ const logger = getLogger([
|
|
|
2354
2354
|
"webfinger",
|
|
2355
2355
|
"server"
|
|
2356
2356
|
]);
|
|
2357
|
+
function getWebFingerSubjectAndAliases({ resourceUrl, actorUri, preferredUsername, acctUsername, host, contextHost }) {
|
|
2358
|
+
const aliases = [];
|
|
2359
|
+
let subject = resourceUrl.href;
|
|
2360
|
+
if (resourceUrl.protocol != "acct:" && preferredUsername != null) {
|
|
2361
|
+
aliases.push(`acct:${preferredUsername}@${host ?? contextHost}`);
|
|
2362
|
+
if (host != null && host !== contextHost) aliases.push(`acct:${preferredUsername}@${contextHost}`);
|
|
2363
|
+
}
|
|
2364
|
+
if (resourceUrl.href !== actorUri.href) aliases.push(actorUri.href);
|
|
2365
|
+
if (resourceUrl.protocol === "acct:" && host != null && host !== contextHost && !resourceUrl.href.endsWith(`@${host}`)) {
|
|
2366
|
+
subject = `acct:${preferredUsername ?? acctUsername}@${host}`;
|
|
2367
|
+
aliases.push(resourceUrl.href);
|
|
2368
|
+
if (preferredUsername != null && preferredUsername !== "" && preferredUsername !== acctUsername) aliases.push(`acct:${preferredUsername}@${contextHost}`);
|
|
2369
|
+
}
|
|
2370
|
+
return {
|
|
2371
|
+
subject,
|
|
2372
|
+
aliases
|
|
2373
|
+
};
|
|
2374
|
+
}
|
|
2357
2375
|
/**
|
|
2358
2376
|
* Handles a WebFinger request. You would not typically call this function
|
|
2359
2377
|
* directly, but instead use {@link Federation.fetch} method.
|
|
@@ -2408,6 +2426,7 @@ async function handleWebFingerInternal(request, { context, host, actorDispatcher
|
|
|
2408
2426
|
return identifier;
|
|
2409
2427
|
}
|
|
2410
2428
|
let identifier = null;
|
|
2429
|
+
let acctUsername = null;
|
|
2411
2430
|
const uriParsed = context.parseUri(resourceUrl);
|
|
2412
2431
|
if (uriParsed?.type != "actor") {
|
|
2413
2432
|
const match = /^acct:([^@]+)@([^@]+)$/.exec(resource);
|
|
@@ -2421,8 +2440,9 @@ async function handleWebFingerInternal(request, { context, host, actorDispatcher
|
|
|
2421
2440
|
const normalizedHost = portMatch == null ? domainToASCII(match[2].toLowerCase()) : domainToASCII(match[2].substring(0, portMatch.index).toLowerCase()) + portMatch[0];
|
|
2422
2441
|
if (normalizedHost != context.url.host && normalizedHost != host) return await onNotFound(request);
|
|
2423
2442
|
else {
|
|
2424
|
-
|
|
2425
|
-
|
|
2443
|
+
acctUsername = match[1];
|
|
2444
|
+
identifier = await mapUsernameToIdentifier(acctUsername);
|
|
2445
|
+
resourceUrl = new URL(`acct:${acctUsername}@${normalizedHost}`);
|
|
2426
2446
|
}
|
|
2427
2447
|
}
|
|
2428
2448
|
} else identifier = uriParsed.identifier;
|
|
@@ -2432,9 +2452,10 @@ async function handleWebFingerInternal(request, { context, host, actorDispatcher
|
|
|
2432
2452
|
logger.error("Actor {identifier} not found.", { identifier });
|
|
2433
2453
|
return await onNotFound(request);
|
|
2434
2454
|
}
|
|
2455
|
+
const actorUri = context.getActorUri(identifier);
|
|
2435
2456
|
const links = [{
|
|
2436
2457
|
rel: "self",
|
|
2437
|
-
href:
|
|
2458
|
+
href: actorUri.href,
|
|
2438
2459
|
type: "application/activity+json"
|
|
2439
2460
|
}];
|
|
2440
2461
|
for (const url of actor.urls) if (url instanceof Link && url.href != null) links.push({
|
|
@@ -2458,22 +2479,19 @@ async function handleWebFingerInternal(request, { context, host, actorDispatcher
|
|
|
2458
2479
|
const customLinks = await webFingerLinksDispatcher(context, resourceUrl);
|
|
2459
2480
|
if (customLinks != null) for (const link of customLinks) links.push(link);
|
|
2460
2481
|
}
|
|
2461
|
-
const aliases =
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
const jrd = {
|
|
2472
|
-
subject: resourceUrl.href,
|
|
2482
|
+
const { subject, aliases } = getWebFingerSubjectAndAliases({
|
|
2483
|
+
resourceUrl,
|
|
2484
|
+
actorUri,
|
|
2485
|
+
preferredUsername: actor.preferredUsername,
|
|
2486
|
+
acctUsername,
|
|
2487
|
+
host,
|
|
2488
|
+
contextHost: context.url.host
|
|
2489
|
+
});
|
|
2490
|
+
return new Response(JSON.stringify({
|
|
2491
|
+
subject,
|
|
2473
2492
|
aliases,
|
|
2474
2493
|
links
|
|
2475
|
-
}
|
|
2476
|
-
return new Response(JSON.stringify(jrd), { headers: {
|
|
2494
|
+
}), { headers: {
|
|
2477
2495
|
"Content-Type": "application/jrd+json",
|
|
2478
2496
|
"Access-Control-Allow-Origin": "*"
|
|
2479
2497
|
} });
|
|
@@ -2,24 +2,24 @@ import { Temporal } from "@js-temporal/polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { n as RouterError } from "./router-CrMLXoOr.mjs";
|
|
5
|
-
import { n as version, t as name } from "./deno-
|
|
6
|
-
import { a as validateCryptoKey, i as importJwk, t as exportJwk } from "./key-
|
|
7
|
-
import { l as verifyRequest } from "./http-
|
|
8
|
-
import { t as getAuthenticatedDocumentLoader } from "./docloader-
|
|
5
|
+
import { n as version, t as name } from "./deno-661NE5Kk.mjs";
|
|
6
|
+
import { a as validateCryptoKey, i as importJwk, t as exportJwk } from "./key-C0qmhoN-.mjs";
|
|
7
|
+
import { l as verifyRequest } from "./http-BQL35dN0.mjs";
|
|
8
|
+
import { t as getAuthenticatedDocumentLoader } from "./docloader-Doj2y_GK.mjs";
|
|
9
9
|
import { n as kvCache } from "./kv-cache-DqEKe5E0.mjs";
|
|
10
|
-
import { a as compactJsonLd, c as getNormalizationContextLoader, d as isInvalidUrlTypeError, f as signJsonLd, g as wrapContextLoaderForJsonLd, l as hasSignature, p as verifyCompactJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as isClearlyMalformedContextReference } from "./ld-
|
|
11
|
-
import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-
|
|
12
|
-
import { n as signObject, r as verifyObject } from "./proof-
|
|
13
|
-
import { t as getNodeInfo } from "./client-
|
|
10
|
+
import { a as compactJsonLd, c as getNormalizationContextLoader, d as isInvalidUrlTypeError, f as signJsonLd, g as wrapContextLoaderForJsonLd, l as hasSignature, p as verifyCompactJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as isClearlyMalformedContextReference } from "./ld-B2MKYZcj.mjs";
|
|
11
|
+
import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-BUbV-zsu.mjs";
|
|
12
|
+
import { n as signObject, r as verifyObject } from "./proof-pGWMVV0R.mjs";
|
|
13
|
+
import { t as getNodeInfo } from "./client-HLLGHiTU.mjs";
|
|
14
14
|
import { t as nodeInfoToJson } from "./types-C37hquWI.mjs";
|
|
15
|
-
import { n as routeActivity } from "./inbox-
|
|
16
|
-
import { t as FederationBuilderImpl } from "./builder-
|
|
15
|
+
import { n as routeActivity } from "./inbox-Bqoa4PJZ.mjs";
|
|
16
|
+
import { t as FederationBuilderImpl } from "./builder-BO_JMtJs.mjs";
|
|
17
17
|
import { t as buildCollectionSynchronizationHeader } from "./collection-ChgDTHLz.mjs";
|
|
18
18
|
import { t as KvKeyCache } from "./keycache-DaQ3ndaJ.mjs";
|
|
19
19
|
import { t as acceptsJsonLd } from "./negotiation-BehA2uul.mjs";
|
|
20
|
-
import { t as hasMalformedKnownTemporalLiteral } from "./temporal-
|
|
20
|
+
import { t as hasMalformedKnownTemporalLiteral } from "./temporal-BUr1JyFa.mjs";
|
|
21
21
|
import { t as createExponentialBackoffPolicy } from "./retry-B_E3V_Dx.mjs";
|
|
22
|
-
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-
|
|
22
|
+
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-DrKWpXWF.mjs";
|
|
23
23
|
import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
|
|
24
24
|
import { lookupWebFinger } from "@fedify/webfinger";
|
|
25
25
|
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
@@ -1202,6 +1202,24 @@ const logger = getLogger([
|
|
|
1202
1202
|
"webfinger",
|
|
1203
1203
|
"server"
|
|
1204
1204
|
]);
|
|
1205
|
+
function getWebFingerSubjectAndAliases({ resourceUrl, actorUri, preferredUsername, acctUsername, host, contextHost }) {
|
|
1206
|
+
const aliases = [];
|
|
1207
|
+
let subject = resourceUrl.href;
|
|
1208
|
+
if (resourceUrl.protocol != "acct:" && preferredUsername != null) {
|
|
1209
|
+
aliases.push(`acct:${preferredUsername}@${host ?? contextHost}`);
|
|
1210
|
+
if (host != null && host !== contextHost) aliases.push(`acct:${preferredUsername}@${contextHost}`);
|
|
1211
|
+
}
|
|
1212
|
+
if (resourceUrl.href !== actorUri.href) aliases.push(actorUri.href);
|
|
1213
|
+
if (resourceUrl.protocol === "acct:" && host != null && host !== contextHost && !resourceUrl.href.endsWith(`@${host}`)) {
|
|
1214
|
+
subject = `acct:${preferredUsername ?? acctUsername}@${host}`;
|
|
1215
|
+
aliases.push(resourceUrl.href);
|
|
1216
|
+
if (preferredUsername != null && preferredUsername !== "" && preferredUsername !== acctUsername) aliases.push(`acct:${preferredUsername}@${contextHost}`);
|
|
1217
|
+
}
|
|
1218
|
+
return {
|
|
1219
|
+
subject,
|
|
1220
|
+
aliases
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1205
1223
|
/**
|
|
1206
1224
|
* Handles a WebFinger request. You would not typically call this function
|
|
1207
1225
|
* directly, but instead use {@link Federation.fetch} method.
|
|
@@ -1256,6 +1274,7 @@ async function handleWebFingerInternal(request, { context, host, actorDispatcher
|
|
|
1256
1274
|
return identifier;
|
|
1257
1275
|
}
|
|
1258
1276
|
let identifier = null;
|
|
1277
|
+
let acctUsername = null;
|
|
1259
1278
|
const uriParsed = context.parseUri(resourceUrl);
|
|
1260
1279
|
if (uriParsed?.type != "actor") {
|
|
1261
1280
|
const match = /^acct:([^@]+)@([^@]+)$/.exec(resource);
|
|
@@ -1269,8 +1288,9 @@ async function handleWebFingerInternal(request, { context, host, actorDispatcher
|
|
|
1269
1288
|
const normalizedHost = portMatch == null ? domainToASCII(match[2].toLowerCase()) : domainToASCII(match[2].substring(0, portMatch.index).toLowerCase()) + portMatch[0];
|
|
1270
1289
|
if (normalizedHost != context.url.host && normalizedHost != host) return await onNotFound(request);
|
|
1271
1290
|
else {
|
|
1272
|
-
|
|
1273
|
-
|
|
1291
|
+
acctUsername = match[1];
|
|
1292
|
+
identifier = await mapUsernameToIdentifier(acctUsername);
|
|
1293
|
+
resourceUrl = new URL(`acct:${acctUsername}@${normalizedHost}`);
|
|
1274
1294
|
}
|
|
1275
1295
|
}
|
|
1276
1296
|
} else identifier = uriParsed.identifier;
|
|
@@ -1280,9 +1300,10 @@ async function handleWebFingerInternal(request, { context, host, actorDispatcher
|
|
|
1280
1300
|
logger.error("Actor {identifier} not found.", { identifier });
|
|
1281
1301
|
return await onNotFound(request);
|
|
1282
1302
|
}
|
|
1303
|
+
const actorUri = context.getActorUri(identifier);
|
|
1283
1304
|
const links = [{
|
|
1284
1305
|
rel: "self",
|
|
1285
|
-
href:
|
|
1306
|
+
href: actorUri.href,
|
|
1286
1307
|
type: "application/activity+json"
|
|
1287
1308
|
}];
|
|
1288
1309
|
for (const url of actor.urls) if (url instanceof Link && url.href != null) links.push({
|
|
@@ -1306,22 +1327,19 @@ async function handleWebFingerInternal(request, { context, host, actorDispatcher
|
|
|
1306
1327
|
const customLinks = await webFingerLinksDispatcher(context, resourceUrl);
|
|
1307
1328
|
if (customLinks != null) for (const link of customLinks) links.push(link);
|
|
1308
1329
|
}
|
|
1309
|
-
const aliases =
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
const jrd = {
|
|
1320
|
-
subject: resourceUrl.href,
|
|
1330
|
+
const { subject, aliases } = getWebFingerSubjectAndAliases({
|
|
1331
|
+
resourceUrl,
|
|
1332
|
+
actorUri,
|
|
1333
|
+
preferredUsername: actor.preferredUsername,
|
|
1334
|
+
acctUsername,
|
|
1335
|
+
host,
|
|
1336
|
+
contextHost: context.url.host
|
|
1337
|
+
});
|
|
1338
|
+
return new Response(JSON.stringify({
|
|
1339
|
+
subject,
|
|
1321
1340
|
aliases,
|
|
1322
1341
|
links
|
|
1323
|
-
}
|
|
1324
|
-
return new Response(JSON.stringify(jrd), { headers: {
|
|
1342
|
+
}), { headers: {
|
|
1325
1343
|
"Content-Type": "application/jrd+json",
|
|
1326
1344
|
"Access-Control-Allow-Origin": "*"
|
|
1327
1345
|
} });
|
package/dist/mod.cjs
CHANGED
|
@@ -4,11 +4,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
4
4
|
require("./chunk-DDcVe30Y.cjs");
|
|
5
5
|
const require_transformers = require("./transformers-NeAONrAq.cjs");
|
|
6
6
|
require("./compat/mod.cjs");
|
|
7
|
-
const require_http = require("./http-
|
|
8
|
-
const require_middleware = require("./middleware-
|
|
9
|
-
const require_proof = require("./proof-
|
|
10
|
-
const require_types = require("./types-
|
|
11
|
-
const require_kv_cache = require("./kv-cache-
|
|
7
|
+
const require_http = require("./http-DWhQe-I5.cjs");
|
|
8
|
+
const require_middleware = require("./middleware-DJcsKDyA.cjs");
|
|
9
|
+
const require_proof = require("./proof-B8z-9_xo.cjs");
|
|
10
|
+
const require_types = require("./types-m8u9L86X.cjs");
|
|
11
|
+
const require_kv_cache = require("./kv-cache-DY8Q_hte.cjs");
|
|
12
12
|
const require_federation_mod = require("./federation/mod.cjs");
|
|
13
13
|
require("./nodeinfo/mod.cjs");
|
|
14
14
|
require("./runtime/mod.cjs");
|
package/dist/mod.js
CHANGED
|
@@ -3,11 +3,11 @@ import { URLPattern } from "urlpattern-polyfill";
|
|
|
3
3
|
import "./chunk-CRNNMoPX.js";
|
|
4
4
|
import { n as autoIdAssigner, r as getDefaultActivityTransformers, t as actorDehydrator } from "./transformers-BGMIq1cs.js";
|
|
5
5
|
import "./compat/mod.js";
|
|
6
|
-
import { a as fetchKey, i as exportJwk, n as signRequest, o as generateCryptoKeyPair, r as verifyRequest, s as importJwk } from "./http-
|
|
7
|
-
import { a as createExponentialBackoffPolicy, c as buildCollectionSynchronizationHeader, d as Router, f as RouterError, i as SendActivityError, l as digest, o as respondWithObject, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as createFederationBuilder } from "./middleware-
|
|
8
|
-
import { _ as signJsonLd, a as doesActorOwnKey, b as verifySignature, d as createSignature, f as detachSignature, i as verifyProof, l as attachSignature, n as signObject, o as getKeyOwner, r as verifyObject, t as createProof, y as verifyJsonLd } from "./proof-
|
|
9
|
-
import { n as getNodeInfo, r as parseNodeInfo, t as nodeInfoToJson } from "./types-
|
|
10
|
-
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-
|
|
6
|
+
import { a as fetchKey, i as exportJwk, n as signRequest, o as generateCryptoKeyPair, r as verifyRequest, s as importJwk } from "./http-CC2-WkSX.js";
|
|
7
|
+
import { a as createExponentialBackoffPolicy, c as buildCollectionSynchronizationHeader, d as Router, f as RouterError, i as SendActivityError, l as digest, o as respondWithObject, r as handleWebFinger, s as respondWithObjectIfAcceptable, t as createFederation, u as createFederationBuilder } from "./middleware-DMsZ7PRo.js";
|
|
8
|
+
import { _ as signJsonLd, a as doesActorOwnKey, b as verifySignature, d as createSignature, f as detachSignature, i as verifyProof, l as attachSignature, n as signObject, o as getKeyOwner, r as verifyObject, t as createProof, y as verifyJsonLd } from "./proof-CGOJ4Mq3.js";
|
|
9
|
+
import { n as getNodeInfo, r as parseNodeInfo, t as nodeInfoToJson } from "./types-DTONwNqL.js";
|
|
10
|
+
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-C7XaTsof.js";
|
|
11
11
|
import { InProcessMessageQueue, MemoryKvStore, ParallelMessageQueue } from "./federation/mod.js";
|
|
12
12
|
import "./nodeinfo/mod.js";
|
|
13
13
|
import "./runtime/mod.js";
|
|
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
|
|
|
4
4
|
import { t as esm_default } from "../esm-DVILvP5e.mjs";
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
6
6
|
import "../std__assert-Duiq_YC9.mjs";
|
|
7
|
-
import { a as parseProtocol, c as parseUsage, i as parseOutboundService, n as parseInboundService, o as parseServices, r as parseNodeInfo, s as parseSoftware, t as getNodeInfo } from "../client-
|
|
7
|
+
import { a as parseProtocol, c as parseUsage, i as parseOutboundService, n as parseInboundService, o as parseServices, r as parseNodeInfo, s as parseSoftware, t as getNodeInfo } from "../client-HLLGHiTU.mjs";
|
|
8
8
|
import { test } from "@fedify/fixture";
|
|
9
9
|
//#region src/nodeinfo/client.test.ts
|
|
10
10
|
test("getNodeInfo()", async (t) => {
|
|
@@ -62,6 +62,66 @@ test("getNodeInfo()", async (t) => {
|
|
|
62
62
|
});
|
|
63
63
|
esm_default.hardReset();
|
|
64
64
|
});
|
|
65
|
+
test("getNodeInfo() blocks SSRF", async (t) => {
|
|
66
|
+
esm_default.spyGlobal();
|
|
67
|
+
await t.step("link href pointing to a loopback address", async () => {
|
|
68
|
+
esm_default.removeRoutes();
|
|
69
|
+
esm_default.get("https://example.com/.well-known/nodeinfo", { body: { links: [{
|
|
70
|
+
rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
|
|
71
|
+
href: "http://127.0.0.1:8080/internal"
|
|
72
|
+
}] } });
|
|
73
|
+
let internalFetched = false;
|
|
74
|
+
esm_default.get("http://127.0.0.1:8080/internal", () => {
|
|
75
|
+
internalFetched = true;
|
|
76
|
+
return { body: { secret: "INTERNAL_DATA_LEAKED" } };
|
|
77
|
+
});
|
|
78
|
+
assertEquals(await getNodeInfo("https://example.com/", { parse: "none" }), void 0);
|
|
79
|
+
assertEquals(internalFetched, false);
|
|
80
|
+
});
|
|
81
|
+
await t.step("link href using a data: URL", async () => {
|
|
82
|
+
esm_default.removeRoutes();
|
|
83
|
+
esm_default.get("https://example.com/.well-known/nodeinfo", { body: { links: [{
|
|
84
|
+
rel: "http://nodeinfo.diaspora.software/ns/schema/2.0",
|
|
85
|
+
href: "data:application/json,{\"software\":{\"name\":\"x\"}}"
|
|
86
|
+
}] } });
|
|
87
|
+
assertEquals(await getNodeInfo("https://example.com/", { parse: "none" }), void 0);
|
|
88
|
+
});
|
|
89
|
+
await t.step("redirect to a private address", async () => {
|
|
90
|
+
esm_default.removeRoutes();
|
|
91
|
+
esm_default.get("https://example.com/.well-known/nodeinfo", { body: { links: [{
|
|
92
|
+
rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
|
|
93
|
+
href: "https://example.com/nodeinfo/2.1"
|
|
94
|
+
}] } });
|
|
95
|
+
esm_default.get("https://example.com/nodeinfo/2.1", {
|
|
96
|
+
status: 302,
|
|
97
|
+
headers: { Location: "https://127.0.0.1:8080/internal" }
|
|
98
|
+
});
|
|
99
|
+
let internalFetched = false;
|
|
100
|
+
esm_default.get("https://127.0.0.1:8080/internal", () => {
|
|
101
|
+
internalFetched = true;
|
|
102
|
+
return { body: { secret: "INTERNAL_DATA_LEAKED" } };
|
|
103
|
+
});
|
|
104
|
+
assertEquals(await getNodeInfo("https://example.com/", { parse: "none" }), void 0);
|
|
105
|
+
assertEquals(internalFetched, false);
|
|
106
|
+
});
|
|
107
|
+
await t.step("direct fetch of a private address", async () => {
|
|
108
|
+
esm_default.removeRoutes();
|
|
109
|
+
let internalFetched = false;
|
|
110
|
+
esm_default.get("http://127.0.0.1:8080/nodeinfo", () => {
|
|
111
|
+
internalFetched = true;
|
|
112
|
+
return { body: { software: {
|
|
113
|
+
name: "x",
|
|
114
|
+
version: "1.0.0"
|
|
115
|
+
} } };
|
|
116
|
+
});
|
|
117
|
+
assertEquals(await getNodeInfo("http://127.0.0.1:8080/nodeinfo", {
|
|
118
|
+
direct: true,
|
|
119
|
+
parse: "none"
|
|
120
|
+
}), void 0);
|
|
121
|
+
assertEquals(internalFetched, false);
|
|
122
|
+
});
|
|
123
|
+
esm_default.hardReset();
|
|
124
|
+
});
|
|
65
125
|
test("parseNodeInfo()", () => {
|
|
66
126
|
const input = {
|
|
67
127
|
software: {
|
|
@@ -5,7 +5,7 @@ import { n as createRequestContext } from "../context-Juj6bdHC.mjs";
|
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
6
6
|
import "../std__assert-Duiq_YC9.mjs";
|
|
7
7
|
import { t as MemoryKvStore } from "../kv-BrZHNugx.mjs";
|
|
8
|
-
import { a as createFederation, h as handleNodeInfoJrd, m as handleNodeInfo } from "../middleware-
|
|
8
|
+
import { a as createFederation, h as handleNodeInfoJrd, m as handleNodeInfo } from "../middleware-DVqurycM.mjs";
|
|
9
9
|
import { test } from "@fedify/fixture";
|
|
10
10
|
//#region src/nodeinfo/handler.test.ts
|
|
11
11
|
test("handleNodeInfo()", async () => {
|
package/dist/nodeinfo/mod.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { Temporal } = require("@js-temporal/polyfill");
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
|
-
const require_types = require("../types-
|
|
4
|
+
const require_types = require("../types-m8u9L86X.cjs");
|
|
5
5
|
exports.getNodeInfo = require_types.getNodeInfo;
|
|
6
6
|
exports.nodeInfoToJson = require_types.nodeInfoToJson;
|
|
7
7
|
exports.parseNodeInfo = require_types.parseNodeInfo;
|
package/dist/nodeinfo/mod.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { n as getNodeInfo, r as parseNodeInfo, t as nodeInfoToJson } from "../types-
|
|
3
|
+
import { n as getNodeInfo, r as parseNodeInfo, t as nodeInfoToJson } from "../types-DTONwNqL.js";
|
|
4
4
|
export { getNodeInfo, nodeInfoToJson, parseNodeInfo };
|
|
@@ -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 "./key-
|
|
4
|
+
import { n as version, t as name } from "./deno-661NE5Kk.mjs";
|
|
5
|
+
import "./key-C0qmhoN-.mjs";
|
|
6
6
|
import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
|
|
7
7
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
8
8
|
import { getDocumentLoader } from "@fedify/vocab-runtime";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { Temporal } = require("@js-temporal/polyfill");
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
3
|
const require_chunk = require("./chunk-DDcVe30Y.cjs");
|
|
4
|
-
const require_http = require("./http-
|
|
4
|
+
const require_http = require("./http-DWhQe-I5.cjs");
|
|
5
5
|
let _logtape_logtape = require("@logtape/logtape");
|
|
6
6
|
let _fedify_vocab = require("@fedify/vocab");
|
|
7
7
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { a as fetchKey, c as validateCryptoKey, l as name, u as version } from "./http-
|
|
3
|
+
import { a as fetchKey, c as validateCryptoKey, l as name, u as version } from "./http-CC2-WkSX.js";
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
5
|
import { Activity, CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1, getTypeId, isActor } from "@fedify/vocab";
|
|
6
6
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -1,8 +1,8 @@
|
|
|
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 { a as validateCryptoKey, n as fetchKey } from "./key-
|
|
4
|
+
import { n as version, t as name } from "./deno-661NE5Kk.mjs";
|
|
5
|
+
import { a as validateCryptoKey, n as fetchKey } from "./key-C0qmhoN-.mjs";
|
|
6
6
|
import { Activity, DataIntegrityProof, Multikey, getTypeId } from "@fedify/vocab";
|
|
7
7
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
8
8
|
import { getLogger } from "@logtape/logtape";
|
|
@@ -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 { n as doubleKnock } from "./http-
|
|
4
|
+
import { n as version, t as name } from "./deno-661NE5Kk.mjs";
|
|
5
|
+
import { n as doubleKnock } from "./http-BQL35dN0.mjs";
|
|
6
6
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
7
7
|
import { getLogger } from "@logtape/logtape";
|
|
8
8
|
//#region src/federation/send.ts
|
package/dist/sig/http.test.mjs
CHANGED
|
@@ -7,8 +7,8 @@ import { a as assertExists, t as assertStringIncludes } from "../std__assert-Dui
|
|
|
7
7
|
import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
|
|
8
8
|
import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
|
|
9
9
|
import { t as assert } from "../assert-ddO5KLpe.mjs";
|
|
10
|
-
import { t as exportJwk } from "../key-
|
|
11
|
-
import { a as parseRfc9421Signature, c as timingSafeEqual, i as formatRfc9421SignatureParameters, l as verifyRequest, n as doubleKnock, o as parseRfc9421SignatureInput, r as formatRfc9421Signature, s as signRequest, t as createRfc9421SignatureBase } from "../http-
|
|
10
|
+
import { t as exportJwk } from "../key-C0qmhoN-.mjs";
|
|
11
|
+
import { a as parseRfc9421Signature, c as timingSafeEqual, i as formatRfc9421SignatureParameters, l as verifyRequest, n as doubleKnock, o as parseRfc9421SignatureInput, r as formatRfc9421Signature, s as signRequest, t as createRfc9421SignatureBase } from "../http-BQL35dN0.mjs";
|
|
12
12
|
import { i as rsaPrivateKey2, l as rsaPublicKey5, o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-CtZLJq76.mjs";
|
|
13
13
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
14
14
|
import { FetchError, exportSpki } from "@fedify/vocab-runtime";
|
package/dist/sig/key.test.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
|
5
5
|
import "../std__assert-Duiq_YC9.mjs";
|
|
6
6
|
import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
|
|
7
7
|
import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
|
|
8
|
-
import { a as validateCryptoKey, i as importJwk, n as fetchKey, r as generateCryptoKeyPair, t as exportJwk } from "../key-
|
|
8
|
+
import { a as validateCryptoKey, i as importJwk, n as fetchKey, r as generateCryptoKeyPair, t as exportJwk } from "../key-C0qmhoN-.mjs";
|
|
9
9
|
import { c as rsaPublicKey3, i as rsaPrivateKey2, o as rsaPublicKey1, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
|
|
10
10
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
11
11
|
import { CryptographicKey, Multikey } from "@fedify/vocab";
|
package/dist/sig/ld.test.mjs
CHANGED
|
@@ -5,9 +5,9 @@ import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
|
5
5
|
import { n as assertFalse, t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
|
|
6
6
|
import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
|
|
7
7
|
import { t as assert } from "../assert-ddO5KLpe.mjs";
|
|
8
|
-
import { r as generateCryptoKeyPair } from "../key-
|
|
8
|
+
import { r as generateCryptoKeyPair } from "../key-C0qmhoN-.mjs";
|
|
9
9
|
import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
|
|
10
|
-
import { a as compactJsonLd, d as isInvalidUrlTypeError, f as signJsonLd, h as verifySignature, i as attachSignature, m as verifyJsonLd, n as UnsafeJsonLdError, o as createSignature, s as detachSignature } from "../ld-
|
|
10
|
+
import { a as compactJsonLd, d as isInvalidUrlTypeError, f as signJsonLd, h as verifySignature, i as attachSignature, m as verifyJsonLd, n as UnsafeJsonLdError, o as createSignature, s as detachSignature } from "../ld-B2MKYZcj.mjs";
|
|
11
11
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
12
12
|
import { CryptographicKey } from "@fedify/vocab";
|
|
13
13
|
import { encodeBase64 } from "byte-encodings/base64";
|
package/dist/sig/mod.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const { Temporal } = require("@js-temporal/polyfill");
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
|
-
const require_http = require("../http-
|
|
5
|
-
const require_proof = require("../proof-
|
|
4
|
+
const require_http = require("../http-DWhQe-I5.cjs");
|
|
5
|
+
const require_proof = require("../proof-B8z-9_xo.cjs");
|
|
6
6
|
exports.attachSignature = require_proof.attachSignature;
|
|
7
7
|
exports.createProof = require_proof.createProof;
|
|
8
8
|
exports.createSignature = require_proof.createSignature;
|
package/dist/sig/mod.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { a as fetchKey, i as exportJwk, n as signRequest, o as generateCryptoKeyPair, r as verifyRequest, s as importJwk } from "../http-
|
|
4
|
-
import { _ as signJsonLd, a as doesActorOwnKey, b as verifySignature, d as createSignature, f as detachSignature, i as verifyProof, l as attachSignature, n as signObject, o as getKeyOwner, r as verifyObject, t as createProof, y as verifyJsonLd } from "../proof-
|
|
3
|
+
import { a as fetchKey, i as exportJwk, n as signRequest, o as generateCryptoKeyPair, r as verifyRequest, s as importJwk } from "../http-CC2-WkSX.js";
|
|
4
|
+
import { _ as signJsonLd, a as doesActorOwnKey, b as verifySignature, d as createSignature, f as detachSignature, i as verifyProof, l as attachSignature, n as signObject, o as getKeyOwner, r as verifyObject, t as createProof, y as verifyJsonLd } from "../proof-CGOJ4Mq3.js";
|
|
5
5
|
export { attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, generateCryptoKeyPair, getKeyOwner, importJwk, signJsonLd, signObject, signRequest, verifyJsonLd, verifyObject, verifyProof, verifyRequest, verifySignature };
|
package/dist/sig/owner.test.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import "../std__assert-Duiq_YC9.mjs";
|
|
|
6
6
|
import { n as assertFalse } from "../assert_rejects-B-qJtC9Z.mjs";
|
|
7
7
|
import { t as assert } from "../assert-ddO5KLpe.mjs";
|
|
8
8
|
import { o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-CtZLJq76.mjs";
|
|
9
|
-
import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-
|
|
9
|
+
import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-BUbV-zsu.mjs";
|
|
10
10
|
import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
11
11
|
import { Create, CryptographicKey, lookupObject } from "@fedify/vocab";
|
|
12
12
|
//#region src/sig/owner.test.ts
|
package/dist/sig/proof.test.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import "../std__assert-Duiq_YC9.mjs";
|
|
|
6
6
|
import { t as assertRejects } from "../assert_rejects-B-qJtC9Z.mjs";
|
|
7
7
|
import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
|
|
8
8
|
import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-CtZLJq76.mjs";
|
|
9
|
-
import { i as verifyProof, n as signObject, r as verifyObject, t as createProof } from "../proof-
|
|
9
|
+
import { i as verifyProof, n as signObject, r as verifyObject, t as createProof } from "../proof-pGWMVV0R.mjs";
|
|
10
10
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
11
11
|
import { Create, DataIntegrityProof, Multikey, Note, Place } from "@fedify/vocab";
|
|
12
12
|
import { decodeMultibase, importMultibaseKey } from "@fedify/vocab-runtime";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { c as getNormalizationContextLoader } from "./ld-
|
|
4
|
+
import { c as getNormalizationContextLoader } from "./ld-B2MKYZcj.mjs";
|
|
5
5
|
import jsonld from "@fedify/vocab-runtime/jsonld";
|
|
6
6
|
//#region src/federation/temporal.ts
|
|
7
7
|
function isPlainObject(value) {
|
|
@@ -1,22 +1,79 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
import { getLogger } from "@logtape/logtape";
|
|
4
|
-
import { getUserAgent } from "@fedify/vocab-runtime";
|
|
4
|
+
import { UrlError, getUserAgent, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
5
5
|
//#region src/nodeinfo/client.ts
|
|
6
6
|
const logger = getLogger([
|
|
7
7
|
"fedify",
|
|
8
8
|
"nodeinfo",
|
|
9
9
|
"client"
|
|
10
10
|
]);
|
|
11
|
+
const DEFAULT_MAX_REDIRECTION = 5;
|
|
12
|
+
/**
|
|
13
|
+
* Fetches a URL while guarding against SSRF. Before every request—including
|
|
14
|
+
* each redirect hop—the destination is validated with
|
|
15
|
+
* {@link validatePublicUrl}, so that loopback, link-local, and private
|
|
16
|
+
* addresses, as well as non-HTTP(S) schemes such as `data:`, are rejected.
|
|
17
|
+
* Redirects are followed manually with a cap, so that a public URL cannot
|
|
18
|
+
* bounce the request to an internal address.
|
|
19
|
+
* @param url The URL to fetch.
|
|
20
|
+
* @param headers The request headers.
|
|
21
|
+
* @returns The final response, or `null` if the URL is disallowed or there
|
|
22
|
+
* are too many redirects.
|
|
23
|
+
*/
|
|
24
|
+
async function fetchPublicUrl(url, headers) {
|
|
25
|
+
let current = url instanceof URL ? url : new URL(url);
|
|
26
|
+
let redirected = 0;
|
|
27
|
+
while (true) {
|
|
28
|
+
try {
|
|
29
|
+
await validatePublicUrl(current.href);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
if (e instanceof UrlError) {
|
|
32
|
+
logger.error("Refused to fetch a private or invalid URL {url}: {error}", {
|
|
33
|
+
url: current.href,
|
|
34
|
+
error: e
|
|
35
|
+
});
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
throw e;
|
|
39
|
+
}
|
|
40
|
+
const response = await fetch(current, {
|
|
41
|
+
headers,
|
|
42
|
+
redirect: "manual"
|
|
43
|
+
});
|
|
44
|
+
if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
|
|
45
|
+
redirected++;
|
|
46
|
+
if (redirected >= DEFAULT_MAX_REDIRECTION) {
|
|
47
|
+
logger.error("Too many redirections ({redirections}) while fetching {url}.", {
|
|
48
|
+
redirections: redirected,
|
|
49
|
+
url: current.href
|
|
50
|
+
});
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const next = new URL(response.headers.get("Location"), response.url == null || response.url === "" ? current : response.url);
|
|
54
|
+
if (next.protocol !== current.protocol) {
|
|
55
|
+
logger.error("Refused a redirect to a different protocol ({protocol} to {redirectedProtocol}) while fetching NodeInfo.", {
|
|
56
|
+
protocol: current.protocol,
|
|
57
|
+
redirectedProtocol: next.protocol
|
|
58
|
+
});
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
current = next;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
return response;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
11
67
|
async function getNodeInfo(url, options = {}) {
|
|
12
68
|
try {
|
|
13
69
|
let nodeInfoUrl = url;
|
|
14
70
|
if (!options.direct) {
|
|
15
71
|
const wellKnownUrl = new URL("/.well-known/nodeinfo", url);
|
|
16
|
-
const wellKnownResponse = await
|
|
72
|
+
const wellKnownResponse = await fetchPublicUrl(wellKnownUrl, {
|
|
17
73
|
Accept: "application/json",
|
|
18
74
|
"User-Agent": typeof options.userAgent === "string" ? options.userAgent : getUserAgent(options.userAgent)
|
|
19
|
-
}
|
|
75
|
+
});
|
|
76
|
+
if (wellKnownResponse == null) return void 0;
|
|
20
77
|
if (!wellKnownResponse.ok) {
|
|
21
78
|
logger.error("Failed to fetch {url}: {status} {statusText}", {
|
|
22
79
|
url: wellKnownUrl.href,
|
|
@@ -36,10 +93,11 @@ async function getNodeInfo(url, options = {}) {
|
|
|
36
93
|
}
|
|
37
94
|
nodeInfoUrl = link.href;
|
|
38
95
|
}
|
|
39
|
-
const response = await
|
|
96
|
+
const response = await fetchPublicUrl(nodeInfoUrl, {
|
|
40
97
|
Accept: "application/json",
|
|
41
98
|
"User-Agent": typeof options.userAgent === "string" ? options.userAgent : getUserAgent(options.userAgent)
|
|
42
|
-
}
|
|
99
|
+
});
|
|
100
|
+
if (response == null) return void 0;
|
|
43
101
|
if (!response.ok) {
|
|
44
102
|
logger.error("Failed to fetch NodeInfo document from {url}: {status} {statusText}", {
|
|
45
103
|
url: nodeInfoUrl.toString(),
|