@fedify/fedify 2.3.7 → 2.3.9-dev.2048
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{assert_instance_of-DBC5X09g.mjs → assert-jSdZMYam.mjs} +19 -1
- package/dist/{builder-Bg7nkigw.mjs → builder-BfY2wZ4V.mjs} +3 -3
- package/dist/{client-D1KuWxjH.mjs → client-DYDoDpMa.mjs} +78 -4
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/outgoing-jsonld.test.mjs +1 -1
- package/dist/compat/public-audience.test.mjs +1 -1
- package/dist/compat/transformers.test.mjs +3 -4
- package/dist/{context-DVoTs_wM.mjs → context-BepjCFHN.mjs} +1 -0
- package/dist/{context-BxVVO5Ro.d.ts → context-CAKnQy1x.d.ts} +4 -3
- package/dist/{context-BpmLyiPx.d.cts → context-CSIggG9_.d.cts} +4 -3
- package/dist/{deno-CTdCdRmf.mjs → deno-ayal9buz.mjs} +1 -1
- package/dist/{docloader-BVBWf8Bg.mjs → docloader-C-JrNL14.mjs} +2 -2
- package/dist/federation/builder.test.mjs +2 -2
- package/dist/federation/circuit-breaker.test.mjs +3 -3
- package/dist/federation/collection.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +128 -11
- package/dist/federation/idempotency.test.mjs +4 -4
- package/dist/federation/inbox.test.mjs +1 -1
- package/dist/federation/keycache.test.mjs +44 -10
- package/dist/federation/kv.test.mjs +1 -1
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +109 -19
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +2 -2
- package/dist/federation/mod.d.ts +2 -2
- package/dist/federation/mod.js +1 -1
- package/dist/federation/mq.test.mjs +1 -1
- package/dist/federation/negotiation.test.mjs +2 -2
- package/dist/federation/retry.test.mjs +1 -1
- package/dist/federation/router.test.mjs +1 -1
- package/dist/federation/send.test.mjs +141 -7
- package/dist/federation/temporal.test.mjs +2 -2
- package/dist/federation/webfinger.test.mjs +3 -3
- package/dist/{http-B3-zan5-.mjs → http-B2u6PvNX.mjs} +4 -4
- package/dist/{http-BjV0BTWd.cjs → http-BGP2QCbe.cjs} +166 -6
- package/dist/{http-DRVY9K4R.js → http-BPPCh0xN.js} +155 -7
- package/dist/{http-lf8Hsd91.d.ts → http-DQmNpfym.d.ts} +1 -1
- package/dist/{http-VyDTd4G3.d.cts → http-DiWQB8Mr.d.cts} +1 -1
- package/dist/{key-C_a6iE1-.mjs → key-C9DkrWwb.mjs} +155 -7
- package/dist/{keycache-BeU0LCII.mjs → keycache-B3qRQNLj.mjs} +12 -4
- package/dist/{kv-cache-OzUoHKnZ.cjs → kv-cache-C1TC_e9y.cjs} +2 -2
- package/dist/{kv-cache-b1dJZHUx.js → kv-cache-Cl1q1aA9.js} +2 -2
- package/dist/{kv-cache-BjjcmjtG.mjs → kv-cache-qJSjfLGm.mjs} +1 -1
- package/dist/{ld-COo05yJj.mjs → ld-DNl7KwLY.mjs} +3 -3
- package/dist/{metrics-V6vX0M13.mjs → metrics-Ce55disp.mjs} +1 -1
- package/dist/{middleware-DRk6xiYo.mjs → middleware-BCG2BX1n.mjs} +41 -30
- package/dist/{middleware-EDVv6ewB.cjs → middleware-BZojifnF.cjs} +101 -25
- package/dist/{middleware-DRGWEo0V.mjs → middleware-C96wm_7x.mjs} +1 -1
- package/dist/{middleware-K13LhN5w.js → middleware-C_utyVa_.js} +101 -25
- package/dist/{mod-yvIXFAEi.d.cts → mod-1TuoXkGs.d.cts} +1 -1
- package/dist/{mod-B0hW12_O.d.cts → mod-Bid79LFU.d.cts} +1 -1
- package/dist/{mod-Rpy4Uwkk.d.ts → mod-CFuyfw3c.d.ts} +1 -1
- package/dist/{mod-DFvNJcNb.d.ts → mod-DHgc4ygG.d.ts} +1 -1
- package/dist/{mod-CjERT09F.d.cts → mod-PVR75MeU.d.cts} +1 -1
- package/dist/{mod-COIAjwRS.d.ts → mod-TLEvgT1i.d.ts} +1 -1
- 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 +28 -1
- 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/{outgoing-jsonld-OFoubetZ.mjs → outgoing-jsonld-HOAywiid.mjs} +1 -1
- package/dist/{owner-CnngXDNJ.d.ts → owner-B3hNQCG8.d.cts} +12 -1
- package/dist/{owner-DEvZuyOE.d.cts → owner-CiBPcC6F.d.ts} +12 -1
- package/dist/owner-DqqDBw-l.mjs +175 -0
- package/dist/{proof-kFq0IDK4.mjs → proof-D5vP7VIN.mjs} +5 -5
- package/dist/{proof-D6gZeewf.js → proof-Dz9ObvUq.js} +112 -58
- package/dist/{proof-Xk8lHNc0.cjs → proof-I6YcKRRq.cjs} +112 -58
- package/dist/{send-3lH63Nqf.mjs → send-CBtR8DQK.mjs} +68 -11
- package/dist/sig/accept.test.mjs +1 -1
- package/dist/sig/http.test.mjs +4 -4
- package/dist/sig/key.test.mjs +170 -3
- package/dist/sig/ld.test.mjs +56 -4
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.d.cts +3 -3
- package/dist/sig/mod.d.ts +3 -3
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +105 -6
- package/dist/sig/proof.test.mjs +73 -5
- package/dist/{temporal-Chwx9cEn.mjs → temporal-B9t2tY9A.mjs} +1 -1
- package/dist/testing/mod.mjs +1 -1
- package/dist/{types-m8u9L86X.cjs → types-DWs-qZaY.cjs} +94 -2
- package/dist/{types-DTONwNqL.js → types-sXITXcWa.js} +78 -4
- package/dist/utils/docloader.test.mjs +28 -4
- 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 +6 -6
- package/dist/assert-OguE97r2.mjs +0 -23
- package/dist/owner-B3720pz3.mjs +0 -120
- /package/dist/{accept-CPkZzmGN.mjs → accept-Dd__NiUL.mjs} +0 -0
- /package/dist/{activity-listener-tztVvlNb.mjs → activity-listener-ell7W1s9.mjs} +0 -0
- /package/dist/{circuit-breaker-D1fxthDI.mjs → circuit-breaker-CDABzqVf.mjs} +0 -0
- /package/dist/{circuit-breaker-test-utils-CAdwjgMi.mjs → circuit-breaker-test-utils-Dm5MM6l9.mjs} +0 -0
- /package/dist/{collection-Cc3DVAhE.mjs → collection-CA3V5zyK.mjs} +0 -0
- /package/dist/{keys-DGu1NFwu.mjs → keys-BAK-tUlf.mjs} +0 -0
- /package/dist/{kv-rV3vodCc.mjs → kv-CX8qfaad.mjs} +0 -0
- /package/dist/{negotiation-DDstyBvc.mjs → negotiation-CDW-_gUU.mjs} +0 -0
- /package/dist/{public-audience-DZJAUUi8.mjs → public-audience-jwoSIGUw.mjs} +0 -0
- /package/dist/{retry-CXg_MBI-.mjs → retry-_VvV0h9f.mjs} +0 -0
- /package/dist/{types-J53Kw7so.mjs → types-s4mCTGkT.mjs} +0 -0
|
@@ -3,6 +3,80 @@ const { URLPattern } = require("urlpattern-polyfill");
|
|
|
3
3
|
require("./chunk-DDcVe30Y.cjs");
|
|
4
4
|
let _logtape_logtape = require("@logtape/logtape");
|
|
5
5
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
6
|
+
//#region src/utils/body.ts
|
|
7
|
+
/** Decoded JSON body limit: 16 MiB. @internal */
|
|
8
|
+
const MAX_BODY_SIZE = 16 * 1024 * 1024;
|
|
9
|
+
/** A body exceeded the byte limit. @internal */
|
|
10
|
+
var BodyTooLargeError = class extends _fedify_vocab_runtime.FetchError {
|
|
11
|
+
/** Creates an error for a body exceeding the given limit. */
|
|
12
|
+
constructor(url, maxBytes) {
|
|
13
|
+
super(url, `Body exceeds the limit of ${maxBytes} bytes`);
|
|
14
|
+
this.name = "BodyTooLargeError";
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
/** Validates a finite, positive byte limit. @internal */
|
|
18
|
+
function validateBodySizeLimit(maxBytes) {
|
|
19
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) throw new RangeError("The body size limit must be a positive safe integer.");
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Reads UTF-8 text while limiting bytes received from the body stream.
|
|
23
|
+
* Fetch responses are already decompressed, so the stream count is authoritative.
|
|
24
|
+
* @param message The response or request to read.
|
|
25
|
+
* @param maxBytes The maximum number of decoded bytes to read.
|
|
26
|
+
* @param url The URL to include in errors and logs.
|
|
27
|
+
* @returns The decoded body text.
|
|
28
|
+
* @throws {BodyTooLargeError} If the body exceeds the limit.
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
async function readBoundedText(message, maxBytes, url) {
|
|
32
|
+
validateBodySizeLimit(maxBytes);
|
|
33
|
+
const reader = message.body?.getReader();
|
|
34
|
+
const tooLarge = () => {
|
|
35
|
+
(0, _logtape_logtape.getLogger)([
|
|
36
|
+
"fedify",
|
|
37
|
+
"runtime",
|
|
38
|
+
"body"
|
|
39
|
+
]).warn("Body from {url} exceeds the limit of {maxBytes} bytes.", {
|
|
40
|
+
url: url.toString(),
|
|
41
|
+
maxBytes
|
|
42
|
+
});
|
|
43
|
+
throw new BodyTooLargeError(url, maxBytes);
|
|
44
|
+
};
|
|
45
|
+
try {
|
|
46
|
+
const length = message.headers.get("Content-Length");
|
|
47
|
+
const encoding = message.headers.get("Content-Encoding");
|
|
48
|
+
if ((encoding == null || encoding.toLowerCase() === "identity") && length != null && /^\d+$/.test(length) && Number(length) > maxBytes) tooLarge();
|
|
49
|
+
if (reader == null) return "";
|
|
50
|
+
let size = 0;
|
|
51
|
+
const textReader = new ReadableStream({ async pull(controller) {
|
|
52
|
+
const { done, value } = await reader.read();
|
|
53
|
+
if (done) {
|
|
54
|
+
controller.close();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
size += value.byteLength;
|
|
58
|
+
if (size > maxBytes) tooLarge();
|
|
59
|
+
controller.enqueue(value);
|
|
60
|
+
} }, { highWaterMark: 0 }).pipeThrough(new TextDecoderStream()).getReader();
|
|
61
|
+
try {
|
|
62
|
+
const chunks = [];
|
|
63
|
+
while (true) {
|
|
64
|
+
const { done, value } = await textReader.read();
|
|
65
|
+
if (done) break;
|
|
66
|
+
chunks.push(value);
|
|
67
|
+
}
|
|
68
|
+
return chunks.join("");
|
|
69
|
+
} finally {
|
|
70
|
+
textReader.releaseLock();
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
if (reader != null) reader.cancel(error).catch(() => {});
|
|
74
|
+
throw error;
|
|
75
|
+
} finally {
|
|
76
|
+
reader?.releaseLock();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
6
80
|
//#region src/nodeinfo/client.ts
|
|
7
81
|
const logger = (0, _logtape_logtape.getLogger)([
|
|
8
82
|
"fedify",
|
|
@@ -83,7 +157,7 @@ async function getNodeInfo(url, options = {}) {
|
|
|
83
157
|
});
|
|
84
158
|
return;
|
|
85
159
|
}
|
|
86
|
-
const wellKnownRd = await wellKnownResponse
|
|
160
|
+
const wellKnownRd = JSON.parse(await readBoundedText(wellKnownResponse, MAX_BODY_SIZE, wellKnownUrl));
|
|
87
161
|
const link = wellKnownRd?.links?.find((link) => link != null && "rel" in link && (link.rel === "http://nodeinfo.diaspora.software/ns/schema/2.0" || link.rel === "http://nodeinfo.diaspora.software/ns/schema/2.1") && "href" in link && link.href != null);
|
|
88
162
|
if (link == null || link.href == null) {
|
|
89
163
|
logger.error("Failed to find a NodeInfo document link from {url}: {resourceDescriptor}", {
|
|
@@ -107,7 +181,7 @@ async function getNodeInfo(url, options = {}) {
|
|
|
107
181
|
});
|
|
108
182
|
return;
|
|
109
183
|
}
|
|
110
|
-
const data = await response
|
|
184
|
+
const data = JSON.parse(await readBoundedText(response, MAX_BODY_SIZE, nodeInfoUrl));
|
|
111
185
|
if (options.parse === "none") return data;
|
|
112
186
|
return parseNodeInfo(data, { tryBestEffort: options.parse === "best-effort" }) ?? void 0;
|
|
113
187
|
} catch (error) {
|
|
@@ -353,6 +427,18 @@ function nodeInfoToJson(nodeInfo) {
|
|
|
353
427
|
};
|
|
354
428
|
}
|
|
355
429
|
//#endregion
|
|
430
|
+
Object.defineProperty(exports, "BodyTooLargeError", {
|
|
431
|
+
enumerable: true,
|
|
432
|
+
get: function() {
|
|
433
|
+
return BodyTooLargeError;
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
Object.defineProperty(exports, "MAX_BODY_SIZE", {
|
|
437
|
+
enumerable: true,
|
|
438
|
+
get: function() {
|
|
439
|
+
return MAX_BODY_SIZE;
|
|
440
|
+
}
|
|
441
|
+
});
|
|
356
442
|
Object.defineProperty(exports, "getNodeInfo", {
|
|
357
443
|
enumerable: true,
|
|
358
444
|
get: function() {
|
|
@@ -371,3 +457,9 @@ Object.defineProperty(exports, "parseNodeInfo", {
|
|
|
371
457
|
return parseNodeInfo;
|
|
372
458
|
}
|
|
373
459
|
});
|
|
460
|
+
Object.defineProperty(exports, "readBoundedText", {
|
|
461
|
+
enumerable: true,
|
|
462
|
+
get: function() {
|
|
463
|
+
return readBoundedText;
|
|
464
|
+
}
|
|
465
|
+
});
|
|
@@ -1,7 +1,81 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
import { getLogger } from "@logtape/logtape";
|
|
4
|
-
import { UrlError, getUserAgent, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
4
|
+
import { FetchError, UrlError, getUserAgent, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
5
|
+
//#region src/utils/body.ts
|
|
6
|
+
/** Decoded JSON body limit: 16 MiB. @internal */
|
|
7
|
+
const MAX_BODY_SIZE = 16 * 1024 * 1024;
|
|
8
|
+
/** A body exceeded the byte limit. @internal */
|
|
9
|
+
var BodyTooLargeError = class extends FetchError {
|
|
10
|
+
/** Creates an error for a body exceeding the given limit. */
|
|
11
|
+
constructor(url, maxBytes) {
|
|
12
|
+
super(url, `Body exceeds the limit of ${maxBytes} bytes`);
|
|
13
|
+
this.name = "BodyTooLargeError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
/** Validates a finite, positive byte limit. @internal */
|
|
17
|
+
function validateBodySizeLimit(maxBytes) {
|
|
18
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) throw new RangeError("The body size limit must be a positive safe integer.");
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Reads UTF-8 text while limiting bytes received from the body stream.
|
|
22
|
+
* Fetch responses are already decompressed, so the stream count is authoritative.
|
|
23
|
+
* @param message The response or request to read.
|
|
24
|
+
* @param maxBytes The maximum number of decoded bytes to read.
|
|
25
|
+
* @param url The URL to include in errors and logs.
|
|
26
|
+
* @returns The decoded body text.
|
|
27
|
+
* @throws {BodyTooLargeError} If the body exceeds the limit.
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
async function readBoundedText(message, maxBytes, url) {
|
|
31
|
+
validateBodySizeLimit(maxBytes);
|
|
32
|
+
const reader = message.body?.getReader();
|
|
33
|
+
const tooLarge = () => {
|
|
34
|
+
getLogger([
|
|
35
|
+
"fedify",
|
|
36
|
+
"runtime",
|
|
37
|
+
"body"
|
|
38
|
+
]).warn("Body from {url} exceeds the limit of {maxBytes} bytes.", {
|
|
39
|
+
url: url.toString(),
|
|
40
|
+
maxBytes
|
|
41
|
+
});
|
|
42
|
+
throw new BodyTooLargeError(url, maxBytes);
|
|
43
|
+
};
|
|
44
|
+
try {
|
|
45
|
+
const length = message.headers.get("Content-Length");
|
|
46
|
+
const encoding = message.headers.get("Content-Encoding");
|
|
47
|
+
if ((encoding == null || encoding.toLowerCase() === "identity") && length != null && /^\d+$/.test(length) && Number(length) > maxBytes) tooLarge();
|
|
48
|
+
if (reader == null) return "";
|
|
49
|
+
let size = 0;
|
|
50
|
+
const textReader = new ReadableStream({ async pull(controller) {
|
|
51
|
+
const { done, value } = await reader.read();
|
|
52
|
+
if (done) {
|
|
53
|
+
controller.close();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
size += value.byteLength;
|
|
57
|
+
if (size > maxBytes) tooLarge();
|
|
58
|
+
controller.enqueue(value);
|
|
59
|
+
} }, { highWaterMark: 0 }).pipeThrough(new TextDecoderStream()).getReader();
|
|
60
|
+
try {
|
|
61
|
+
const chunks = [];
|
|
62
|
+
while (true) {
|
|
63
|
+
const { done, value } = await textReader.read();
|
|
64
|
+
if (done) break;
|
|
65
|
+
chunks.push(value);
|
|
66
|
+
}
|
|
67
|
+
return chunks.join("");
|
|
68
|
+
} finally {
|
|
69
|
+
textReader.releaseLock();
|
|
70
|
+
}
|
|
71
|
+
} catch (error) {
|
|
72
|
+
if (reader != null) reader.cancel(error).catch(() => {});
|
|
73
|
+
throw error;
|
|
74
|
+
} finally {
|
|
75
|
+
reader?.releaseLock();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
5
79
|
//#region src/nodeinfo/client.ts
|
|
6
80
|
const logger = getLogger([
|
|
7
81
|
"fedify",
|
|
@@ -82,7 +156,7 @@ async function getNodeInfo(url, options = {}) {
|
|
|
82
156
|
});
|
|
83
157
|
return;
|
|
84
158
|
}
|
|
85
|
-
const wellKnownRd = await wellKnownResponse
|
|
159
|
+
const wellKnownRd = JSON.parse(await readBoundedText(wellKnownResponse, MAX_BODY_SIZE, wellKnownUrl));
|
|
86
160
|
const link = wellKnownRd?.links?.find((link) => link != null && "rel" in link && (link.rel === "http://nodeinfo.diaspora.software/ns/schema/2.0" || link.rel === "http://nodeinfo.diaspora.software/ns/schema/2.1") && "href" in link && link.href != null);
|
|
87
161
|
if (link == null || link.href == null) {
|
|
88
162
|
logger.error("Failed to find a NodeInfo document link from {url}: {resourceDescriptor}", {
|
|
@@ -106,7 +180,7 @@ async function getNodeInfo(url, options = {}) {
|
|
|
106
180
|
});
|
|
107
181
|
return;
|
|
108
182
|
}
|
|
109
|
-
const data = await response
|
|
183
|
+
const data = JSON.parse(await readBoundedText(response, MAX_BODY_SIZE, nodeInfoUrl));
|
|
110
184
|
if (options.parse === "none") return data;
|
|
111
185
|
return parseNodeInfo(data, { tryBestEffort: options.parse === "best-effort" }) ?? void 0;
|
|
112
186
|
} catch (error) {
|
|
@@ -352,4 +426,4 @@ function nodeInfoToJson(nodeInfo) {
|
|
|
352
426
|
};
|
|
353
427
|
}
|
|
354
428
|
//#endregion
|
|
355
|
-
export { getNodeInfo as n, parseNodeInfo as r, nodeInfoToJson as t };
|
|
429
|
+
export { MAX_BODY_SIZE as a, BodyTooLargeError as i, getNodeInfo as n, readBoundedText as o, parseNodeInfo as r, nodeInfoToJson as t };
|
|
@@ -5,11 +5,11 @@ import { t as esm_default } from "../esm-vrlUxr60.mjs";
|
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-C-ZRDbaf.mjs";
|
|
6
6
|
import "../std__assert-BBjXFNOb.mjs";
|
|
7
7
|
import { t as assertRejects } from "../assert_rejects-DN60FHPX.mjs";
|
|
8
|
-
import { l as verifyRequest } from "../http-
|
|
9
|
-
import { i as rsaPrivateKey2 } from "../keys-
|
|
10
|
-
import { t as getAuthenticatedDocumentLoader } from "../docloader-
|
|
8
|
+
import { l as verifyRequest } from "../http-B2u6PvNX.mjs";
|
|
9
|
+
import { i as rsaPrivateKey2 } from "../keys-BAK-tUlf.mjs";
|
|
10
|
+
import { t as getAuthenticatedDocumentLoader } from "../docloader-C-JrNL14.mjs";
|
|
11
11
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
12
|
-
import { UrlError } from "@fedify/vocab-runtime";
|
|
12
|
+
import { FetchError, UrlError } from "@fedify/vocab-runtime";
|
|
13
13
|
//#region src/utils/docloader.test.ts
|
|
14
14
|
test("getAuthenticatedDocumentLoader()", async (t) => {
|
|
15
15
|
esm_default.spyGlobal();
|
|
@@ -136,5 +136,29 @@ test("getAuthenticatedDocumentLoader() cancellation", {
|
|
|
136
136
|
});
|
|
137
137
|
esm_default.hardReset();
|
|
138
138
|
});
|
|
139
|
+
test("getAuthenticatedDocumentLoader() bounds JSON after redirects", async () => {
|
|
140
|
+
esm_default.mockGlobal();
|
|
141
|
+
let oversized = true;
|
|
142
|
+
try {
|
|
143
|
+
const url = "https://example.com/bounded";
|
|
144
|
+
esm_default.get(url, {
|
|
145
|
+
status: 302,
|
|
146
|
+
headers: { Location: `${url}/document` }
|
|
147
|
+
});
|
|
148
|
+
esm_default.get(`${url}/document`, () => new Response("{\"name\":\"hello\"}", { headers: {
|
|
149
|
+
"Content-Type": "application/activity+json",
|
|
150
|
+
...oversized ? { "Content-Length": String(16777217) } : {}
|
|
151
|
+
} }));
|
|
152
|
+
const loader = getAuthenticatedDocumentLoader({
|
|
153
|
+
privateKey: rsaPrivateKey2,
|
|
154
|
+
keyId: new URL("https://example.com/key2")
|
|
155
|
+
}, { allowPrivateAddress: true });
|
|
156
|
+
await assertRejects(() => loader(url), FetchError);
|
|
157
|
+
oversized = false;
|
|
158
|
+
assertEquals((await loader(url)).document, { name: "hello" });
|
|
159
|
+
} finally {
|
|
160
|
+
esm_default.hardReset();
|
|
161
|
+
}
|
|
162
|
+
});
|
|
139
163
|
//#endregion
|
|
140
164
|
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-qJSjfLGm.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-C1TC_e9y.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-1TuoXkGs.cjs";
|
|
3
3
|
export { getAuthenticatedDocumentLoader, kvCache };
|
package/dist/utils/mod.d.ts
CHANGED
package/dist/utils/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 getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-
|
|
3
|
+
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-Cl1q1aA9.js";
|
|
4
4
|
export { getAuthenticatedDocumentLoader, kvCache };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/fedify",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.9-dev.2048+c88fcc8c",
|
|
4
4
|
"description": "An ActivityPub server framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ActivityPub",
|
|
@@ -152,10 +152,10 @@
|
|
|
152
152
|
"jsonld": "^9.0.0",
|
|
153
153
|
"structured-field-values": "^2.0.4",
|
|
154
154
|
"urlpattern-polyfill": "^10.1.0",
|
|
155
|
-
"@fedify/uri-template": "2.3.
|
|
156
|
-
"@fedify/
|
|
157
|
-
"@fedify/vocab": "2.3.
|
|
158
|
-
"@fedify/
|
|
155
|
+
"@fedify/uri-template": "2.3.9-dev.2048+c88fcc8c",
|
|
156
|
+
"@fedify/webfinger": "2.3.9-dev.2048+c88fcc8c",
|
|
157
|
+
"@fedify/vocab-runtime": "2.3.9-dev.2048+c88fcc8c",
|
|
158
|
+
"@fedify/vocab": "2.3.9-dev.2048+c88fcc8c"
|
|
159
159
|
},
|
|
160
160
|
"devDependencies": {
|
|
161
161
|
"@std/assert": "npm:@jsr/std__assert@^0.226.0",
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"typescript": "^6.0.0",
|
|
169
169
|
"wrangler": "^4.17.0",
|
|
170
170
|
"@fedify/fixture": "2.0.0",
|
|
171
|
-
"@fedify/vocab-tools": "^2.3.
|
|
171
|
+
"@fedify/vocab-tools": "^2.3.9-dev.2048+c88fcc8c"
|
|
172
172
|
},
|
|
173
173
|
"scripts": {
|
|
174
174
|
"build:self": "tsdown",
|
package/dist/assert-OguE97r2.mjs
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import "@js-temporal/polyfill";
|
|
2
|
-
import "urlpattern-polyfill";
|
|
3
|
-
globalThis.addEventListener = () => {};
|
|
4
|
-
import { l as AssertionError } from "./assert_equals-C-ZRDbaf.mjs";
|
|
5
|
-
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert.js
|
|
6
|
-
/**
|
|
7
|
-
* Make an assertion, error will be thrown if `expr` does not have truthy value.
|
|
8
|
-
*
|
|
9
|
-
* @example Usage
|
|
10
|
-
* ```ts no-eval
|
|
11
|
-
* import { assert } from "@std/assert/assert";
|
|
12
|
-
*
|
|
13
|
-
* assert("hello".includes("ello")); // Doesn't throw
|
|
14
|
-
* assert("hello".includes("world")); // Throws
|
|
15
|
-
* ```
|
|
16
|
-
*
|
|
17
|
-
* @param expr The expression to test.
|
|
18
|
-
* @param msg The optional message to display if the assertion fails.
|
|
19
|
-
*/ function assert(expr, msg = "") {
|
|
20
|
-
if (!expr) throw new AssertionError(msg);
|
|
21
|
-
}
|
|
22
|
-
//#endregion
|
|
23
|
-
export { assert as t };
|
package/dist/owner-B3720pz3.mjs
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import "@js-temporal/polyfill";
|
|
2
|
-
import "urlpattern-polyfill";
|
|
3
|
-
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-CTdCdRmf.mjs";
|
|
5
|
-
import "./key-C_a6iE1-.mjs";
|
|
6
|
-
import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
|
|
7
|
-
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
8
|
-
import { getDocumentLoader } from "@fedify/vocab-runtime";
|
|
9
|
-
//#region src/sig/owner.ts
|
|
10
|
-
/**
|
|
11
|
-
* Checks if the actor of the given activity owns the specified key.
|
|
12
|
-
* @param activity The activity to check.
|
|
13
|
-
* @param key The public key to check.
|
|
14
|
-
* @param options Options for checking the key ownership.
|
|
15
|
-
* @returns Whether the actor is the owner of the key.
|
|
16
|
-
*/
|
|
17
|
-
async function doesActorOwnKey(activity, key, options) {
|
|
18
|
-
return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("activitypub.verify_key_ownership", {
|
|
19
|
-
kind: SpanKind.INTERNAL,
|
|
20
|
-
attributes: {
|
|
21
|
-
"activitypub.actor.id": activity.actorId?.href ?? "",
|
|
22
|
-
"activitypub.key.id": key.id?.href ?? ""
|
|
23
|
-
}
|
|
24
|
-
}, async (span) => {
|
|
25
|
-
try {
|
|
26
|
-
if (key.ownerId != null) {
|
|
27
|
-
const owns = key.ownerId.href === activity.actorId?.href;
|
|
28
|
-
span.setAttribute("activitypub.key_ownership.verified", owns);
|
|
29
|
-
span.setAttribute("activitypub.key_ownership.method", "owner_id");
|
|
30
|
-
return owns;
|
|
31
|
-
}
|
|
32
|
-
const actor = await activity.getActor(options);
|
|
33
|
-
if (actor == null || !isActor(actor)) {
|
|
34
|
-
span.setAttribute("activitypub.key_ownership.verified", false);
|
|
35
|
-
span.setAttribute("activitypub.key_ownership.method", "actor_fetch");
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
for (const publicKeyId of actor.publicKeyIds) if (key.id != null && publicKeyId.href === key.id.href) {
|
|
39
|
-
span.setAttribute("activitypub.key_ownership.verified", true);
|
|
40
|
-
span.setAttribute("activitypub.key_ownership.method", "actor_fetch");
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
span.setAttribute("activitypub.key_ownership.verified", false);
|
|
44
|
-
span.setAttribute("activitypub.key_ownership.method", "actor_fetch");
|
|
45
|
-
return false;
|
|
46
|
-
} catch (error) {
|
|
47
|
-
span.recordException(error);
|
|
48
|
-
span.setStatus({
|
|
49
|
-
code: SpanStatusCode.ERROR,
|
|
50
|
-
message: String(error)
|
|
51
|
-
});
|
|
52
|
-
throw error;
|
|
53
|
-
} finally {
|
|
54
|
-
span.end();
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Gets the actor that owns the specified key. Returns `null` if the key has no
|
|
60
|
-
* known owner.
|
|
61
|
-
*
|
|
62
|
-
* @param keyId The ID of the key to check, or the key itself.
|
|
63
|
-
* @param options Options for getting the key owner.
|
|
64
|
-
* @returns The actor that owns the key, or `null` if the key has no known
|
|
65
|
-
* owner.
|
|
66
|
-
* @since 0.7.0
|
|
67
|
-
*/
|
|
68
|
-
async function getKeyOwner(keyId, options) {
|
|
69
|
-
const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
|
|
70
|
-
const documentLoader = options.documentLoader ?? getDocumentLoader();
|
|
71
|
-
const contextLoader = options.contextLoader ?? getDocumentLoader();
|
|
72
|
-
let object;
|
|
73
|
-
if (keyId instanceof CryptographicKey) {
|
|
74
|
-
object = keyId;
|
|
75
|
-
if (object.id == null) return null;
|
|
76
|
-
keyId = object.id;
|
|
77
|
-
} else {
|
|
78
|
-
let keyDoc;
|
|
79
|
-
try {
|
|
80
|
-
const { document } = await documentLoader(keyId.href);
|
|
81
|
-
keyDoc = document;
|
|
82
|
-
} catch (_) {
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
try {
|
|
86
|
-
object = await Object$1.fromJsonLd(keyDoc, {
|
|
87
|
-
documentLoader,
|
|
88
|
-
contextLoader,
|
|
89
|
-
tracerProvider
|
|
90
|
-
});
|
|
91
|
-
} catch (e) {
|
|
92
|
-
if (!(e instanceof TypeError)) throw e;
|
|
93
|
-
try {
|
|
94
|
-
object = await CryptographicKey.fromJsonLd(keyDoc, {
|
|
95
|
-
documentLoader,
|
|
96
|
-
contextLoader,
|
|
97
|
-
tracerProvider
|
|
98
|
-
});
|
|
99
|
-
} catch (e) {
|
|
100
|
-
if (e instanceof TypeError) return null;
|
|
101
|
-
throw e;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
let owner = null;
|
|
106
|
-
if (object instanceof CryptographicKey) {
|
|
107
|
-
if (object.ownerId == null) return null;
|
|
108
|
-
owner = await object.getOwner({
|
|
109
|
-
documentLoader,
|
|
110
|
-
contextLoader,
|
|
111
|
-
tracerProvider
|
|
112
|
-
});
|
|
113
|
-
} else if (isActor(object)) owner = object;
|
|
114
|
-
else return null;
|
|
115
|
-
if (owner == null) return null;
|
|
116
|
-
for (const kid of owner.publicKeyIds) if (kid.href === keyId.href) return owner;
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
//#endregion
|
|
120
|
-
export { getKeyOwner as n, doesActorOwnKey as t };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/{circuit-breaker-test-utils-CAdwjgMi.mjs → circuit-breaker-test-utils-Dm5MM6l9.mjs}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|