@fedify/vocab-runtime 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.
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-C0gO8fmt.cjs +95 -0
  5. package/dist/tests/body-DYKjs6_2.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-DI-3ZVtd.mjs → docloader-B3cffcK1.mjs} +26 -34
  13. package/dist/tests/{docloader-hPeotBri.cjs → docloader-BqznqaJT.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-pMmqUKuo.cjs → key-CWDxavIR.cjs} +2 -2
  19. package/dist/tests/{key-CrrK9mYh.mjs → key-Qj7u1qmH.mjs} +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-Cj1FlU8G.cjs → request-4o-Cs0CR.cjs} +1 -1
  29. package/dist/tests/{request-BMbeYb8u.mjs → request-89V7ieWl.mjs} +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-Bz_UUDtL.cjs → multibase-BL45eko3.cjs} +0 -0
  46. /package/dist/tests/{multibase-B4bvakyA.mjs → multibase-Da9VJCw8.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-BF_Nb_Cu.cjs → url-BbEC9H_R.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 {
@@ -202,55 +203,52 @@ export async function getRemoteDocument(
202
203
  ) {
203
204
  // Security: Limit HTML response size to mitigate ReDoS attacks
204
205
  const MAX_HTML_SIZE = 1024 * 1024; // 1MB
205
- const html = await response.text();
206
- if (html.length > MAX_HTML_SIZE) {
207
- logger.warn(
208
- "HTML response too large, skipping alternate link discovery: {url}",
209
- { url: documentUrl, size: html.length },
210
- );
211
- document = JSON.parse(html);
212
- } else {
213
- // Safe regex patterns without nested quantifiers to prevent ReDoS
214
- // (CVE-2025-68475)
215
- // Step 1: Extract <a ...> or <link ...> tags
216
- const tagPattern = /<(a|link)\s+([^>]*?)\s*\/?>/gi;
217
- // Step 2: Parse attributes
218
- const attrPattern =
219
- /([a-z][a-z:_-]*)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
206
+ const html = await readBoundedText(
207
+ response,
208
+ MAX_HTML_SIZE,
209
+ documentUrl,
210
+ );
211
+ // Safe regex patterns without nested quantifiers to prevent ReDoS
212
+ // (CVE-2025-68475)
213
+ // Step 1: Extract <a ...> or <link ...> tags
214
+ const tagPattern = /<(a|link)\s+([^>]*?)\s*\/?>/gi;
215
+ // Step 2: Parse attributes
216
+ const attrPattern = /([a-z][a-z:_-]*)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi;
220
217
 
221
- let tagMatch: RegExpExecArray | null;
222
- while ((tagMatch = tagPattern.exec(html)) !== null) {
223
- const tagContent = tagMatch[2];
224
- let attrMatch: RegExpExecArray | null;
225
- const attribs: Record<string, string> = {};
218
+ let tagMatch: RegExpExecArray | null;
219
+ while ((tagMatch = tagPattern.exec(html)) !== null) {
220
+ const tagContent = tagMatch[2];
221
+ let attrMatch: RegExpExecArray | null;
222
+ const attribs: Record<string, string> = {};
226
223
 
227
- // Reset regex state for attribute parsing
228
- attrPattern.lastIndex = 0;
229
- while ((attrMatch = attrPattern.exec(tagContent)) !== null) {
230
- const key = attrMatch[1].toLowerCase();
231
- const value = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
232
- attribs[key] = value;
233
- }
224
+ // Reset regex state for attribute parsing
225
+ attrPattern.lastIndex = 0;
226
+ while ((attrMatch = attrPattern.exec(tagContent)) !== null) {
227
+ const key = attrMatch[1].toLowerCase();
228
+ const value = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
229
+ attribs[key] = value;
230
+ }
234
231
 
235
- if (
236
- attribs.rel === "alternate" && "type" in attribs && (
237
- attribs.type === "application/activity+json" ||
238
- attribs.type === "application/ld+json" ||
239
- attribs.type.startsWith("application/ld+json;")
240
- ) && "href" in attribs &&
241
- new URL(attribs.href, docUrl).href !== docUrl.href
242
- ) {
243
- logger.debug(
244
- "Found alternate document: {alternateUrl} from {url}",
245
- { alternateUrl: attribs.href, url: documentUrl },
246
- );
247
- return await fetch(new URL(attribs.href, docUrl).href);
248
- }
232
+ if (
233
+ attribs.rel === "alternate" && "type" in attribs && (
234
+ attribs.type === "application/activity+json" ||
235
+ attribs.type === "application/ld+json" ||
236
+ attribs.type.startsWith("application/ld+json;")
237
+ ) && "href" in attribs &&
238
+ new URL(attribs.href, docUrl).href !== docUrl.href
239
+ ) {
240
+ logger.debug(
241
+ "Found alternate document: {alternateUrl} from {url}",
242
+ { alternateUrl: attribs.href, url: documentUrl },
243
+ );
244
+ return await fetch(new URL(attribs.href, docUrl).href);
249
245
  }
250
- document = JSON.parse(html);
251
246
  }
247
+ document = JSON.parse(html);
252
248
  } else {
253
- document = await response.json();
249
+ document = JSON.parse(
250
+ await readBoundedText(response, MAX_BODY_SIZE, documentUrl),
251
+ );
254
252
  }
255
253
  logger.debug(
256
254
  "Fetched document: {status} {url} {headers}",