@fedify/fedify 2.3.9-dev.2048 → 2.3.10
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-BfY2wZ4V.mjs → builder-Bal9bfuM.mjs} +10 -2
- package/dist/{client-DYDoDpMa.mjs → client-Ccbsek6u.mjs} +7 -3
- 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/{context-CAKnQy1x.d.ts → context-BWbdE_MZ.d.ts} +1 -1
- package/dist/{context-BepjCFHN.mjs → context-CxbCIptr.mjs} +2 -1
- package/dist/{context-CSIggG9_.d.cts → context-MOrCC7yl.d.cts} +1 -1
- package/dist/{deno-ayal9buz.mjs → deno-DUgFsCmM.mjs} +1 -1
- package/dist/docloader-w72ipM49.mjs +79 -0
- package/dist/federation/builder.test.mjs +38 -2
- package/dist/federation/circuit-breaker.test.mjs +1 -1
- package/dist/federation/collection.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +7 -7
- package/dist/federation/idempotency.test.mjs +3 -3
- package/dist/federation/kv.test.mjs +1 -1
- package/dist/federation/metrics.test.mjs +2 -2
- package/dist/federation/middleware.test.mjs +302 -8
- 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/mq.test.mjs +98 -43
- package/dist/federation/negotiation.test.mjs +1 -1
- package/dist/federation/router.test.mjs +1 -1
- package/dist/federation/send.test.mjs +85 -4
- package/dist/federation/temporal.test.mjs +2 -2
- package/dist/federation/webfinger.test.mjs +3 -3
- package/dist/{http-B2u6PvNX.mjs → http-BNDHRNJP.mjs} +8 -4
- package/dist/{http-BPPCh0xN.js → http-BY8PpQzP.js} +6 -2
- package/dist/{http-BGP2QCbe.cjs → http-CTYio50W.cjs} +6 -2
- package/dist/{key-C9DkrWwb.mjs → key-BbuFo4CW.mjs} +2 -2
- package/dist/{kv-D6hNiMTK.d.ts → kv-CZKl1IUS.d.cts} +3 -2
- package/dist/{kv-gJ8LYbxX.d.cts → kv-CxaI4eGo.d.ts} +3 -2
- package/dist/{kv-cache-qJSjfLGm.mjs → kv-cache-CNZOaZYq.mjs} +1 -1
- package/dist/{kv-cache-C1TC_e9y.cjs → kv-cache-CrcqGkT-.cjs} +34 -8
- package/dist/{kv-cache-Cl1q1aA9.js → kv-cache-DNnjnc9t.js} +35 -9
- package/dist/{ld-DNl7KwLY.mjs → ld-BYV2Luge.mjs} +4 -4
- package/dist/{metrics-Ce55disp.mjs → metrics-QrVsKSG9.mjs} +1 -1
- package/dist/{middleware-C96wm_7x.mjs → middleware-54KSGAQA.mjs} +1 -1
- package/dist/{middleware-C_utyVa_.js → middleware-B4FNnN3W.js} +36 -11
- package/dist/{middleware-BCG2BX1n.mjs → middleware-Bj9s3J_0.mjs} +22 -19
- package/dist/{middleware-BZojifnF.cjs → middleware-Dv-L7Plm.cjs} +36 -11
- package/dist/{mod-PVR75MeU.d.cts → mod-B6PwkUMU.d.cts} +1 -1
- package/dist/{mod-DHgc4ygG.d.ts → mod-Br8yJNcE.d.ts} +3 -1
- package/dist/{mod-1TuoXkGs.d.cts → mod-Co1M3Ux0.d.cts} +3 -1
- package/dist/{mod-CFuyfw3c.d.ts → mod-LmD03uRA.d.ts} +1 -1
- package/dist/mod.cjs +5 -5
- package/dist/mod.d.cts +4 -4
- package/dist/mod.d.ts +4 -4
- package/dist/mod.js +5 -5
- package/dist/nodeinfo/client.test.mjs +50 -2
- package/dist/nodeinfo/handler.test.mjs +3 -3
- package/dist/nodeinfo/mod.cjs +1 -1
- package/dist/nodeinfo/mod.js +1 -1
- package/dist/nodeinfo/types.test.mjs +1 -1
- package/dist/otel/exporter.test.mjs +1 -1
- package/dist/otel/mod.d.cts +1 -1
- package/dist/otel/mod.d.ts +1 -1
- package/dist/{owner-DqqDBw-l.mjs → owner-BsBzJADO.mjs} +2 -2
- package/dist/{proof-Dz9ObvUq.js → proof-BxS2Xa8B.js} +2 -2
- package/dist/{proof-I6YcKRRq.cjs → proof-CGKQFT2M.cjs} +2 -2
- package/dist/{proof-D5vP7VIN.mjs → proof-cXVkPBIU.mjs} +3 -3
- package/dist/{send-CBtR8DQK.mjs → send-omt23uTA.mjs} +18 -4
- package/dist/sig/http.test.mjs +43 -3
- package/dist/sig/key.test.mjs +2 -2
- package/dist/sig/ld.test.mjs +5 -2
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +2 -2
- package/dist/sig/proof.test.mjs +2 -2
- package/dist/{std__assert-BBjXFNOb.mjs → std__assert-BvGuO4xO.mjs} +2 -27
- package/dist/{temporal-B9t2tY9A.mjs → temporal-ZUAQe754.mjs} +1 -1
- package/dist/testing/mod.mjs +1 -1
- package/dist/{types-DWs-qZaY.cjs → types-DRPjmHVV.cjs} +7 -3
- package/dist/{types-sXITXcWa.js → types-miAYfiGO.js} +7 -3
- package/dist/utils/docloader.test.mjs +299 -3
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.d.cts +1 -1
- package/dist/utils/mod.d.ts +1 -1
- package/dist/utils/mod.js +1 -1
- package/dist/vocab/cjs.test.mjs +1 -1
- package/package.json +7 -7
- package/dist/docloader-C-JrNL14.mjs +0 -53
|
@@ -1,9 +1,9 @@
|
|
|
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 getDurationMs, r as getFederationMetrics } from "./metrics-
|
|
6
|
-
import { n as doubleKnock } from "./http-
|
|
4
|
+
import { n as version, t as name } from "./deno-DUgFsCmM.mjs";
|
|
5
|
+
import { n as getDurationMs, r as getFederationMetrics } from "./metrics-QrVsKSG9.mjs";
|
|
6
|
+
import { n as doubleKnock } from "./http-BNDHRNJP.mjs";
|
|
7
7
|
import { getLogger } from "@logtape/logtape";
|
|
8
8
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
9
9
|
import { FetchError, UrlError, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
@@ -125,6 +125,15 @@ async function sendActivityInternal({ activity, activityId, activityType, keys,
|
|
|
125
125
|
if (!allowPrivateAddress) try {
|
|
126
126
|
await validatePublicUrl(url);
|
|
127
127
|
} catch (error) {
|
|
128
|
+
if (error instanceof UrlError && error.reason === "dns") {
|
|
129
|
+
logger.error("DNS resolution failed for URL: {url}", {
|
|
130
|
+
url,
|
|
131
|
+
error
|
|
132
|
+
});
|
|
133
|
+
const failure = new FetchError(url, error.message);
|
|
134
|
+
failure.cause = error;
|
|
135
|
+
throw failure;
|
|
136
|
+
}
|
|
128
137
|
if (error instanceof UrlError) logger.error("Disallowed private URL: {url}", {
|
|
129
138
|
url,
|
|
130
139
|
error
|
|
@@ -132,7 +141,12 @@ async function sendActivityInternal({ activity, activityId, activityType, keys,
|
|
|
132
141
|
throw error;
|
|
133
142
|
}
|
|
134
143
|
}
|
|
135
|
-
|
|
144
|
+
try {
|
|
145
|
+
await validateUrl(inbox.href);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
if (error instanceof FetchError) federationMetrics.recordDelivery(inbox, getDurationMs(started), false, activityType);
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
136
150
|
headers = new Headers(headers);
|
|
137
151
|
headers.set("Content-Type", "application/activity+json");
|
|
138
152
|
const request = new Request(inbox, {
|
package/dist/sig/http.test.mjs
CHANGED
|
@@ -3,12 +3,12 @@ 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 {
|
|
6
|
+
import { n as assertExists, t as assertStringIncludes } from "../std__assert-BvGuO4xO.mjs";
|
|
7
7
|
import { n as assertGreaterOrEqual, r as assertFalse, t as assertRejects } from "../assert_rejects-DN60FHPX.mjs";
|
|
8
8
|
import { t as assert } from "../assert-jSdZMYam.mjs";
|
|
9
9
|
import { t as assertThrows } from "../assert_throws-BOkhLGYc.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, u as verifyRequestDetailed } from "../http-
|
|
10
|
+
import { t as exportJwk } from "../key-BbuFo4CW.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, u as verifyRequestDetailed } from "../http-BNDHRNJP.mjs";
|
|
12
12
|
import { i as rsaPrivateKey2, l as rsaPublicKey5, o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-BAK-tUlf.mjs";
|
|
13
13
|
import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
14
14
|
import { FetchError, exportSpki } from "@fedify/vocab-runtime";
|
|
@@ -628,6 +628,46 @@ test("verifyRequest() [rfc9421] successful GET verification", async () => {
|
|
|
628
628
|
currentTime: Temporal.Instant.from(`${(/* @__PURE__ */ new Date(currentTimestamp * 1e3)).toISOString()}`)
|
|
629
629
|
}), rsaPublicKey2, "Valid signature should verify to the correct public key");
|
|
630
630
|
});
|
|
631
|
+
for (const failure of [
|
|
632
|
+
"missing key",
|
|
633
|
+
"invalid signature",
|
|
634
|
+
"digest mismatch",
|
|
635
|
+
"empty body",
|
|
636
|
+
"cached key"
|
|
637
|
+
]) test(`verifyRequest() [rfc9421] multiple POST signatures: ${failure}`, async () => {
|
|
638
|
+
const body = failure === "empty body" ? "" : "Hello, world!";
|
|
639
|
+
const currentTime = Temporal.Instant.from("2024-03-05T08:09:44Z");
|
|
640
|
+
const signed = await signRequest(new Request("https://example.com/inbox", {
|
|
641
|
+
method: "POST",
|
|
642
|
+
body
|
|
643
|
+
}), rsaPrivateKey2, new URL("https://example.com/key2"), {
|
|
644
|
+
spec: "rfc9421",
|
|
645
|
+
currentTime
|
|
646
|
+
});
|
|
647
|
+
const input = signed.headers.get("Signature-Input");
|
|
648
|
+
const signature = signed.headers.get("Signature");
|
|
649
|
+
const firstInput = failure === "missing key" ? input.replace("https://example.com/key2", "https://example.com/missing-key") : input;
|
|
650
|
+
signed.headers.set("Signature-Input", `${firstInput}, ${input.replace(/^sig1=/, "sig2=")}`);
|
|
651
|
+
signed.headers.set("Signature", `sig1=:AAAAAA==:, ${signature.replace(/^sig1=/, "sig2=")}`);
|
|
652
|
+
const request = failure === "digest mismatch" ? new Request(signed, { body: "Tampered body" }) : signed;
|
|
653
|
+
const loaded = [];
|
|
654
|
+
assertEquals(await verifyRequest(request, {
|
|
655
|
+
keyCache: failure === "cached key" ? {
|
|
656
|
+
get: () => Promise.resolve(rsaPublicKey1),
|
|
657
|
+
set: async () => {}
|
|
658
|
+
} : void 0,
|
|
659
|
+
spec: "rfc9421",
|
|
660
|
+
currentTime,
|
|
661
|
+
contextLoader: mockDocumentLoader,
|
|
662
|
+
documentLoader: (url, options) => {
|
|
663
|
+
loaded.push(url);
|
|
664
|
+
return mockDocumentLoader(url, options);
|
|
665
|
+
}
|
|
666
|
+
}), failure === "digest mismatch" ? null : rsaPublicKey2);
|
|
667
|
+
assertEquals(loaded, failure === "digest mismatch" ? [] : failure === "missing key" ? ["https://example.com/missing-key", "https://example.com/key2"] : ["https://example.com/key2", "https://example.com/key2"]);
|
|
668
|
+
assertFalse(request.bodyUsed);
|
|
669
|
+
assertEquals(await request.text(), failure === "digest mismatch" ? "Tampered body" : body);
|
|
670
|
+
});
|
|
631
671
|
test("verifyRequest() [rfc9421] manual POST verification", async () => {
|
|
632
672
|
const currentTimestamp = 1709626184;
|
|
633
673
|
const currentTime = Temporal.Instant.from("2024-03-05T08:09:44Z");
|
package/dist/sig/key.test.mjs
CHANGED
|
@@ -2,11 +2,11 @@ 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-
|
|
5
|
+
import "../std__assert-BvGuO4xO.mjs";
|
|
6
6
|
import { t as assertRejects } from "../assert_rejects-DN60FHPX.mjs";
|
|
7
7
|
import { t as assert } from "../assert-jSdZMYam.mjs";
|
|
8
8
|
import { t as assertThrows } from "../assert_throws-BOkhLGYc.mjs";
|
|
9
|
-
import { a as generateCryptoKeyPair, i as fetchKeyDetailed, o as importJwk, r as fetchKey, s as validateCryptoKey, t as exportJwk } from "../key-
|
|
9
|
+
import { a as generateCryptoKeyPair, i as fetchKeyDetailed, o as importJwk, r as fetchKey, s as validateCryptoKey, t as exportJwk } from "../key-BbuFo4CW.mjs";
|
|
10
10
|
import { c as rsaPublicKey3, i as rsaPrivateKey2, o as rsaPublicKey1, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.mjs";
|
|
11
11
|
import { CryptographicKey, Multikey } from "@fedify/vocab";
|
|
12
12
|
import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
package/dist/sig/ld.test.mjs
CHANGED
|
@@ -5,14 +5,17 @@ import { t as assertEquals } from "../assert_equals-C-ZRDbaf.mjs";
|
|
|
5
5
|
import { n as assertGreaterOrEqual, r as assertFalse, t as assertRejects } from "../assert_rejects-DN60FHPX.mjs";
|
|
6
6
|
import { n as assertInstanceOf, t as assert } from "../assert-jSdZMYam.mjs";
|
|
7
7
|
import { t as assertThrows } from "../assert_throws-BOkhLGYc.mjs";
|
|
8
|
-
import { a as generateCryptoKeyPair } from "../key-
|
|
8
|
+
import { a as generateCryptoKeyPair } from "../key-BbuFo4CW.mjs";
|
|
9
9
|
import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.mjs";
|
|
10
|
-
import { a as compactJsonLd, f as isInvalidUrlTypeError, g as verifySignature, h as verifyJsonLd, i as attachSignature, n as UnsafeJsonLdError, o as createSignature, p as signJsonLd, s as detachSignature, u as hasSignatureLike } from "../ld-
|
|
10
|
+
import { a as compactJsonLd, f as isInvalidUrlTypeError, g as verifySignature, h as verifyJsonLd, i as attachSignature, n as UnsafeJsonLdError, o as createSignature, p as signJsonLd, s as detachSignature, u as hasSignatureLike } from "../ld-BYV2Luge.mjs";
|
|
11
11
|
import { CryptographicKey } from "@fedify/vocab";
|
|
12
12
|
import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
13
13
|
import { encodeBase64 } from "byte-encodings/base64";
|
|
14
14
|
//#region src/sig/ld.test.ts
|
|
15
15
|
test("isInvalidUrlTypeError()", () => {
|
|
16
|
+
assert(isInvalidUrlTypeError(/* @__PURE__ */ new TypeError("Invalid URL string.")));
|
|
17
|
+
assertFalse(isInvalidUrlTypeError(/* @__PURE__ */ new Error("Invalid URL string.")));
|
|
18
|
+
assertFalse(isInvalidUrlTypeError(/* @__PURE__ */ new TypeError("Invalid URL string. Other error")));
|
|
16
19
|
assert(isInvalidUrlTypeError(/* @__PURE__ */ new TypeError("Invalid URL: http://[")));
|
|
17
20
|
assert(isInvalidUrlTypeError(/* @__PURE__ */ new TypeError("\"http://[\" cannot be parsed as a URL.")));
|
|
18
21
|
const error = /* @__PURE__ */ new TypeError("Failed to parse URL");
|
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-CTYio50W.cjs");
|
|
5
|
+
const require_proof = require("../proof-CGKQFT2M.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 { F as validateAcceptSignature, M as formatAcceptSignature, N as fulfillAcceptSignature, P as parseAcceptSignature, a as verifyRequestDetailed, c as fetchKey, d as importJwk, i as verifyRequest, l as fetchKeyDetailed, o as exportJwk, r as signRequest, u as generateCryptoKeyPair } from "../http-
|
|
4
|
-
import { C as verifySignature, S as verifyJsonLd, _ as hasSignatureLike, a as verifyProof, b as signJsonLd, c as getKeyOwner, d as attachSignature, i as verifyObject, m as detachSignature, n as hasProofLike, p as createSignature, r as signObject, s as doesActorOwnKey, t as createProof } from "../proof-
|
|
3
|
+
import { F as validateAcceptSignature, M as formatAcceptSignature, N as fulfillAcceptSignature, P as parseAcceptSignature, a as verifyRequestDetailed, c as fetchKey, d as importJwk, i as verifyRequest, l as fetchKeyDetailed, o as exportJwk, r as signRequest, u as generateCryptoKeyPair } from "../http-BY8PpQzP.js";
|
|
4
|
+
import { C as verifySignature, S as verifyJsonLd, _ as hasSignatureLike, a as verifyProof, b as signJsonLd, c as getKeyOwner, d as attachSignature, i as verifyObject, m as detachSignature, n as hasProofLike, p as createSignature, r as signObject, s as doesActorOwnKey, t as createProof } from "../proof-BxS2Xa8B.js";
|
|
5
5
|
export { attachSignature, createProof, createSignature, detachSignature, doesActorOwnKey, exportJwk, fetchKey, fetchKeyDetailed, formatAcceptSignature, fulfillAcceptSignature, generateCryptoKeyPair, getKeyOwner, hasProofLike, hasSignatureLike, importJwk, parseAcceptSignature, signJsonLd, signObject, signRequest, validateAcceptSignature, verifyJsonLd, verifyObject, verifyProof, verifyRequest, verifyRequestDetailed, verifySignature };
|
package/dist/sig/owner.test.mjs
CHANGED
|
@@ -2,11 +2,11 @@ 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-
|
|
5
|
+
import "../std__assert-BvGuO4xO.mjs";
|
|
6
6
|
import { r as assertFalse } from "../assert_rejects-DN60FHPX.mjs";
|
|
7
7
|
import { t as assert } from "../assert-jSdZMYam.mjs";
|
|
8
8
|
import { o as rsaPublicKey1, s as rsaPublicKey2 } from "../keys-BAK-tUlf.mjs";
|
|
9
|
-
import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-
|
|
9
|
+
import { n as getKeyOwner, t as doesActorOwnKey } from "../owner-BsBzJADO.mjs";
|
|
10
10
|
import { Create, CryptographicKey, lookupObject } from "@fedify/vocab";
|
|
11
11
|
import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
12
12
|
//#region src/sig/owner.test.ts
|
package/dist/sig/proof.test.mjs
CHANGED
|
@@ -2,12 +2,12 @@ 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-
|
|
5
|
+
import "../std__assert-BvGuO4xO.mjs";
|
|
6
6
|
import { n as assertGreaterOrEqual, r as assertFalse, t as assertRejects } from "../assert_rejects-DN60FHPX.mjs";
|
|
7
7
|
import { n as assertInstanceOf, t as assert } from "../assert-jSdZMYam.mjs";
|
|
8
8
|
import { i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-BAK-tUlf.mjs";
|
|
9
9
|
import { r as normalizeOutgoingActivityJsonLd } from "../outgoing-jsonld-HOAywiid.mjs";
|
|
10
|
-
import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-
|
|
10
|
+
import { a as verifyProof, i as verifyObject, n as hasProofLike, r as signObject, t as createProof } from "../proof-cXVkPBIU.mjs";
|
|
11
11
|
import { Create, DataIntegrityProof, Document, Multikey, Note, PUBLIC_COLLECTION, Place } from "@fedify/vocab";
|
|
12
12
|
import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
13
13
|
import { decodeMultibase, importMultibaseKey } from "@fedify/vocab-runtime";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { l as AssertionError
|
|
4
|
+
import { l as AssertionError } from "./assert_equals-C-ZRDbaf.mjs";
|
|
5
5
|
import "./assert_rejects-DN60FHPX.mjs";
|
|
6
6
|
import "./assert_throws-BOkhLGYc.mjs";
|
|
7
7
|
import "./assert_strict_equals-XEgZAlrj.mjs";
|
|
@@ -28,31 +28,6 @@ import "./assert_strict_equals-XEgZAlrj.mjs";
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
//#endregion
|
|
31
|
-
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert_greater.js
|
|
32
|
-
/**
|
|
33
|
-
* Make an assertion that `actual` is greater than `expected`.
|
|
34
|
-
* If not then throw.
|
|
35
|
-
*
|
|
36
|
-
* @example Usage
|
|
37
|
-
* ```ts no-eval
|
|
38
|
-
* import { assertGreater } from "@std/assert/assert-greater";
|
|
39
|
-
*
|
|
40
|
-
* assertGreater(2, 1); // Doesn't throw
|
|
41
|
-
* assertGreater(1, 1); // Throws
|
|
42
|
-
* assertGreater(0, 1); // Throws
|
|
43
|
-
* ```
|
|
44
|
-
*
|
|
45
|
-
* @typeParam T The type of the values to compare.
|
|
46
|
-
* @param actual The actual value to compare.
|
|
47
|
-
* @param expected The expected value to compare.
|
|
48
|
-
* @param msg The optional message to display if the assertion fails.
|
|
49
|
-
*/ function assertGreater(actual, expected, msg) {
|
|
50
|
-
if (actual > expected) return;
|
|
51
|
-
const actualString = format(actual);
|
|
52
|
-
const expectedString = format(expected);
|
|
53
|
-
throw new AssertionError(msg ?? `Expect ${actualString} > ${expectedString}`);
|
|
54
|
-
}
|
|
55
|
-
//#endregion
|
|
56
31
|
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert_string_includes.js
|
|
57
32
|
/**
|
|
58
33
|
* Make an assertion that actual includes expected. If not
|
|
@@ -76,4 +51,4 @@ import "./assert_strict_equals-XEgZAlrj.mjs";
|
|
|
76
51
|
}
|
|
77
52
|
}
|
|
78
53
|
//#endregion
|
|
79
|
-
export {
|
|
54
|
+
export { assertExists as n, assertStringIncludes as t };
|
|
@@ -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-BYV2Luge.mjs";
|
|
5
5
|
import jsonld from "@fedify/vocab-runtime/jsonld";
|
|
6
6
|
//#region src/federation/temporal.ts
|
|
7
7
|
function isPlainObject(value) {
|
package/dist/testing/mod.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { i as testDefinitions, n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-
|
|
4
|
+
import { i as testDefinitions, n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-CxbCIptr.mjs";
|
|
5
5
|
export { createInboxContext, createOutboxContext, createRequestContext, testDefinitions };
|
|
@@ -93,8 +93,8 @@ const DEFAULT_MAX_REDIRECTION = 5;
|
|
|
93
93
|
* bounce the request to an internal address.
|
|
94
94
|
* @param url The URL to fetch.
|
|
95
95
|
* @param headers The request headers.
|
|
96
|
-
* @returns The final response, or `null` if the URL is disallowed
|
|
97
|
-
* are too many redirects.
|
|
96
|
+
* @returns The final response, or `null` if the URL is disallowed, its
|
|
97
|
+
* hostname cannot be resolved, or there are too many redirects.
|
|
98
98
|
*/
|
|
99
99
|
async function fetchPublicUrl(url, headers) {
|
|
100
100
|
let current = url instanceof URL ? url : new URL(url);
|
|
@@ -104,7 +104,11 @@ async function fetchPublicUrl(url, headers) {
|
|
|
104
104
|
await (0, _fedify_vocab_runtime.validatePublicUrl)(current.href);
|
|
105
105
|
} catch (e) {
|
|
106
106
|
if (e instanceof _fedify_vocab_runtime.UrlError) {
|
|
107
|
-
logger.error("
|
|
107
|
+
if (e.reason === "dns") logger.error("DNS lookup failed for {url}: {error}", {
|
|
108
|
+
url: current.href,
|
|
109
|
+
error: e
|
|
110
|
+
});
|
|
111
|
+
else logger.error("Refused to fetch a private or invalid URL {url}: {error}", {
|
|
108
112
|
url: current.href,
|
|
109
113
|
error: e
|
|
110
114
|
});
|
|
@@ -92,8 +92,8 @@ const DEFAULT_MAX_REDIRECTION = 5;
|
|
|
92
92
|
* bounce the request to an internal address.
|
|
93
93
|
* @param url The URL to fetch.
|
|
94
94
|
* @param headers The request headers.
|
|
95
|
-
* @returns The final response, or `null` if the URL is disallowed
|
|
96
|
-
* are too many redirects.
|
|
95
|
+
* @returns The final response, or `null` if the URL is disallowed, its
|
|
96
|
+
* hostname cannot be resolved, or there are too many redirects.
|
|
97
97
|
*/
|
|
98
98
|
async function fetchPublicUrl(url, headers) {
|
|
99
99
|
let current = url instanceof URL ? url : new URL(url);
|
|
@@ -103,7 +103,11 @@ async function fetchPublicUrl(url, headers) {
|
|
|
103
103
|
await validatePublicUrl(current.href);
|
|
104
104
|
} catch (e) {
|
|
105
105
|
if (e instanceof UrlError) {
|
|
106
|
-
logger.error("
|
|
106
|
+
if (e.reason === "dns") logger.error("DNS lookup failed for {url}: {error}", {
|
|
107
|
+
url: current.href,
|
|
108
|
+
error: e
|
|
109
|
+
});
|
|
110
|
+
else logger.error("Refused to fetch a private or invalid URL {url}: {error}", {
|
|
107
111
|
url: current.href,
|
|
108
112
|
error: e
|
|
109
113
|
});
|
|
@@ -3,13 +3,16 @@ 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-
|
|
6
|
+
import "../std__assert-BvGuO4xO.mjs";
|
|
7
7
|
import { t as assertRejects } from "../assert_rejects-DN60FHPX.mjs";
|
|
8
|
-
import { l as verifyRequest } from "../http-
|
|
8
|
+
import { l as verifyRequest } from "../http-BNDHRNJP.mjs";
|
|
9
9
|
import { i as rsaPrivateKey2 } from "../keys-BAK-tUlf.mjs";
|
|
10
|
-
import { t as getAuthenticatedDocumentLoader } from "../docloader-
|
|
10
|
+
import { t as getAuthenticatedDocumentLoader } from "../docloader-w72ipM49.mjs";
|
|
11
|
+
import { configure, reset } from "@logtape/logtape";
|
|
11
12
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
12
13
|
import { FetchError, UrlError } from "@fedify/vocab-runtime";
|
|
14
|
+
import dns from "node:dns/promises";
|
|
15
|
+
import { deepStrictEqual, ok, rejects } from "node:assert/strict";
|
|
13
16
|
//#region src/utils/docloader.test.ts
|
|
14
17
|
test("getAuthenticatedDocumentLoader()", async (t) => {
|
|
15
18
|
esm_default.spyGlobal();
|
|
@@ -160,5 +163,298 @@ test("getAuthenticatedDocumentLoader() bounds JSON after redirects", async () =>
|
|
|
160
163
|
esm_default.hardReset();
|
|
161
164
|
}
|
|
162
165
|
});
|
|
166
|
+
test("getAuthenticatedDocumentLoader() logs DNS failures as such", { ignore: "Deno" in globalThis && (await Deno.permissions.query({ name: "net" })).state !== "granted" }, async (t) => {
|
|
167
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
168
|
+
keyId: new URL("https://example.com/key2"),
|
|
169
|
+
privateKey: rsaPrivateKey2
|
|
170
|
+
});
|
|
171
|
+
for (const result of [
|
|
172
|
+
"throws",
|
|
173
|
+
"empty",
|
|
174
|
+
"private"
|
|
175
|
+
]) await t.step(result, async () => {
|
|
176
|
+
const originalLookup = dns.lookup;
|
|
177
|
+
dns.lookup = (() => result === "throws" ? Promise.reject(/* @__PURE__ */ new Error("Resolver unavailable")) : Promise.resolve(result === "empty" ? [] : [{
|
|
178
|
+
address: "127.0.0.1",
|
|
179
|
+
family: 4
|
|
180
|
+
}]));
|
|
181
|
+
const records = [];
|
|
182
|
+
await configure({
|
|
183
|
+
sinks: { buffer: (record) => records.push(record) },
|
|
184
|
+
loggers: [{
|
|
185
|
+
category: "fedify",
|
|
186
|
+
sinks: ["buffer"],
|
|
187
|
+
lowestLevel: "debug"
|
|
188
|
+
}, {
|
|
189
|
+
category: ["logtape", "meta"],
|
|
190
|
+
sinks: []
|
|
191
|
+
}],
|
|
192
|
+
reset: true
|
|
193
|
+
});
|
|
194
|
+
try {
|
|
195
|
+
const url = "https://dns-failure.invalid/object";
|
|
196
|
+
const error = await assertRejects(() => loader(url), UrlError);
|
|
197
|
+
assertEquals(error.reason, result === "private" ? "disallowed" : "dns");
|
|
198
|
+
assertEquals(records.map((r) => [
|
|
199
|
+
r.level,
|
|
200
|
+
r.rawMessage,
|
|
201
|
+
r.properties.url
|
|
202
|
+
]), [result === "private" ? [
|
|
203
|
+
"error",
|
|
204
|
+
"Disallowed private URL: {url}",
|
|
205
|
+
url
|
|
206
|
+
] : [
|
|
207
|
+
"debug",
|
|
208
|
+
"DNS lookup failed for {url}",
|
|
209
|
+
url
|
|
210
|
+
]]);
|
|
211
|
+
assertEquals(records[0].properties.error, error);
|
|
212
|
+
} finally {
|
|
213
|
+
await reset();
|
|
214
|
+
dns.lookup = originalLookup;
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
test("getAuthenticatedDocumentLoader() bounds alternate document chains", async (t) => {
|
|
219
|
+
const base = "https://example.com/alternate-chain/";
|
|
220
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
221
|
+
keyId: new URL("https://example.com/key2"),
|
|
222
|
+
privateKey: rsaPrivateKey2
|
|
223
|
+
}, { allowPrivateAddress: true });
|
|
224
|
+
for (const mode of [
|
|
225
|
+
"header",
|
|
226
|
+
"html",
|
|
227
|
+
"mixed"
|
|
228
|
+
]) for (const hops of [20, 21]) await t.step(`${mode}: ${hops} hops`, async () => {
|
|
229
|
+
esm_default.mockGlobal();
|
|
230
|
+
let requests = 0;
|
|
231
|
+
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
232
|
+
requests++;
|
|
233
|
+
const index = Number(new URL(url).pathname.split("/").at(-1));
|
|
234
|
+
if (index === hops || requests > 30) return Response.json({ done: true });
|
|
235
|
+
const next = `${base}${index + 1}`;
|
|
236
|
+
if (mode === "mixed" && index % 2 === 1) return Response.redirect(next, 302);
|
|
237
|
+
return alternate(next, mode === "html");
|
|
238
|
+
});
|
|
239
|
+
try {
|
|
240
|
+
if (hops === 20) deepStrictEqual((await loader(`${base}0`)).document, { done: true });
|
|
241
|
+
else await rejects(loader(`${base}0`), (error) => {
|
|
242
|
+
ok(error instanceof FetchError);
|
|
243
|
+
ok(error.message.includes("Too many redirections (21)"));
|
|
244
|
+
return true;
|
|
245
|
+
});
|
|
246
|
+
deepStrictEqual(requests, 21);
|
|
247
|
+
} finally {
|
|
248
|
+
esm_default.hardReset();
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
for (const mode of [
|
|
252
|
+
"header",
|
|
253
|
+
"html",
|
|
254
|
+
"alternate-redirect",
|
|
255
|
+
"redirect-alternate",
|
|
256
|
+
"redirect-intermediate"
|
|
257
|
+
]) await t.step(`${mode}: cycle`, async () => {
|
|
258
|
+
esm_default.mockGlobal();
|
|
259
|
+
let requests = 0;
|
|
260
|
+
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
261
|
+
requests++;
|
|
262
|
+
if (requests > 30) return Response.json({ stopped: true });
|
|
263
|
+
const index = Number(new URL(url).pathname.split("/").at(-1));
|
|
264
|
+
const next = `${base}${mode === "redirect-intermediate" ? index === 0 ? 1 : index === 1 ? 2 : 1 : 1 - index}`;
|
|
265
|
+
if (mode === "alternate-redirect" && index === 1 || (mode === "redirect-alternate" || mode === "redirect-intermediate") && index === 0) return Response.redirect(next, 302);
|
|
266
|
+
return alternate(next, mode === "html");
|
|
267
|
+
});
|
|
268
|
+
try {
|
|
269
|
+
await rejects(loader(`${base}0`), (error) => {
|
|
270
|
+
ok(error instanceof FetchError);
|
|
271
|
+
ok(error.message.includes("Redirect loop detected:"));
|
|
272
|
+
return true;
|
|
273
|
+
});
|
|
274
|
+
deepStrictEqual(requests, mode === "redirect-intermediate" ? 3 : 2);
|
|
275
|
+
} finally {
|
|
276
|
+
esm_default.hardReset();
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
await t.step("alternate followed by 20 redirects shares the limit", async () => {
|
|
280
|
+
esm_default.mockGlobal();
|
|
281
|
+
let requests = 0;
|
|
282
|
+
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
283
|
+
requests++;
|
|
284
|
+
const index = Number(new URL(url).pathname.split("/").at(-1));
|
|
285
|
+
if (index === 21) return Response.json({ done: true });
|
|
286
|
+
return index === 0 ? alternate(`${base}1`, false) : Response.redirect(`${base}${index + 1}`, 302);
|
|
287
|
+
});
|
|
288
|
+
try {
|
|
289
|
+
await rejects(loader(`${base}0`), (error) => {
|
|
290
|
+
ok(error instanceof FetchError);
|
|
291
|
+
ok(error.message.includes("Too many redirections (21)"));
|
|
292
|
+
return true;
|
|
293
|
+
});
|
|
294
|
+
deepStrictEqual(requests, 21);
|
|
295
|
+
} finally {
|
|
296
|
+
esm_default.hardReset();
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
await t.step("relative alternate after redirect and isolated calls", async () => {
|
|
300
|
+
esm_default.mockGlobal();
|
|
301
|
+
esm_default.get(`${base}start`, Response.redirect(`${base}html`, 302));
|
|
302
|
+
esm_default.get(`${base}html`, alternate("./document", true));
|
|
303
|
+
esm_default.get(`${base}document`, Response.json({ done: true }));
|
|
304
|
+
try {
|
|
305
|
+
for (let i = 0; i < 2; i++) {
|
|
306
|
+
const results = await Promise.all([loader(`${base}start`), loader(`${base}start`)]);
|
|
307
|
+
for (const result of results) {
|
|
308
|
+
deepStrictEqual(result.document, { done: true });
|
|
309
|
+
deepStrictEqual(result.documentUrl, `${base}document`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
} finally {
|
|
313
|
+
esm_default.hardReset();
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
function alternate(next, html) {
|
|
317
|
+
return html ? new Response(`<link rel="alternate" type="application/activity+json" href="${next}">`, { headers: { "Content-Type": "text/html" } }) : new Response("not JSON", { headers: {
|
|
318
|
+
"Content-Type": "text/plain",
|
|
319
|
+
Link: `<${next}>; rel="alternate"; type="application/activity+json"`
|
|
320
|
+
} });
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
test("getAuthenticatedDocumentLoader() preserves cancellation across alternates", async (t) => {
|
|
324
|
+
const base = "https://example.com/alternate-abort/";
|
|
325
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
326
|
+
keyId: new URL("https://example.com/key2"),
|
|
327
|
+
privateKey: rsaPrivateKey2
|
|
328
|
+
}, { allowPrivateAddress: true });
|
|
329
|
+
for (const html of [false, true]) await t.step(html ? "HTML" : "Link header", async () => {
|
|
330
|
+
esm_default.mockGlobal();
|
|
331
|
+
const controller = new AbortController();
|
|
332
|
+
const reason = /* @__PURE__ */ new Error("Alternate document loading cancelled");
|
|
333
|
+
let requests = 0;
|
|
334
|
+
esm_default.get(`begin:${base}`, ({ url }) => {
|
|
335
|
+
requests++;
|
|
336
|
+
const index = Number(new URL(url).pathname.split("/").at(-1));
|
|
337
|
+
if (index === 2) return Response.json({ done: true });
|
|
338
|
+
if (index === 1) controller.abort(reason);
|
|
339
|
+
const next = `${base}${index + 1}`;
|
|
340
|
+
return new Response(html ? `<link rel="alternate" type="application/activity+json" href="${next}">` : "not JSON", { headers: html ? { "Content-Type": "text/html" } : {
|
|
341
|
+
"Content-Type": "text/plain",
|
|
342
|
+
Link: `<${next}>; rel="alternate"; type="application/activity+json"`
|
|
343
|
+
} });
|
|
344
|
+
});
|
|
345
|
+
try {
|
|
346
|
+
await rejects(loader(`${base}0`, { signal: controller.signal }), (error) => {
|
|
347
|
+
ok(error === reason);
|
|
348
|
+
return true;
|
|
349
|
+
});
|
|
350
|
+
deepStrictEqual(requests, 2);
|
|
351
|
+
} finally {
|
|
352
|
+
esm_default.hardReset();
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
test("getAuthenticatedDocumentLoader() tracks fallback redirects after alternates", async () => {
|
|
357
|
+
esm_default.mockGlobal();
|
|
358
|
+
let requests = 0;
|
|
359
|
+
let knocks = 0;
|
|
360
|
+
const first = "https://example.com/fallback-alternate/a";
|
|
361
|
+
const second = "https://example.com/fallback-alternate/b";
|
|
362
|
+
esm_default.get(first, () => {
|
|
363
|
+
requests++;
|
|
364
|
+
if (requests > 30) return Response.json({ stopped: true });
|
|
365
|
+
return new Response("", { headers: {
|
|
366
|
+
"Content-Type": "text/plain",
|
|
367
|
+
Link: `<${second}>; rel="alternate"; type="application/activity+json"`
|
|
368
|
+
} });
|
|
369
|
+
});
|
|
370
|
+
esm_default.get(second, () => {
|
|
371
|
+
requests++;
|
|
372
|
+
return ++knocks % 2 === 1 ? new Response("", { status: 401 }) : Response.redirect(first, 302);
|
|
373
|
+
});
|
|
374
|
+
try {
|
|
375
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
376
|
+
keyId: new URL("https://example.com/key2"),
|
|
377
|
+
privateKey: rsaPrivateKey2
|
|
378
|
+
}, { allowPrivateAddress: true });
|
|
379
|
+
await assertRejects(() => loader(first), FetchError, "Redirect loop detected:");
|
|
380
|
+
assertEquals(requests, 3);
|
|
381
|
+
} finally {
|
|
382
|
+
esm_default.hardReset();
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
test("getAuthenticatedDocumentLoader() resolves relative alternates without response URLs", async () => {
|
|
386
|
+
const originalFetch = globalThis.fetch;
|
|
387
|
+
const base = "https://example.com/empty-response-url/";
|
|
388
|
+
const urls = [];
|
|
389
|
+
globalThis.fetch = (input) => {
|
|
390
|
+
const url = input instanceof Request ? input.url : String(input);
|
|
391
|
+
urls.push(url);
|
|
392
|
+
if (url === `${base}start`) return Promise.resolve(Response.redirect(`${base}nested/page`, 302));
|
|
393
|
+
if (url === `${base}nested/page`) return Promise.resolve(new Response("<link rel=\"alternate\" type=\"application/activity+json\" href=\"document\">", { headers: { "Content-Type": "text/html" } }));
|
|
394
|
+
assertEquals(url, `${base}nested/document`);
|
|
395
|
+
return Promise.resolve(Response.json({ done: true }));
|
|
396
|
+
};
|
|
397
|
+
try {
|
|
398
|
+
assertEquals(await getAuthenticatedDocumentLoader({
|
|
399
|
+
keyId: new URL("https://example.com/key2"),
|
|
400
|
+
privateKey: rsaPrivateKey2
|
|
401
|
+
}, { allowPrivateAddress: true })(`${base}start`), {
|
|
402
|
+
contextUrl: null,
|
|
403
|
+
document: { done: true },
|
|
404
|
+
documentUrl: `${base}nested/document`
|
|
405
|
+
});
|
|
406
|
+
assertEquals(urls, [
|
|
407
|
+
`${base}start`,
|
|
408
|
+
`${base}nested/page`,
|
|
409
|
+
`${base}nested/document`
|
|
410
|
+
]);
|
|
411
|
+
} finally {
|
|
412
|
+
globalThis.fetch = originalFetch;
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
test("getAuthenticatedDocumentLoader() validates alternate addresses", async () => {
|
|
416
|
+
esm_default.mockGlobal();
|
|
417
|
+
let privateRequests = 0;
|
|
418
|
+
const url = "https://8.8.8.8/alternate";
|
|
419
|
+
esm_default.get(url, new Response("", { headers: {
|
|
420
|
+
"Content-Type": "text/plain",
|
|
421
|
+
Link: "<http://127.0.0.1/private>; rel=\"alternate\"; type=\"application/activity+json\""
|
|
422
|
+
} }));
|
|
423
|
+
esm_default.get("http://127.0.0.1/private", () => {
|
|
424
|
+
privateRequests++;
|
|
425
|
+
return Response.json({ private: true });
|
|
426
|
+
});
|
|
427
|
+
try {
|
|
428
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
429
|
+
keyId: new URL("https://example.com/key2"),
|
|
430
|
+
privateKey: rsaPrivateKey2
|
|
431
|
+
});
|
|
432
|
+
await assertRejects(() => loader(url), UrlError);
|
|
433
|
+
assertEquals(privateRequests, 0);
|
|
434
|
+
} finally {
|
|
435
|
+
esm_default.hardReset();
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
test("getAuthenticatedDocumentLoader() rejects cancellation before fetching", async () => {
|
|
439
|
+
esm_default.mockGlobal();
|
|
440
|
+
let requests = 0;
|
|
441
|
+
const url = "https://example.com/pre-aborted-alternate";
|
|
442
|
+
esm_default.get(url, () => {
|
|
443
|
+
requests++;
|
|
444
|
+
return Response.json({ done: true });
|
|
445
|
+
});
|
|
446
|
+
try {
|
|
447
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
448
|
+
keyId: new URL("https://example.com/key2"),
|
|
449
|
+
privateKey: rsaPrivateKey2
|
|
450
|
+
}, { allowPrivateAddress: true });
|
|
451
|
+
const controller = new AbortController();
|
|
452
|
+
controller.abort();
|
|
453
|
+
await rejects(loader(url, { signal: controller.signal }), { name: "AbortError" });
|
|
454
|
+
deepStrictEqual(requests, 0);
|
|
455
|
+
} finally {
|
|
456
|
+
esm_default.hardReset();
|
|
457
|
+
}
|
|
458
|
+
});
|
|
163
459
|
//#endregion
|
|
164
460
|
export {};
|
|
@@ -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 { n as kvCache, t as MockKvStore } from "../kv-cache-
|
|
4
|
+
import { n as kvCache, t as MockKvStore } from "../kv-cache-CNZOaZYq.mjs";
|
|
5
5
|
import { deepStrictEqual, throws } from "node:assert";
|
|
6
6
|
import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
7
7
|
import { preloadedContexts } from "@fedify/vocab-runtime";
|
package/dist/utils/mod.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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_kv_cache = require("../kv-cache-
|
|
4
|
+
const require_kv_cache = require("../kv-cache-CrcqGkT-.cjs");
|
|
5
5
|
exports.getAuthenticatedDocumentLoader = require_kv_cache.getAuthenticatedDocumentLoader;
|
|
6
6
|
exports.kvCache = require_kv_cache.kvCache;
|
package/dist/utils/mod.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../mod-
|
|
2
|
+
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../mod-Co1M3Ux0.cjs";
|
|
3
3
|
export { getAuthenticatedDocumentLoader, kvCache };
|