@fedify/vocab-runtime 2.1.22 → 2.1.24

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.
Files changed (50) hide show
  1. package/deno.json +1 -1
  2. package/dist/mod.cjs +166 -101
  3. package/dist/mod.js +166 -101
  4. package/dist/tests/body-BWNGF5gy.cjs +95 -0
  5. package/dist/tests/body-D_GduSEt.mjs +77 -0
  6. package/dist/tests/body.test.cjs +90 -0
  7. package/dist/tests/body.test.d.cts +1 -0
  8. package/dist/tests/body.test.d.mts +1 -0
  9. package/dist/tests/body.test.mjs +90 -0
  10. package/dist/tests/decimal.test.cjs +6 -6
  11. package/dist/tests/decimal.test.mjs +6 -6
  12. package/dist/tests/{docloader-DTEkEfXf.mjs → docloader-BBEZYcQU.mjs} +26 -34
  13. package/dist/tests/{docloader-CsqLeLhI.cjs → docloader-CrsmzPTc.cjs} +31 -33
  14. package/dist/tests/docloader.test.cjs +83 -4
  15. package/dist/tests/docloader.test.mjs +83 -4
  16. package/dist/tests/internal/multicodec.test.cjs +2 -2
  17. package/dist/tests/internal/multicodec.test.mjs +2 -2
  18. package/dist/tests/{key-BeTHFQJK.mjs → key-BDIsC6hV.mjs} +2 -2
  19. package/dist/tests/{key-DTTIntwb.cjs → key-BarKGLQz.cjs} +2 -2
  20. package/dist/tests/key.test.cjs +3 -3
  21. package/dist/tests/key.test.mjs +3 -3
  22. package/dist/tests/langstr.test.cjs +2 -2
  23. package/dist/tests/langstr.test.mjs +2 -2
  24. package/dist/tests/link.test.cjs +2 -2
  25. package/dist/tests/link.test.mjs +2 -2
  26. package/dist/tests/multibase/multibase.test.cjs +2 -2
  27. package/dist/tests/multibase/multibase.test.mjs +2 -2
  28. package/dist/tests/{request-W5ez4835.mjs → request-CbVzw-Ce.mjs} +1 -1
  29. package/dist/tests/{request-0j5qU0qi.cjs → request-xQEQeUO1.cjs} +1 -1
  30. package/dist/tests/request.test.cjs +2 -2
  31. package/dist/tests/request.test.mjs +2 -2
  32. package/dist/tests/temporal.test.cjs +1 -1
  33. package/dist/tests/temporal.test.mjs +1 -1
  34. package/dist/tests/url.test.cjs +2 -2
  35. package/dist/tests/url.test.mjs +2 -2
  36. package/package.json +1 -1
  37. package/src/body.test.ts +125 -0
  38. package/src/body.ts +95 -0
  39. package/src/docloader.test.ts +124 -1
  40. package/src/docloader.ts +41 -43
  41. /package/dist/tests/{langstr-CbAxaeEZ.cjs → langstr-BOQHfJDr.cjs} +0 -0
  42. /package/dist/tests/{langstr-Di5AvKpB.mjs → langstr-DDLc4833.mjs} +0 -0
  43. /package/dist/tests/{link-NUUWCdnK.mjs → link-CYszIegt.mjs} +0 -0
  44. /package/dist/tests/{link-FguCydMA.cjs → link-qDTmjPw_.cjs} +0 -0
  45. /package/dist/tests/{multibase-F7LtMMsK.cjs → multibase-8zhYPa7o.cjs} +0 -0
  46. /package/dist/tests/{multibase-BgU9XRf7.mjs → multibase-Ds75BvXs.mjs} +0 -0
  47. /package/dist/tests/{multicodec-CyFp54fI.mjs → multicodec-BBPZjRfg.mjs} +0 -0
  48. /package/dist/tests/{multicodec-CxGVGa91.cjs → multicodec-ByS9XLsw.cjs} +0 -0
  49. /package/dist/tests/{url-o0e-aXQY.mjs → url-BBfduh6o.mjs} +0 -0
  50. /package/dist/tests/{url-CWU5HT3Y.cjs → url-CnyF489g.cjs} +0 -0
package/src/docloader.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { getLogger } from "@logtape/logtape";
2
2
  import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
3
3
  import metadata from "../deno.json" with { type: "json" };
4
+ import { MAX_BODY_SIZE, readBoundedText } from "./body.ts";
4
5
  import preloadedContexts from "./contexts.ts";
5
6
  import { HttpHeaderLink } from "./link.ts";
6
7
  import {
@@ -195,55 +196,52 @@ export async function getRemoteDocument(
195
196
  ) {
196
197
  // Security: Limit HTML response size to mitigate ReDoS attacks
197
198
  const MAX_HTML_SIZE = 1024 * 1024; // 1MB
198
- const html = await response.text();
199
- if (html.length > MAX_HTML_SIZE) {
200
- logger.warn(
201
- "HTML response too large, skipping alternate link discovery: {url}",
202
- { url: documentUrl, size: html.length },
203
- );
204
- document = JSON.parse(html);
205
- } else {
206
- // Safe regex patterns without nested quantifiers to prevent ReDoS
207
- // (CVE-2025-68475)
208
- // Step 1: Extract <a ...> or <link ...> tags
209
- const tagPattern = /<(a|link)\s+([^>]*?)\s*\/?>/gi;
210
- // Step 2: Parse attributes
211
- const attrPattern =
212
- /([a-z][a-z:_-]*)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
199
+ const html = await readBoundedText(
200
+ response,
201
+ MAX_HTML_SIZE,
202
+ documentUrl,
203
+ );
204
+ // Safe regex patterns without nested quantifiers to prevent ReDoS
205
+ // (CVE-2025-68475)
206
+ // Step 1: Extract <a ...> or <link ...> tags
207
+ const tagPattern = /<(a|link)\s+([^>]*?)\s*\/?>/gi;
208
+ // Step 2: Parse attributes
209
+ const attrPattern = /([a-z][a-z:_-]*)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
213
210
 
214
- let tagMatch: RegExpExecArray | null;
215
- while ((tagMatch = tagPattern.exec(html)) !== null) {
216
- const tagContent = tagMatch[2];
217
- let attrMatch: RegExpExecArray | null;
218
- const attribs: Record<string, string> = {};
211
+ let tagMatch: RegExpExecArray | null;
212
+ while ((tagMatch = tagPattern.exec(html)) !== null) {
213
+ const tagContent = tagMatch[2];
214
+ let attrMatch: RegExpExecArray | null;
215
+ const attribs: Record<string, string> = {};
219
216
 
220
- // Reset regex state for attribute parsing
221
- attrPattern.lastIndex = 0;
222
- while ((attrMatch = attrPattern.exec(tagContent)) !== null) {
223
- const key = attrMatch[1].toLowerCase();
224
- const value = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
225
- attribs[key] = value;
226
- }
217
+ // Reset regex state for attribute parsing
218
+ attrPattern.lastIndex = 0;
219
+ while ((attrMatch = attrPattern.exec(tagContent)) !== null) {
220
+ const key = attrMatch[1].toLowerCase();
221
+ const value = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
222
+ attribs[key] = value;
223
+ }
227
224
 
228
- if (
229
- attribs.rel === "alternate" && "type" in attribs && (
230
- attribs.type === "application/activity+json" ||
231
- attribs.type === "application/ld+json" ||
232
- attribs.type.startsWith("application/ld+json;")
233
- ) && "href" in attribs &&
234
- new URL(attribs.href, docUrl).href !== docUrl.href
235
- ) {
236
- logger.debug(
237
- "Found alternate document: {alternateUrl} from {url}",
238
- { alternateUrl: attribs.href, url: documentUrl },
239
- );
240
- return await fetch(new URL(attribs.href, docUrl).href);
241
- }
225
+ if (
226
+ attribs.rel === "alternate" && "type" in attribs && (
227
+ attribs.type === "application/activity+json" ||
228
+ attribs.type === "application/ld+json" ||
229
+ attribs.type.startsWith("application/ld+json;")
230
+ ) && "href" in attribs &&
231
+ new URL(attribs.href, docUrl).href !== docUrl.href
232
+ ) {
233
+ logger.debug(
234
+ "Found alternate document: {alternateUrl} from {url}",
235
+ { alternateUrl: attribs.href, url: documentUrl },
236
+ );
237
+ return await fetch(new URL(attribs.href, docUrl).href);
242
238
  }
243
- document = JSON.parse(html);
244
239
  }
240
+ document = JSON.parse(html);
245
241
  } else {
246
- document = await response.json();
242
+ document = JSON.parse(
243
+ await readBoundedText(response, MAX_BODY_SIZE, documentUrl),
244
+ );
247
245
  }
248
246
  logger.debug(
249
247
  "Fetched document: {status} {url} {headers}",