@fedify/fedify 2.4.5-dev.2462 → 2.4.6-dev.2628
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/README.md +3 -0
- package/dist/{builder-BBUGd9wr.mjs → builder-kj5boG2l.mjs} +2 -2
- package/dist/{client-D-XP_Ccb.d.cts → client-3InDZbba.d.cts} +0 -1
- package/dist/{client-D-XP_Ccb.d.ts → client-3InDZbba.d.ts} +0 -1
- package/dist/{client-CEnNz8O7.mjs → client-5SIFzW3q.mjs} +113 -64
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{compound-proof-CariICma.mjs → compound-proof-BoNAYSHt.mjs} +2 -2
- package/dist/{context-7NyiqIcg.d.ts → context-CVOOd9pD.d.ts} +28 -2
- package/dist/{context-tsYPJ2Ew.d.cts → context-D0gFIgev.d.cts} +28 -2
- package/dist/{deno-BO7-a3hz.mjs → deno-ksnVeCA7.mjs} +1 -1
- package/dist/docloader-BhVNi06k.mjs +136 -0
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/compound-fanout.test.mjs +6 -3
- package/dist/federation/handler-compound-proof.test.mjs +3 -3
- package/dist/federation/handler.test.mjs +4 -4
- package/dist/federation/hashlink-media.test.mjs +2 -2
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/inbox-report.test.mjs +5 -5
- package/dist/federation/inbox.test.mjs +1 -1
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +465 -32
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +3 -3
- package/dist/federation/mod.d.ts +3 -3
- package/dist/federation/mod.js +1 -1
- package/dist/federation/outgoing-proof.test.mjs +9 -6
- package/dist/federation/portable-actor.test.mjs +3 -3
- package/dist/federation/portable-chain.test.mjs +3 -3
- package/dist/federation/portable-collection.test.mjs +4 -4
- package/dist/federation/portable-delivery.test.mjs +2 -2
- package/dist/federation/portable-gateway-keys.test.mjs +11 -5
- package/dist/federation/portable-inbox.test.mjs +4 -4
- package/dist/federation/portable-parse-uri.test.mjs +1 -1
- package/dist/federation/portable-route-activity.test.mjs +2 -2
- package/dist/federation/portable.test.mjs +3 -3
- package/dist/federation/send.test.mjs +498 -88
- package/dist/federation/tasks/enqueue.test.mjs +1 -1
- package/dist/federation/tasks/tasks.test.mjs +2 -2
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +1 -1
- package/dist/{federation-Dd9IwOEi.cjs → federation-BtPz9sr3.cjs} +240 -102
- package/dist/{http-D7L2pqLT.mjs → http-BSARoDPh.mjs} +204 -106
- package/dist/{http-DLf8QYD6.cjs → http-CeVcKQMZ.cjs} +179 -110
- package/dist/{http-BVrOR6MG.js → http-rH230xCD.js} +178 -109
- package/dist/{inbox-DtEKOr3W.mjs → inbox-BdZenpZQ.mjs} +2 -2
- package/dist/{key-DYxuyd-s.d.cts → key-CyCcut3h.d.ts} +1 -2
- package/dist/{key-C1nv7_jD.d.ts → key-VEL1QqHF.d.cts} +1 -2
- package/dist/{kv-cache-Dkzuqs8B.cjs → kv-cache-BpGIONmd.cjs} +72 -27
- package/dist/{kv-cache-DoZoRS9p.js → kv-cache-CNfNI_95.js} +73 -28
- package/dist/{kv-cache-m3RIr811.mjs → kv-cache-Cxn7pNMx.mjs} +1 -1
- package/dist/{ld-PJLGA2MJ.mjs → ld-DJZrjNuN.mjs} +2 -2
- package/dist/{metrics-CGR9cI-Y.mjs → metrics-DtxsYIkN.mjs} +1 -1
- package/dist/{middleware-BxhBd7pw.js → middleware-DDvck2q9.js} +241 -103
- package/dist/{middleware-ByanhTvb.mjs → middleware-DblGj642.mjs} +82 -42
- package/dist/{middleware-DPI-Jp9w.mjs → middleware-DyEjt33n.mjs} +1 -1
- package/dist/{mod-DEZXwV6J.d.ts → mod-B1Qt5cQQ.d.ts} +2 -9
- package/dist/{mod-Xj5P4s4d.d.ts → mod-B5COx5Wd.d.ts} +1 -1
- package/dist/{mod-CavhAgLw.d.cts → mod-BTxJG7ZH.d.cts} +1 -1
- package/dist/{mod-CtpF2BU5.d.ts → mod-CpyjFA9s.d.ts} +1 -1
- package/dist/{mod-BojP2Bw3.d.cts → mod-makPMVMg.d.cts} +1 -1
- package/dist/{mod-Dw-nPxQh.d.cts → mod-ss0wBUH1.d.cts} +2 -9
- package/dist/mod.cjs +5 -5
- package/dist/mod.d.cts +6 -6
- package/dist/mod.d.ts +6 -6
- package/dist/mod.js +5 -5
- package/dist/nodeinfo/client.test.mjs +337 -19
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/nodeinfo/mod.cjs +1 -1
- package/dist/nodeinfo/mod.d.cts +1 -1
- package/dist/nodeinfo/mod.d.ts +1 -1
- package/dist/nodeinfo/mod.js +1 -1
- package/dist/otel/exporter.test.mjs +292 -30
- package/dist/otel/mod.cjs +36 -30
- package/dist/otel/mod.d.cts +13 -0
- package/dist/otel/mod.d.ts +13 -0
- package/dist/otel/mod.js +36 -30
- package/dist/{owner-B5c276hH.mjs → owner-2vfqhUJw.mjs} +3 -3
- package/dist/{portable-collection-BMZY9qT-.js → portable-collection-B7AQ_dW7.js} +1 -1
- package/dist/{portable-collection-CR5uwjws.cjs → portable-collection-Cs--KD5A.cjs} +1 -1
- package/dist/{portable-collection-C88tBiy0.mjs → portable-collection-DKJwGO8S.mjs} +2 -2
- package/dist/{portable-key-DxTXUpCK.mjs → portable-key-DXGepvtD.mjs} +1 -1
- package/dist/{proof-DNu-qP0i.mjs → proof-DW0FK6Cp.mjs} +3 -3
- package/dist/{send-CdCifQs4.mjs → send-CqsocpvF.mjs} +174 -76
- 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 +553 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +1 -1
- package/dist/sig/mitra-receive-interop.test.mjs +4 -4
- package/dist/sig/mitra-send-interop.test.mjs +3 -3
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.d.cts +2 -2
- package/dist/sig/mod.d.ts +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/portable-collection.test.mjs +1 -1
- package/dist/sig/portable-interop.test.mjs +3 -3
- package/dist/sig/portable-key.test.mjs +5 -5
- package/dist/sig/proof.test.mjs +4 -4
- package/dist/sig/tootik-request-interop.test.mjs +4 -4
- package/dist/sig/tootik-send-interop.test.mjs +3 -3
- package/dist/sig/verification.test.mjs +3 -3
- package/dist/{temporal-BuMu2bgP.mjs → temporal-Dm2E1-vs.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- package/dist/testing/mod.d.mts +26 -0
- package/dist/{types-_S2_MeLF.js → types-DUjZb4i6.js} +112 -63
- package/dist/{types-poIao40f.cjs → types-hKCCjii0.cjs} +111 -62
- package/dist/utils/docloader.test.mjs +344 -36
- 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/package.json +7 -7
- package/dist/docloader-DQNRDYDb.mjs +0 -91
|
@@ -15,7 +15,7 @@ import serialize from "json-canon";
|
|
|
15
15
|
import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
|
|
16
16
|
//#region deno.json
|
|
17
17
|
var name = "@fedify/fedify";
|
|
18
|
-
var version = "2.4.
|
|
18
|
+
var version = "2.4.6-dev.2628+2a78382f";
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region src/sig/portable-key-id.ts
|
|
21
21
|
const COMPATIBLE_KEY_ID_PATH_PATTERN = /^\/\.well-known\/apgateway\/did(?::|%3A)/i;
|
|
@@ -6434,10 +6434,10 @@ async function createRedirectRequest(request, location, body, validateRedirect)
|
|
|
6434
6434
|
cache: request.cache
|
|
6435
6435
|
});
|
|
6436
6436
|
}
|
|
6437
|
-
async function fetchDoubleKnockRequest(request, signedRequest, signal) {
|
|
6437
|
+
async function fetchDoubleKnockRequest(session, request, signedRequest, signal) {
|
|
6438
6438
|
const maxAttempts = request.method === "GET" || request.method === "HEAD" ? 2 : 1;
|
|
6439
6439
|
for (let attempt = 1;; attempt++) try {
|
|
6440
|
-
return await fetch(signedRequest, {
|
|
6440
|
+
return await session.fetch(signedRequest, {
|
|
6441
6441
|
redirect: "manual",
|
|
6442
6442
|
signal
|
|
6443
6443
|
});
|
|
@@ -6488,125 +6488,194 @@ function getAbortReason(signal) {
|
|
|
6488
6488
|
return signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
6489
6489
|
}
|
|
6490
6490
|
/**
|
|
6491
|
-
* Performs a double-knock request
|
|
6492
|
-
*
|
|
6493
|
-
*
|
|
6491
|
+
* Performs a double-knock request like {@link doubleKnock}, opening a session
|
|
6492
|
+
* for every hop with the given function, and passes the final response to
|
|
6493
|
+
* the given function. The final session is closed after `consume` settles,
|
|
6494
|
+
* so `consume` must read or cancel the response body before it returns.
|
|
6495
|
+
* This is not exported from any entry point.
|
|
6494
6496
|
* @param request The request to send.
|
|
6495
6497
|
* @param identity The identity to use for signing the request.
|
|
6496
6498
|
* @param options The options for double-knock requests.
|
|
6497
|
-
* @
|
|
6498
|
-
*
|
|
6499
|
+
* @param openHop The function to open a session for each hop. The session of
|
|
6500
|
+
* a hop is closed before the next hop is opened.
|
|
6501
|
+
* @param consume The function to consume the final response.
|
|
6502
|
+
* @returns The value returned by `consume`.
|
|
6499
6503
|
*/
|
|
6500
|
-
async function
|
|
6501
|
-
|
|
6504
|
+
async function doubleKnockScoped(request, identity, options, openHop, consume) {
|
|
6505
|
+
const { response, session } = await doubleKnockCore(request, identity, options, openHop);
|
|
6506
|
+
try {
|
|
6507
|
+
return await consume(response);
|
|
6508
|
+
} catch (error) {
|
|
6509
|
+
getLogger([
|
|
6510
|
+
"fedify",
|
|
6511
|
+
"sig",
|
|
6512
|
+
"http"
|
|
6513
|
+
]).debug("Failed to consume the response from {url}; closing the session: {error}", {
|
|
6514
|
+
url: request.url,
|
|
6515
|
+
error
|
|
6516
|
+
});
|
|
6517
|
+
throw error;
|
|
6518
|
+
} finally {
|
|
6519
|
+
await session.close();
|
|
6520
|
+
}
|
|
6521
|
+
}
|
|
6522
|
+
function isRedirectResponse(response) {
|
|
6523
|
+
return response.status >= 300 && response.status < 400 && response.headers.has("Location");
|
|
6502
6524
|
}
|
|
6503
|
-
|
|
6525
|
+
/**
|
|
6526
|
+
* Starts cancelling the body of a response that is not passed to the caller,
|
|
6527
|
+
* without waiting for it to settle. The cancellation of a branch of a tee
|
|
6528
|
+
* (e.g., a body cloned by a fetch mock) settles only after the other branch
|
|
6529
|
+
* is cancelled too, per the Streams standard, so awaiting it could block
|
|
6530
|
+
* forever. Failures are only logged.
|
|
6531
|
+
*/
|
|
6532
|
+
function cancelResponseBody(response, url) {
|
|
6533
|
+
response.body?.cancel().catch((error) => {
|
|
6534
|
+
getLogger([
|
|
6535
|
+
"fedify",
|
|
6536
|
+
"sig",
|
|
6537
|
+
"http"
|
|
6538
|
+
]).debug("Failed to cancel the response body from {url}: {error}", {
|
|
6539
|
+
url,
|
|
6540
|
+
error
|
|
6541
|
+
});
|
|
6542
|
+
});
|
|
6543
|
+
}
|
|
6544
|
+
async function doubleKnockCore(request, identity, options, openHop) {
|
|
6504
6545
|
const { specDeterminer, log, tracerProvider, signal } = options;
|
|
6505
6546
|
signal?.throwIfAborted();
|
|
6506
6547
|
const maximumRedirection = options.maxRedirection ?? DEFAULT_MAX_REDIRECTION;
|
|
6507
|
-
visited
|
|
6508
|
-
const origin = new URL(request.url).origin;
|
|
6509
|
-
const firstTrySpec = specDeterminer == null ? "rfc9421" : await specDeterminer.determineSpec(origin);
|
|
6510
|
-
signal?.throwIfAborted();
|
|
6548
|
+
const visited = /* @__PURE__ */ new Set();
|
|
6511
6549
|
const body = options.body !== void 0 ? options.body : request.method !== "GET" && request.method !== "HEAD" ? await request.clone().arrayBuffer() : null;
|
|
6512
|
-
let
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6550
|
+
let session = await openHop(request.url);
|
|
6551
|
+
try {
|
|
6552
|
+
for (let redirected = 0;; redirected++) {
|
|
6553
|
+
visited.add(request.url);
|
|
6554
|
+
const origin = new URL(request.url).origin;
|
|
6555
|
+
const firstTrySpec = specDeterminer == null ? "rfc9421" : await specDeterminer.determineSpec(origin);
|
|
6556
|
+
signal?.throwIfAborted();
|
|
6557
|
+
let signedRequest = await signRequest(request, identity.privateKey, identity.keyId, {
|
|
6558
|
+
spec: firstTrySpec,
|
|
6559
|
+
tracerProvider,
|
|
6560
|
+
body
|
|
6561
|
+
});
|
|
6562
|
+
signal?.throwIfAborted();
|
|
6563
|
+
log?.(signedRequest);
|
|
6564
|
+
let response = await fetchDoubleKnockRequest(session, request, signedRequest, signal);
|
|
6565
|
+
const firstRedirected = isRedirectResponse(response);
|
|
6566
|
+
if (!firstRedirected && (response.status === 400 || response.status === 401 || response.status > 401)) {
|
|
6567
|
+
const logger = getLogger([
|
|
6568
|
+
"fedify",
|
|
6569
|
+
"sig",
|
|
6570
|
+
"http"
|
|
6571
|
+
]);
|
|
6572
|
+
const acceptSigHeader = response.headers.get("Accept-Signature");
|
|
6573
|
+
if (acceptSigHeader != null) {
|
|
6574
|
+
const entries = validateAcceptSignature(parseAcceptSignature(acceptSigHeader));
|
|
6575
|
+
const localKeyId = identity.keyId.href;
|
|
6576
|
+
const localAlg = "rsa-v1_5-sha256";
|
|
6577
|
+
let fulfilled = false;
|
|
6578
|
+
let challengeRequest;
|
|
6579
|
+
for (const entry of entries) {
|
|
6580
|
+
signal?.throwIfAborted();
|
|
6581
|
+
const rfc9421 = fulfillAcceptSignature(entry, localKeyId, localAlg);
|
|
6582
|
+
if (rfc9421 == null) continue;
|
|
6583
|
+
logger.debug("Received Accept-Signature challenge; accumulating label {label} and components {components}.", {
|
|
6584
|
+
label: rfc9421.label,
|
|
6585
|
+
components: rfc9421.components
|
|
6586
|
+
});
|
|
6587
|
+
try {
|
|
6588
|
+
challengeRequest = await signRequest(challengeRequest ?? request, identity.privateKey, identity.keyId, {
|
|
6589
|
+
spec: "rfc9421",
|
|
6590
|
+
tracerProvider,
|
|
6591
|
+
body,
|
|
6592
|
+
rfc9421
|
|
6593
|
+
});
|
|
6594
|
+
fulfilled = true;
|
|
6595
|
+
} catch (error) {
|
|
6596
|
+
logger.debug("Failed to fulfill Accept-Signature challenge entry {label}: {error}", {
|
|
6597
|
+
label: entry.label,
|
|
6598
|
+
error
|
|
6599
|
+
});
|
|
6600
|
+
}
|
|
6601
|
+
}
|
|
6602
|
+
if (fulfilled && challengeRequest != null) {
|
|
6603
|
+
signal?.throwIfAborted();
|
|
6604
|
+
cancelResponseBody(response, request.url);
|
|
6605
|
+
signedRequest = challengeRequest;
|
|
6606
|
+
log?.(signedRequest);
|
|
6607
|
+
response = await session.fetch(signedRequest, {
|
|
6608
|
+
redirect: "manual",
|
|
6609
|
+
signal
|
|
6610
|
+
});
|
|
6611
|
+
}
|
|
6612
|
+
if (fulfilled && !isRedirectResponse(response)) {
|
|
6613
|
+
if (response.status < 300) {
|
|
6614
|
+
await specDeterminer?.rememberSpec(origin, "rfc9421");
|
|
6615
|
+
return {
|
|
6616
|
+
response,
|
|
6617
|
+
session
|
|
6618
|
+
};
|
|
6619
|
+
}
|
|
6620
|
+
if (response.status !== 400 && response.status !== 401) return {
|
|
6621
|
+
response,
|
|
6622
|
+
session
|
|
6623
|
+
};
|
|
6624
|
+
}
|
|
6625
|
+
}
|
|
6626
|
+
if (!isRedirectResponse(response)) {
|
|
6627
|
+
const spec = firstTrySpec === "draft-cavage-http-signatures-12" ? "rfc9421" : "draft-cavage-http-signatures-12";
|
|
6628
|
+
getLogger([
|
|
6629
|
+
"fedify",
|
|
6630
|
+
"sig",
|
|
6631
|
+
"http"
|
|
6632
|
+
]).debug("Failed to verify with the spec {spec} ({status} {statusText}); retrying with spec {secondSpec}... (double-knocking)", {
|
|
6633
|
+
spec: firstTrySpec,
|
|
6634
|
+
secondSpec: spec,
|
|
6635
|
+
status: response.status,
|
|
6636
|
+
statusText: response.statusText
|
|
6555
6637
|
});
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6638
|
+
cancelResponseBody(response, request.url);
|
|
6639
|
+
signal?.throwIfAborted();
|
|
6640
|
+
signedRequest = await signRequest(request, identity.privateKey, identity.keyId, {
|
|
6641
|
+
spec,
|
|
6642
|
+
tracerProvider,
|
|
6643
|
+
body
|
|
6561
6644
|
});
|
|
6645
|
+
signal?.throwIfAborted();
|
|
6646
|
+
log?.(signedRequest);
|
|
6647
|
+
response = await fetchDoubleKnockRequest(session, request, signedRequest, signal);
|
|
6648
|
+
if (!isRedirectResponse(response) && response.status !== 400 && response.status !== 401) await specDeterminer?.rememberSpec(origin, spec);
|
|
6562
6649
|
}
|
|
6563
|
-
}
|
|
6564
|
-
if (
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
signal
|
|
6571
|
-
});
|
|
6572
|
-
if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) return doubleKnock(await createRedirectRequest(request, response.headers.get("Location"), body, options.validateRedirect), identity, {
|
|
6573
|
-
...options,
|
|
6574
|
-
body
|
|
6575
|
-
});
|
|
6576
|
-
}
|
|
6577
|
-
if (fulfilled && response.status < 300) {
|
|
6578
|
-
await specDeterminer?.rememberSpec(origin, "rfc9421");
|
|
6579
|
-
return response;
|
|
6580
|
-
}
|
|
6581
|
-
if (fulfilled && response.status !== 400 && response.status !== 401) return response;
|
|
6582
|
-
}
|
|
6583
|
-
const spec = firstTrySpec === "draft-cavage-http-signatures-12" ? "rfc9421" : "draft-cavage-http-signatures-12";
|
|
6584
|
-
logger.debug("Failed to verify with the spec {spec} ({status} {statusText}); retrying with spec {secondSpec}... (double-knocking)", {
|
|
6585
|
-
spec: firstTrySpec,
|
|
6586
|
-
secondSpec: spec,
|
|
6587
|
-
status: response.status,
|
|
6588
|
-
statusText: response.statusText
|
|
6589
|
-
});
|
|
6590
|
-
signal?.throwIfAborted();
|
|
6591
|
-
signedRequest = await signRequest(request, identity.privateKey, identity.keyId, {
|
|
6592
|
-
spec,
|
|
6593
|
-
tracerProvider,
|
|
6594
|
-
body
|
|
6595
|
-
});
|
|
6596
|
-
signal?.throwIfAborted();
|
|
6597
|
-
log?.(signedRequest);
|
|
6598
|
-
response = await fetchDoubleKnockRequest(request, signedRequest, signal);
|
|
6599
|
-
if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
|
|
6650
|
+
} else if (!firstRedirected) await specDeterminer?.rememberSpec(origin, firstTrySpec);
|
|
6651
|
+
if (!isRedirectResponse(response)) return {
|
|
6652
|
+
response,
|
|
6653
|
+
session
|
|
6654
|
+
};
|
|
6655
|
+
cancelResponseBody(response, request.url);
|
|
6656
|
+
await session.close();
|
|
6600
6657
|
if (redirected >= maximumRedirection) throw new FetchError(request.url, `Too many redirections (${redirected + 1})`);
|
|
6601
|
-
const
|
|
6658
|
+
const location = response.headers.get("Location");
|
|
6659
|
+
const redirectRequest = await createRedirectRequest(request, location, body, options.validateRedirect);
|
|
6602
6660
|
if (visited.has(redirectRequest.url)) throw new FetchError(request.url, `Redirect loop detected: ${redirectRequest.url}`);
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6661
|
+
request = redirectRequest;
|
|
6662
|
+
session = await openHop(request.url);
|
|
6663
|
+
}
|
|
6664
|
+
} catch (error) {
|
|
6665
|
+
try {
|
|
6666
|
+
await session.close();
|
|
6667
|
+
} catch (closeError) {
|
|
6668
|
+
getLogger([
|
|
6669
|
+
"fedify",
|
|
6670
|
+
"sig",
|
|
6671
|
+
"http"
|
|
6672
|
+
]).debug("Failed to close the session for {url}: {error}", {
|
|
6673
|
+
url: request.url,
|
|
6674
|
+
error: closeError
|
|
6675
|
+
});
|
|
6676
|
+
}
|
|
6677
|
+
throw error;
|
|
6678
|
+
}
|
|
6610
6679
|
}
|
|
6611
6680
|
/**
|
|
6612
6681
|
* Performs a timing-safe equality comparison between two `Uint8Array` values.
|
|
@@ -6636,4 +6705,4 @@ function timingSafeEqual(a, b) {
|
|
|
6636
6705
|
return result === 0;
|
|
6637
6706
|
}
|
|
6638
6707
|
//#endregion
|
|
6639
|
-
export { instrumentDocumentLoader as $, hasSignature as A, isPortableUri as At, fetchActorDocument as B, InvalidContextReferenceError as C, getGatewayKeyBase as Ct, createSignature as D, isCompatibleKeyId as Dt, compactJsonLd as E, hasPortableActor as Et, verifyCompactJsonLd as F, validateCryptoKey as G, fetchKeyDetailed as H, verifyJsonLd as I, getVerifiedKeyOwnerEvidence as J, verifyKeyOwnership as K, verifySignature as L, isClearlyMalformedContextReference as M, isSamePublicKey as Mt, isInvalidUrlTypeError as N, name as Nt, detachSignature as O, isPortableId as Ot, signJsonLd as P, version as Pt, getRemoteHost as Q, wrapContextLoaderForJsonLd as R, normalizeOutgoingActivityJsonLd as S, getCanonicalPortableId as St, attachSignature as T, getRawCanonicalPortableId as Tt, generateCryptoKeyPair as U, fetchKey as V, importJwk as W, getDurationMs as X, parseKeyOwnerEvidence as Y, getFederationMetrics as Z, verifyObject as _, validateAcceptSignature as _t, signRequest as a, recordCollectionTotalItems as at, verifyPortableObjectProofWithRoot as b, verificationObservation as bt, verifyRequestDetailed as c, recordInboxActivity as ct, InvalidPortableObjectIdError as d, recordWebFingerHandle as dt, isAbortError$1 as et, classifyFep2277CoreType as f, registerQueueDepthGauge as ft, verifyMapLocalProof as g, parseAcceptSignature as gt, signObject as h, fulfillAcceptSignature as ht, selectRequestSignature as i, recordCollectionRequest as it, hasSignatureLike as j, isSameObjectId as jt, getNormalizationContextLoader as k, isPortableKeyId as kt, fetchPortableGatewayKey as l, recordOutboxActivity as lt, hasProofLike as m, formatAcceptSignature as mt, listRequestSignatures as n, recordCollectionDispatchDuration as nt, validateMaxSignatures as o, recordDocumentCache as ot, createProof as p, preloadedOnlyDocumentLoader as pt, MAX_PORTABLE_KEY_TTL as q, parseRfc9421SignatureInput as r, recordCollectionPageItems as rt, verifyRequest as s, recordFanoutRecipients as st,
|
|
6708
|
+
export { instrumentDocumentLoader as $, hasSignature as A, isPortableUri as At, fetchActorDocument as B, InvalidContextReferenceError as C, getGatewayKeyBase as Ct, createSignature as D, isCompatibleKeyId as Dt, compactJsonLd as E, hasPortableActor as Et, verifyCompactJsonLd as F, validateCryptoKey as G, fetchKeyDetailed as H, verifyJsonLd as I, getVerifiedKeyOwnerEvidence as J, verifyKeyOwnership as K, verifySignature as L, isClearlyMalformedContextReference as M, isSamePublicKey as Mt, isInvalidUrlTypeError as N, name as Nt, detachSignature as O, isPortableId as Ot, signJsonLd as P, version as Pt, getRemoteHost as Q, wrapContextLoaderForJsonLd as R, normalizeOutgoingActivityJsonLd as S, getCanonicalPortableId as St, attachSignature as T, getRawCanonicalPortableId as Tt, generateCryptoKeyPair as U, fetchKey as V, importJwk as W, getDurationMs as X, parseKeyOwnerEvidence as Y, getFederationMetrics as Z, verifyObject as _, validateAcceptSignature as _t, signRequest as a, recordCollectionTotalItems as at, verifyPortableObjectProofWithRoot as b, verificationObservation as bt, verifyRequestDetailed as c, recordInboxActivity as ct, InvalidPortableObjectIdError as d, recordWebFingerHandle as dt, isAbortError$1 as et, classifyFep2277CoreType as f, registerQueueDepthGauge as ft, verifyMapLocalProof as g, parseAcceptSignature as gt, signObject as h, fulfillAcceptSignature as ht, selectRequestSignature as i, recordCollectionRequest as it, hasSignatureLike as j, isSameObjectId as jt, getNormalizationContextLoader as k, isPortableKeyId as kt, fetchPortableGatewayKey as l, recordOutboxActivity as lt, hasProofLike as m, formatAcceptSignature as mt, listRequestSignatures as n, recordCollectionDispatchDuration as nt, validateMaxSignatures as o, recordDocumentCache as ot, createProof as p, preloadedOnlyDocumentLoader as pt, MAX_PORTABLE_KEY_TTL as q, parseRfc9421SignatureInput as r, recordCollectionPageItems as rt, verifyRequest as s, recordFanoutRecipients as st, doubleKnockScoped as t, recordCircuitBreakerStateChange as tt, resolvePortableActorKey as u, recordOutboxEnqueue as ut, verifyPortableObjectProof as v, observeAttempt as vt, assertSafeJsonLd as w, getPortableDid as wt, verifyProof as x, getAuthenticationOrigin as xt, verifyPortableObjectProofPolicy as y, snapshotKey as yt, exportJwk as z };
|
|
@@ -2,8 +2,8 @@ import { Temporal } from "temporal-polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as getAuthenticationOrigin } from "./portable-key-id-Ca30-hOa.mjs";
|
|
5
|
-
import { n as version, t as name } from "./deno-
|
|
6
|
-
import { g as recordInboxActivity, n as getDurationMs, r as getFederationMetrics } from "./metrics-
|
|
5
|
+
import { n as version, t as name } from "./deno-ksnVeCA7.mjs";
|
|
6
|
+
import { g as recordInboxActivity, n as getDurationMs, r as getFederationMetrics } from "./metrics-DtxsYIkN.mjs";
|
|
7
7
|
import { getLogger } from "@logtape/logtape";
|
|
8
8
|
import { getTypeId } from "@fedify/vocab";
|
|
9
9
|
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
2
|
import { Actor, CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1 } from "@fedify/vocab";
|
|
3
|
-
import { DocumentLoader, PortableObjectVerifier } from "@fedify/vocab-runtime";
|
|
4
3
|
import { MeterProvider, TracerProvider } from "@opentelemetry/api";
|
|
5
|
-
|
|
4
|
+
import { DocumentLoader, PortableObjectVerifier } from "@fedify/vocab-runtime";
|
|
6
5
|
//#region src/sig/proof.d.ts
|
|
7
6
|
/**
|
|
8
7
|
* Checks if the given JSON-LD document has a DataIntegrityProof-like object,
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
2
|
import { Actor, CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1 } from "@fedify/vocab";
|
|
3
|
-
import { MeterProvider, TracerProvider } from "@opentelemetry/api";
|
|
4
3
|
import { DocumentLoader, PortableObjectVerifier } from "@fedify/vocab-runtime";
|
|
5
|
-
|
|
4
|
+
import { MeterProvider, TracerProvider } from "@opentelemetry/api";
|
|
6
5
|
//#region src/sig/proof.d.ts
|
|
7
6
|
/**
|
|
8
7
|
* Checks if the given JSON-LD document has a DataIntegrityProof-like object,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
|
-
const require_http = require("./http-
|
|
2
|
+
const require_http = require("./http-CeVcKQMZ.cjs");
|
|
3
3
|
let _logtape_logtape = require("@logtape/logtape");
|
|
4
4
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
5
5
|
let es_toolkit = require("es-toolkit");
|
|
6
|
+
let _fedify_vocab_runtime_internal = require("@fedify/vocab-runtime/internal");
|
|
6
7
|
//#region src/utils/docloader.ts
|
|
7
8
|
const logger$1 = (0, _logtape_logtape.getLogger)([
|
|
8
9
|
"fedify",
|
|
@@ -26,13 +27,35 @@ const DEFAULT_MAX_REDIRECTION = 20;
|
|
|
26
27
|
* @throws {RangeError} If the `timeout` option is invalid.
|
|
27
28
|
* @since 0.4.0
|
|
28
29
|
*/
|
|
29
|
-
function getAuthenticatedDocumentLoader(identity,
|
|
30
|
+
function getAuthenticatedDocumentLoader(identity, options = {}) {
|
|
31
|
+
return createAuthenticatedDocumentLoader(identity, options);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The placeholder that the alternate document callback of
|
|
35
|
+
* `getRemoteDocument()` returns, so that the alternate document is loaded
|
|
36
|
+
* after the current hop is closed.
|
|
37
|
+
*/
|
|
38
|
+
const ALTERNATE_PLACEHOLDER = Object.freeze({
|
|
39
|
+
contextUrl: null,
|
|
40
|
+
document: null,
|
|
41
|
+
documentUrl: "about:blank"
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* The implementation of {@link getAuthenticatedDocumentLoader}. This is not
|
|
45
|
+
* exported from any entry point.
|
|
46
|
+
* @param identity The identity to get the document loader for.
|
|
47
|
+
* @param options The options for the document loader.
|
|
48
|
+
* @param deps The dependencies, for tests.
|
|
49
|
+
* @returns The authenticated document loader.
|
|
50
|
+
* @throws {TypeError} If the key is invalid or unsupported.
|
|
51
|
+
*/
|
|
52
|
+
function createAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedirection, userAgent, specDeterminer, timeout, tracerProvider } = {}, deps = {}) {
|
|
30
53
|
require_http.validateCryptoKey(identity.privateKey);
|
|
31
54
|
const resolvedTimeout = (0, _fedify_vocab_runtime.resolveDocumentLoaderTimeout)(timeout);
|
|
32
55
|
async function load(url, options, redirected = 0, visited = /* @__PURE__ */ new Set()) {
|
|
33
56
|
options?.signal?.throwIfAborted();
|
|
34
57
|
let currentUrl = new URL(url).href;
|
|
35
|
-
|
|
58
|
+
validateUrl(currentUrl);
|
|
36
59
|
visited.add(currentUrl);
|
|
37
60
|
const originalRequest = (0, _fedify_vocab_runtime.createActivityPubRequest)(currentUrl, { userAgent });
|
|
38
61
|
function follow(nextUrl) {
|
|
@@ -41,46 +64,68 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedi
|
|
|
41
64
|
if (visited.has(nextUrl)) throw new _fedify_vocab_runtime.FetchError(currentUrl, `Redirect loop detected: ${nextUrl}`);
|
|
42
65
|
redirected++;
|
|
43
66
|
}
|
|
44
|
-
const
|
|
67
|
+
const result = await require_http.doubleKnockScoped(originalRequest, identity, {
|
|
45
68
|
maxRedirection,
|
|
46
69
|
specDeterminer,
|
|
47
70
|
log: (0, es_toolkit.curry)(_fedify_vocab_runtime.logRequest)(logger$1),
|
|
48
71
|
tracerProvider,
|
|
49
72
|
signal: options?.signal,
|
|
50
|
-
validateRedirect:
|
|
73
|
+
validateRedirect: (nextUrl) => {
|
|
51
74
|
follow(nextUrl);
|
|
52
|
-
|
|
75
|
+
validateUrl(nextUrl);
|
|
53
76
|
visited.add(nextUrl);
|
|
54
77
|
currentUrl = nextUrl;
|
|
55
78
|
}
|
|
79
|
+
}, (hopUrl) => openHop(hopUrl, options), async (response) => {
|
|
80
|
+
options?.signal?.throwIfAborted();
|
|
81
|
+
let alternateUrl;
|
|
82
|
+
const document = await (0, _fedify_vocab_runtime.getRemoteDocument)(currentUrl, response, (url) => {
|
|
83
|
+
alternateUrl = url;
|
|
84
|
+
return Promise.resolve(ALTERNATE_PLACEHOLDER);
|
|
85
|
+
}, options);
|
|
86
|
+
if (alternateUrl == null) return { document };
|
|
87
|
+
if (!response.bodyUsed && response.body?.locked !== true) response.body?.cancel().catch((error) => {
|
|
88
|
+
logger$1.debug("Failed to cancel the response body from {url}: {error}", {
|
|
89
|
+
url: currentUrl,
|
|
90
|
+
error
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
return { alternateUrl };
|
|
56
94
|
});
|
|
57
95
|
options?.signal?.throwIfAborted();
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
96
|
+
if ("document" in result) return result.document;
|
|
97
|
+
follow(result.alternateUrl);
|
|
98
|
+
return load(result.alternateUrl, options, redirected, visited);
|
|
99
|
+
}
|
|
100
|
+
function openUnvalidatedHop(url, signal) {
|
|
101
|
+
if (deps.openHop != null) return deps.openHop(url);
|
|
102
|
+
return allowPrivateAddress ? (0, _fedify_vocab_runtime_internal.openDirectFetch)(url) : (0, _fedify_vocab_runtime_internal.openPublicFetch)(url, { signal });
|
|
62
103
|
}
|
|
63
|
-
async function
|
|
104
|
+
async function openHop(url, options) {
|
|
105
|
+
try {
|
|
106
|
+
const session = await openUnvalidatedHop(url, options?.signal);
|
|
107
|
+
if (options?.signal?.aborted) {
|
|
108
|
+
await session.close();
|
|
109
|
+
options.signal.throwIfAborted();
|
|
110
|
+
}
|
|
111
|
+
return session;
|
|
112
|
+
} catch (error) {
|
|
113
|
+
if (error instanceof _fedify_vocab_runtime.UrlError) if (error.reason === "dns") logger$1.debug("DNS lookup failed for {url}", {
|
|
114
|
+
url,
|
|
115
|
+
error
|
|
116
|
+
});
|
|
117
|
+
else logger$1[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
|
|
118
|
+
url,
|
|
119
|
+
error
|
|
120
|
+
});
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function validateUrl(url) {
|
|
64
125
|
const parsedUrl = new URL(url);
|
|
65
126
|
const protocol = parsedUrl.protocol;
|
|
66
127
|
if (protocol !== "http:" && protocol !== "https:") throw new _fedify_vocab_runtime.UrlError(`Unsupported protocol: ${protocol}`);
|
|
67
128
|
if (parsedUrl.username !== "" || parsedUrl.password !== "") throw new _fedify_vocab_runtime.UrlError("URLs with credentials are not allowed");
|
|
68
|
-
if (!allowPrivateAddress) {
|
|
69
|
-
try {
|
|
70
|
-
await (0, _fedify_vocab_runtime.validatePublicUrl)(url);
|
|
71
|
-
} catch (error) {
|
|
72
|
-
if (error instanceof _fedify_vocab_runtime.UrlError) if (error.reason === "dns") logger$1.debug("DNS lookup failed for {url}", {
|
|
73
|
-
url,
|
|
74
|
-
error
|
|
75
|
-
});
|
|
76
|
-
else logger$1[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
|
|
77
|
-
url,
|
|
78
|
-
error
|
|
79
|
-
});
|
|
80
|
-
throw error;
|
|
81
|
-
}
|
|
82
|
-
options?.signal?.throwIfAborted();
|
|
83
|
-
}
|
|
84
129
|
}
|
|
85
130
|
return (0, _fedify_vocab_runtime.withDocumentLoaderTimeout)((url, options) => load(url, options), resolvedTimeout);
|
|
86
131
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { G as validateCryptoKey, ot as recordDocumentCache, t as
|
|
3
|
+
import { G as validateCryptoKey, ot as recordDocumentCache, t as doubleKnockScoped } from "./http-rH230xCD.js";
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
|
-
import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, resolveDocumentLoaderTimeout,
|
|
5
|
+
import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, resolveDocumentLoaderTimeout, withDocumentLoaderTimeout } from "@fedify/vocab-runtime";
|
|
6
6
|
import { curry } from "es-toolkit";
|
|
7
|
+
import { openDirectFetch, openPublicFetch } from "@fedify/vocab-runtime/internal";
|
|
7
8
|
//#region src/utils/docloader.ts
|
|
8
9
|
const logger$1 = getLogger([
|
|
9
10
|
"fedify",
|
|
@@ -27,13 +28,35 @@ const DEFAULT_MAX_REDIRECTION = 20;
|
|
|
27
28
|
* @throws {RangeError} If the `timeout` option is invalid.
|
|
28
29
|
* @since 0.4.0
|
|
29
30
|
*/
|
|
30
|
-
function getAuthenticatedDocumentLoader(identity,
|
|
31
|
+
function getAuthenticatedDocumentLoader(identity, options = {}) {
|
|
32
|
+
return createAuthenticatedDocumentLoader(identity, options);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The placeholder that the alternate document callback of
|
|
36
|
+
* `getRemoteDocument()` returns, so that the alternate document is loaded
|
|
37
|
+
* after the current hop is closed.
|
|
38
|
+
*/
|
|
39
|
+
const ALTERNATE_PLACEHOLDER = Object.freeze({
|
|
40
|
+
contextUrl: null,
|
|
41
|
+
document: null,
|
|
42
|
+
documentUrl: "about:blank"
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* The implementation of {@link getAuthenticatedDocumentLoader}. This is not
|
|
46
|
+
* exported from any entry point.
|
|
47
|
+
* @param identity The identity to get the document loader for.
|
|
48
|
+
* @param options The options for the document loader.
|
|
49
|
+
* @param deps The dependencies, for tests.
|
|
50
|
+
* @returns The authenticated document loader.
|
|
51
|
+
* @throws {TypeError} If the key is invalid or unsupported.
|
|
52
|
+
*/
|
|
53
|
+
function createAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedirection, userAgent, specDeterminer, timeout, tracerProvider } = {}, deps = {}) {
|
|
31
54
|
validateCryptoKey(identity.privateKey);
|
|
32
55
|
const resolvedTimeout = resolveDocumentLoaderTimeout(timeout);
|
|
33
56
|
async function load(url, options, redirected = 0, visited = /* @__PURE__ */ new Set()) {
|
|
34
57
|
options?.signal?.throwIfAborted();
|
|
35
58
|
let currentUrl = new URL(url).href;
|
|
36
|
-
|
|
59
|
+
validateUrl(currentUrl);
|
|
37
60
|
visited.add(currentUrl);
|
|
38
61
|
const originalRequest = createActivityPubRequest(currentUrl, { userAgent });
|
|
39
62
|
function follow(nextUrl) {
|
|
@@ -42,46 +65,68 @@ function getAuthenticatedDocumentLoader(identity, { allowPrivateAddress, maxRedi
|
|
|
42
65
|
if (visited.has(nextUrl)) throw new FetchError(currentUrl, `Redirect loop detected: ${nextUrl}`);
|
|
43
66
|
redirected++;
|
|
44
67
|
}
|
|
45
|
-
const
|
|
68
|
+
const result = await doubleKnockScoped(originalRequest, identity, {
|
|
46
69
|
maxRedirection,
|
|
47
70
|
specDeterminer,
|
|
48
71
|
log: curry(logRequest)(logger$1),
|
|
49
72
|
tracerProvider,
|
|
50
73
|
signal: options?.signal,
|
|
51
|
-
validateRedirect:
|
|
74
|
+
validateRedirect: (nextUrl) => {
|
|
52
75
|
follow(nextUrl);
|
|
53
|
-
|
|
76
|
+
validateUrl(nextUrl);
|
|
54
77
|
visited.add(nextUrl);
|
|
55
78
|
currentUrl = nextUrl;
|
|
56
79
|
}
|
|
80
|
+
}, (hopUrl) => openHop(hopUrl, options), async (response) => {
|
|
81
|
+
options?.signal?.throwIfAborted();
|
|
82
|
+
let alternateUrl;
|
|
83
|
+
const document = await getRemoteDocument(currentUrl, response, (url) => {
|
|
84
|
+
alternateUrl = url;
|
|
85
|
+
return Promise.resolve(ALTERNATE_PLACEHOLDER);
|
|
86
|
+
}, options);
|
|
87
|
+
if (alternateUrl == null) return { document };
|
|
88
|
+
if (!response.bodyUsed && response.body?.locked !== true) response.body?.cancel().catch((error) => {
|
|
89
|
+
logger$1.debug("Failed to cancel the response body from {url}: {error}", {
|
|
90
|
+
url: currentUrl,
|
|
91
|
+
error
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
return { alternateUrl };
|
|
57
95
|
});
|
|
58
96
|
options?.signal?.throwIfAborted();
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
97
|
+
if ("document" in result) return result.document;
|
|
98
|
+
follow(result.alternateUrl);
|
|
99
|
+
return load(result.alternateUrl, options, redirected, visited);
|
|
100
|
+
}
|
|
101
|
+
function openUnvalidatedHop(url, signal) {
|
|
102
|
+
if (deps.openHop != null) return deps.openHop(url);
|
|
103
|
+
return allowPrivateAddress ? openDirectFetch(url) : openPublicFetch(url, { signal });
|
|
104
|
+
}
|
|
105
|
+
async function openHop(url, options) {
|
|
106
|
+
try {
|
|
107
|
+
const session = await openUnvalidatedHop(url, options?.signal);
|
|
108
|
+
if (options?.signal?.aborted) {
|
|
109
|
+
await session.close();
|
|
110
|
+
options.signal.throwIfAborted();
|
|
111
|
+
}
|
|
112
|
+
return session;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
if (error instanceof UrlError) if (error.reason === "dns") logger$1.debug("DNS lookup failed for {url}", {
|
|
115
|
+
url,
|
|
116
|
+
error
|
|
117
|
+
});
|
|
118
|
+
else logger$1[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
|
|
119
|
+
url,
|
|
120
|
+
error
|
|
121
|
+
});
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
63
124
|
}
|
|
64
|
-
|
|
125
|
+
function validateUrl(url) {
|
|
65
126
|
const parsedUrl = new URL(url);
|
|
66
127
|
const protocol = parsedUrl.protocol;
|
|
67
128
|
if (protocol !== "http:" && protocol !== "https:") throw new UrlError(`Unsupported protocol: ${protocol}`);
|
|
68
129
|
if (parsedUrl.username !== "" || parsedUrl.password !== "") throw new UrlError("URLs with credentials are not allowed");
|
|
69
|
-
if (!allowPrivateAddress) {
|
|
70
|
-
try {
|
|
71
|
-
await validatePublicUrl(url);
|
|
72
|
-
} catch (error) {
|
|
73
|
-
if (error instanceof UrlError) if (error.reason === "dns") logger$1.debug("DNS lookup failed for {url}", {
|
|
74
|
-
url,
|
|
75
|
-
error
|
|
76
|
-
});
|
|
77
|
-
else logger$1[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
|
|
78
|
-
url,
|
|
79
|
-
error
|
|
80
|
-
});
|
|
81
|
-
throw error;
|
|
82
|
-
}
|
|
83
|
-
options?.signal?.throwIfAborted();
|
|
84
|
-
}
|
|
85
130
|
}
|
|
86
131
|
return withDocumentLoaderTimeout((url, options) => load(url, options), resolvedTimeout);
|
|
87
132
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { p as recordDocumentCache } from "./metrics-
|
|
4
|
+
import { p as recordDocumentCache } from "./metrics-DtxsYIkN.mjs";
|
|
5
5
|
import { getLogger } from "@logtape/logtape";
|
|
6
6
|
import { preloadedContexts } from "@fedify/vocab-runtime";
|
|
7
7
|
//#region src/utils/kv-cache.ts
|