@fedify/fedify 2.4.0-dev.1962 → 2.4.0-dev.1988
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-CWYQXC2W.mjs → builder-Cts78G9N.mjs} +2 -2
- package/dist/{client-CtxvmazV.mjs → client-DpnpgjyX.mjs} +78 -4
- 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-COLwHogJ.d.cts → context-BeDnDuF3.d.cts} +4 -3
- package/dist/{context-DiiCt4S7.d.ts → context-uyRUWoZQ.d.ts} +4 -3
- package/dist/{deno-CfLMX4HF.mjs → deno-BgMEefEr.mjs} +1 -1
- package/dist/{docloader-CDmmYxYb.mjs → docloader-DEYs99FZ.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +122 -4
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/keycache.test.mjs +52 -9
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +111 -15
- 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/send.test.mjs +139 -4
- 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-CIeDMHxZ.cjs → federation-DzPUG_AP.cjs} +93 -17
- package/dist/{http-6TI0tI03.d.cts → http-65PYi9jY.d.ts} +34 -2
- package/dist/{http-CdrSn2ip.d.ts → http-CP-7OdSq.d.cts} +34 -2
- package/dist/{http-DWZZicb2.js → http-CgwqtxAy.js} +169 -7
- package/dist/{http-BR190IDB.mjs → http-CtidZS_t.mjs} +3 -3
- package/dist/{http-C3kkrvAE.cjs → http-Z3anvCd-.cjs} +180 -6
- package/dist/{key-BcA-AzPp.mjs → key-Cwbg5ggV.mjs} +169 -7
- package/dist/{keycache-ZLqIfrkL.mjs → keycache-BUDHB5rY.mjs} +12 -4
- package/dist/{kv-cache-DCItgZUM.cjs → kv-cache-BM2-w-Wq.cjs} +2 -2
- package/dist/{kv-cache-5d2HgB_-.js → kv-cache-CykuL0ya.js} +2 -2
- package/dist/{kv-cache-m962_cok.mjs → kv-cache-DHiR8yTf.mjs} +1 -1
- package/dist/{ld-QpPkmUjy.mjs → ld-CzhdWyTt.mjs} +3 -3
- package/dist/{metrics-Dkyzq7ml.mjs → metrics-CrqsHP0l.mjs} +1 -1
- package/dist/{middleware-BdKtWJK1.mjs → middleware-CZpYxSKD.mjs} +1 -1
- package/dist/{middleware-BNktRUnj.js → middleware-CeCj5caM.js} +101 -25
- package/dist/{middleware-BaZ32nCi.mjs → middleware-DCpiAsZi.mjs} +34 -23
- package/dist/{mod-DypxPS9H.d.ts → mod-C0BYc0OU.d.ts} +1 -1
- package/dist/{mod-CnGLNoVw.d.cts → mod-CbKDOnCt.d.cts} +1 -1
- package/dist/{mod-CLHkCwLm.d.cts → mod-CyiSjRkk.d.cts} +1 -1
- package/dist/{mod-CSH1Ee-I.d.ts → mod-D882_Xsg.d.ts} +1 -1
- package/dist/{mod-DzRXACM5.d.ts → mod-UDwMjuHM.d.ts} +1 -1
- package/dist/{mod-BZldCEU0.d.cts → mod-x9W0d0Pk.d.cts} +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 +1 -1
- package/dist/nodeinfo/mod.cjs +1 -1
- package/dist/nodeinfo/mod.js +1 -1
- package/dist/{owner-r_waTiQj.d.cts → owner-BF0L9cMt.d.cts} +11 -0
- package/dist/{owner-DGSfntI-.d.ts → owner-BSzr5-I8.d.ts} +11 -0
- package/dist/owner-BqVXJLW8.mjs +175 -0
- package/dist/{proof-DrWB_vel.js → proof-CUghqhAf.js} +122 -65
- package/dist/{proof-CYdLcTFg.cjs → proof-DHu5zI0Z.cjs} +122 -65
- package/dist/{proof-Mov6-gSw.mjs → proof-DL8Iid3a.mjs} +14 -11
- package/dist/{send-DB1mkFKO.mjs → send-6jS4xFsX.mjs} +68 -11
- package/dist/sig/http.test.mjs +2 -2
- package/dist/sig/key.test.mjs +169 -2
- package/dist/sig/ld.test.mjs +55 -2
- 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 +103 -4
- package/dist/sig/proof.test.mjs +143 -2
- package/dist/{temporal-Yi0JAV9z.mjs → temporal-DcyzeytP.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- package/dist/testing/mod.d.mts +2 -1
- package/dist/{types-RXm5YxpC.cjs → types-Be2zbyeG.cjs} +94 -2
- package/dist/{types-Dtyf8lVj.js → types-C_cNlNVK.js} +78 -4
- package/dist/utils/docloader.test.mjs +27 -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/package.json +7 -7
- package/dist/owner-B795xXwU.mjs +0 -120
|
@@ -1,6 +1,80 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
2
|
let _logtape_logtape = require("@logtape/logtape");
|
|
3
3
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
4
|
+
//#region src/utils/body.ts
|
|
5
|
+
/** Decoded JSON body limit: 16 MiB. @internal */
|
|
6
|
+
const MAX_BODY_SIZE = 16 * 1024 * 1024;
|
|
7
|
+
/** A body exceeded the byte limit. @internal */
|
|
8
|
+
var BodyTooLargeError = class extends _fedify_vocab_runtime.FetchError {
|
|
9
|
+
/** Creates an error for a body exceeding the given limit. */
|
|
10
|
+
constructor(url, maxBytes) {
|
|
11
|
+
super(url, `Body exceeds the limit of ${maxBytes} bytes`);
|
|
12
|
+
this.name = "BodyTooLargeError";
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
/** Validates a finite, positive byte limit. @internal */
|
|
16
|
+
function validateBodySizeLimit(maxBytes) {
|
|
17
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) throw new RangeError("The body size limit must be a positive safe integer.");
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Reads UTF-8 text while limiting bytes received from the body stream.
|
|
21
|
+
* Fetch responses are already decompressed, so the stream count is authoritative.
|
|
22
|
+
* @param message The response or request to read.
|
|
23
|
+
* @param maxBytes The maximum number of decoded bytes to read.
|
|
24
|
+
* @param url The URL to include in errors and logs.
|
|
25
|
+
* @returns The decoded body text.
|
|
26
|
+
* @throws {BodyTooLargeError} If the body exceeds the limit.
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
async function readBoundedText(message, maxBytes, url) {
|
|
30
|
+
validateBodySizeLimit(maxBytes);
|
|
31
|
+
const reader = message.body?.getReader();
|
|
32
|
+
const tooLarge = () => {
|
|
33
|
+
(0, _logtape_logtape.getLogger)([
|
|
34
|
+
"fedify",
|
|
35
|
+
"runtime",
|
|
36
|
+
"body"
|
|
37
|
+
]).warn("Body from {url} exceeds the limit of {maxBytes} bytes.", {
|
|
38
|
+
url: url.toString(),
|
|
39
|
+
maxBytes
|
|
40
|
+
});
|
|
41
|
+
throw new BodyTooLargeError(url, maxBytes);
|
|
42
|
+
};
|
|
43
|
+
try {
|
|
44
|
+
const length = message.headers.get("Content-Length");
|
|
45
|
+
const encoding = message.headers.get("Content-Encoding");
|
|
46
|
+
if ((encoding == null || encoding.toLowerCase() === "identity") && length != null && /^\d+$/.test(length) && Number(length) > maxBytes) tooLarge();
|
|
47
|
+
if (reader == null) return "";
|
|
48
|
+
let size = 0;
|
|
49
|
+
const textReader = new ReadableStream({ async pull(controller) {
|
|
50
|
+
const { done, value } = await reader.read();
|
|
51
|
+
if (done) {
|
|
52
|
+
controller.close();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
size += value.byteLength;
|
|
56
|
+
if (size > maxBytes) tooLarge();
|
|
57
|
+
controller.enqueue(value);
|
|
58
|
+
} }, { highWaterMark: 0 }).pipeThrough(new TextDecoderStream()).getReader();
|
|
59
|
+
try {
|
|
60
|
+
const chunks = [];
|
|
61
|
+
while (true) {
|
|
62
|
+
const { done, value } = await textReader.read();
|
|
63
|
+
if (done) break;
|
|
64
|
+
chunks.push(value);
|
|
65
|
+
}
|
|
66
|
+
return chunks.join("");
|
|
67
|
+
} finally {
|
|
68
|
+
textReader.releaseLock();
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (reader != null) reader.cancel(error).catch(() => {});
|
|
72
|
+
throw error;
|
|
73
|
+
} finally {
|
|
74
|
+
reader?.releaseLock();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
4
78
|
//#region src/nodeinfo/client.ts
|
|
5
79
|
const logger = (0, _logtape_logtape.getLogger)([
|
|
6
80
|
"fedify",
|
|
@@ -81,7 +155,7 @@ async function getNodeInfo(url, options = {}) {
|
|
|
81
155
|
});
|
|
82
156
|
return;
|
|
83
157
|
}
|
|
84
|
-
const wellKnownRd = await wellKnownResponse
|
|
158
|
+
const wellKnownRd = JSON.parse(await readBoundedText(wellKnownResponse, MAX_BODY_SIZE, wellKnownUrl));
|
|
85
159
|
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);
|
|
86
160
|
if (link == null || link.href == null) {
|
|
87
161
|
logger.error("Failed to find a NodeInfo document link from {url}: {resourceDescriptor}", {
|
|
@@ -105,7 +179,7 @@ async function getNodeInfo(url, options = {}) {
|
|
|
105
179
|
});
|
|
106
180
|
return;
|
|
107
181
|
}
|
|
108
|
-
const data = await response
|
|
182
|
+
const data = JSON.parse(await readBoundedText(response, MAX_BODY_SIZE, nodeInfoUrl));
|
|
109
183
|
if (options.parse === "none") return data;
|
|
110
184
|
return parseNodeInfo(data, { tryBestEffort: options.parse === "best-effort" }) ?? void 0;
|
|
111
185
|
} catch (error) {
|
|
@@ -351,6 +425,18 @@ function nodeInfoToJson(nodeInfo) {
|
|
|
351
425
|
};
|
|
352
426
|
}
|
|
353
427
|
//#endregion
|
|
428
|
+
Object.defineProperty(exports, "BodyTooLargeError", {
|
|
429
|
+
enumerable: true,
|
|
430
|
+
get: function() {
|
|
431
|
+
return BodyTooLargeError;
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
Object.defineProperty(exports, "MAX_BODY_SIZE", {
|
|
435
|
+
enumerable: true,
|
|
436
|
+
get: function() {
|
|
437
|
+
return MAX_BODY_SIZE;
|
|
438
|
+
}
|
|
439
|
+
});
|
|
354
440
|
Object.defineProperty(exports, "getNodeInfo", {
|
|
355
441
|
enumerable: true,
|
|
356
442
|
get: function() {
|
|
@@ -369,3 +455,9 @@ Object.defineProperty(exports, "parseNodeInfo", {
|
|
|
369
455
|
return parseNodeInfo;
|
|
370
456
|
}
|
|
371
457
|
});
|
|
458
|
+
Object.defineProperty(exports, "readBoundedText", {
|
|
459
|
+
enumerable: true,
|
|
460
|
+
get: function() {
|
|
461
|
+
return readBoundedText;
|
|
462
|
+
}
|
|
463
|
+
});
|
|
@@ -1,7 +1,81 @@
|
|
|
1
1
|
import { Temporal } from "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-BHXXx4Wx.mjs";
|
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-CBlRfA-_.mjs";
|
|
6
6
|
import "../std__assert-CxFT0MNt.mjs";
|
|
7
7
|
import { t as assertRejects } from "../assert_rejects-wFbSPn1O.mjs";
|
|
8
|
-
import { l as verifyRequest } from "../http-
|
|
8
|
+
import { l as verifyRequest } from "../http-CtidZS_t.mjs";
|
|
9
9
|
import { i as rsaPrivateKey2 } from "../keys-DIJNHW-Y.mjs";
|
|
10
|
-
import { t as getAuthenticatedDocumentLoader } from "../docloader-
|
|
10
|
+
import { t as getAuthenticatedDocumentLoader } from "../docloader-DEYs99FZ.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 "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-DHiR8yTf.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,5 +1,5 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const require_kv_cache = require("../kv-cache-
|
|
3
|
+
const require_kv_cache = require("../kv-cache-BM2-w-Wq.cjs");
|
|
4
4
|
exports.getAuthenticatedDocumentLoader = require_kv_cache.getAuthenticatedDocumentLoader;
|
|
5
5
|
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-CyiSjRkk.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 "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-CykuL0ya.js";
|
|
4
4
|
export { getAuthenticatedDocumentLoader, kvCache };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/fedify",
|
|
3
|
-
"version": "2.4.0-dev.
|
|
3
|
+
"version": "2.4.0-dev.1988+c5c9d617",
|
|
4
4
|
"description": "An ActivityPub server framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ActivityPub",
|
|
@@ -151,10 +151,10 @@
|
|
|
151
151
|
"structured-field-values": "^2.0.4",
|
|
152
152
|
"temporal-polyfill": "^1.0.1",
|
|
153
153
|
"urlpattern-polyfill": "^10.1.0",
|
|
154
|
-
"@fedify/uri-template": "2.4.0-dev.
|
|
155
|
-
"@fedify/vocab": "2.4.0-dev.
|
|
156
|
-
"@fedify/vocab-runtime": "2.4.0-dev.
|
|
157
|
-
"@fedify/webfinger": "2.4.0-dev.
|
|
154
|
+
"@fedify/uri-template": "2.4.0-dev.1988+c5c9d617",
|
|
155
|
+
"@fedify/vocab": "2.4.0-dev.1988+c5c9d617",
|
|
156
|
+
"@fedify/vocab-runtime": "2.4.0-dev.1988+c5c9d617",
|
|
157
|
+
"@fedify/webfinger": "2.4.0-dev.1988+c5c9d617"
|
|
158
158
|
},
|
|
159
159
|
"devDependencies": {
|
|
160
160
|
"@std/assert": "npm:@jsr/std__assert@^0.226.0",
|
|
@@ -166,8 +166,8 @@
|
|
|
166
166
|
"tsx": "^4.21.0",
|
|
167
167
|
"typescript": "^6.0.0",
|
|
168
168
|
"wrangler": "^4.17.0",
|
|
169
|
-
"@fedify/
|
|
170
|
-
"@fedify/
|
|
169
|
+
"@fedify/fixture": "2.0.0",
|
|
170
|
+
"@fedify/vocab-tools": "^2.4.0-dev.1988+c5c9d617"
|
|
171
171
|
},
|
|
172
172
|
"scripts": {
|
|
173
173
|
"build:self": "tsdown",
|
package/dist/owner-B795xXwU.mjs
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import "temporal-polyfill";
|
|
2
|
-
import "urlpattern-polyfill";
|
|
3
|
-
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-CfLMX4HF.mjs";
|
|
5
|
-
import "./key-BcA-AzPp.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 };
|