@fedify/vocab-runtime 2.0.33 → 2.0.34-dev.2423

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/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/vocab-runtime",
3
- "version": "2.0.33",
3
+ "version": "2.0.34-dev.2423+4999dc80",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./src/mod.ts",
package/dist/mod.cjs CHANGED
@@ -4504,7 +4504,7 @@ const preloadedContexts = {
4504
4504
  //#endregion
4505
4505
  //#region deno.json
4506
4506
  var name = "@fedify/vocab-runtime";
4507
- var version = "2.0.33";
4507
+ var version = "2.0.34-dev.2423+4999dc80";
4508
4508
  //#endregion
4509
4509
  //#region src/request.ts
4510
4510
  /**
@@ -5160,6 +5160,7 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
5160
5160
  options?.signal?.throwIfAborted();
5161
5161
  const parsedUrl = new URL(url);
5162
5162
  if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") throw new UrlError(`Unsupported protocol: ${parsedUrl.protocol}`);
5163
+ if (parsedUrl.username !== "" || parsedUrl.password !== "") throw new UrlError("URLs with credentials are not allowed");
5163
5164
  const currentUrl = parsedUrl.href;
5164
5165
  if (!skipPreloadedContexts && currentUrl in preloadedContexts) {
5165
5166
  logger.debug("Using preloaded context: {url}.", { url: currentUrl });
package/dist/mod.js CHANGED
@@ -4499,7 +4499,7 @@ const preloadedContexts = {
4499
4499
  //#endregion
4500
4500
  //#region deno.json
4501
4501
  var name = "@fedify/vocab-runtime";
4502
- var version = "2.0.33";
4502
+ var version = "2.0.34-dev.2423+4999dc80";
4503
4503
  //#endregion
4504
4504
  //#region src/request.ts
4505
4505
  /**
@@ -5155,6 +5155,7 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
5155
5155
  options?.signal?.throwIfAborted();
5156
5156
  const parsedUrl = new URL(url);
5157
5157
  if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") throw new UrlError(`Unsupported protocol: ${parsedUrl.protocol}`);
5158
+ if (parsedUrl.username !== "" || parsedUrl.password !== "") throw new UrlError("URLs with credentials are not allowed");
5158
5159
  const currentUrl = parsedUrl.href;
5159
5160
  if (!skipPreloadedContexts && currentUrl in preloadedContexts) {
5160
5161
  logger.debug("Using preloaded context: {url}.", { url: currentUrl });
@@ -1,5 +1,5 @@
1
1
  require("./chunk-Do9eywBl.cjs");
2
- const require_request = require("./request-BhX093Vd.cjs");
2
+ const require_request = require("./request-Ds0hJGeF.cjs");
3
3
  let _logtape_logtape = require("@logtape/logtape");
4
4
  //#region src/body.ts
5
5
  /** Decoded JSON body limit: 16 MiB. @internal */
@@ -1,4 +1,4 @@
1
- import { t as FetchError } from "./request-zvoIOWWs.mjs";
1
+ import { t as FetchError } from "./request-BS9N4kB1.mjs";
2
2
  import { getLogger } from "@logtape/logtape";
3
3
  //#region src/body.ts
4
4
  /** Decoded JSON body limit: 16 MiB. @internal */
@@ -1,5 +1,5 @@
1
1
  require("./chunk-Do9eywBl.cjs");
2
- const require_body = require("./body-Cjg7OBhe.cjs");
2
+ const require_body = require("./body-Bf3IUKB-.cjs");
3
3
  let node_assert_strict = require("node:assert/strict");
4
4
  let node_test = require("node:test");
5
5
  let node_zlib = require("node:zlib");
@@ -1,4 +1,4 @@
1
- import { r as readBoundedText, t as BodyTooLargeError } from "./body-CKUDh6i2.mjs";
1
+ import { r as readBoundedText, t as BodyTooLargeError } from "./body-M8IeUMdL.mjs";
2
2
  import { deepStrictEqual, ok, rejects } from "node:assert/strict";
3
3
  import { test } from "node:test";
4
4
  import { gunzipSync, gzipSync } from "node:zlib";
@@ -1,6 +1,6 @@
1
1
  const require_chunk = require("./chunk-Do9eywBl.cjs");
2
- const require_request = require("./request-BhX093Vd.cjs");
3
- const require_body = require("./body-Cjg7OBhe.cjs");
2
+ const require_request = require("./request-Ds0hJGeF.cjs");
3
+ const require_body = require("./body-Bf3IUKB-.cjs");
4
4
  const require_link = require("./link-FguCydMA.cjs");
5
5
  const require_url = require("./url-Qk1svKZU.cjs");
6
6
  let node_zlib = require("node:zlib");
@@ -5826,6 +5826,7 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
5826
5826
  options?.signal?.throwIfAborted();
5827
5827
  const parsedUrl = new URL(url);
5828
5828
  if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") throw new require_url.UrlError(`Unsupported protocol: ${parsedUrl.protocol}`);
5829
+ if (parsedUrl.username !== "" || parsedUrl.password !== "") throw new require_url.UrlError("URLs with credentials are not allowed");
5829
5830
  const currentUrl = parsedUrl.href;
5830
5831
  if (!skipPreloadedContexts && currentUrl in preloadedContexts) {
5831
5832
  logger.debug("Using preloaded context: {url}.", { url: currentUrl });
@@ -6696,6 +6697,52 @@ const unsupportedUrls = [
6696
6697
  "file:///collection",
6697
6698
  `data:application/ld+json,${encodeURIComponent(JSON.stringify({ id: "https://example.com/data" }))}`
6698
6699
  ];
6700
+ function isCredentialUrlError(error) {
6701
+ return error instanceof require_url.UrlError && error.reason === "disallowed" && error.message === "URLs with credentials are not allowed";
6702
+ }
6703
+ (0, _fedify_fixture.test)("getDocumentLoader() rejects URLs with credentials", async (t) => {
6704
+ const start = "https://8.8.8.8/start";
6705
+ const target = "https://user:pass@8.8.8.8/document";
6706
+ for (const allowPrivateAddress of [false, true]) {
6707
+ const loader = getDocumentLoader({ allowPrivateAddress });
6708
+ for (const path of [
6709
+ "direct",
6710
+ "redirect",
6711
+ "Link",
6712
+ "HTML"
6713
+ ]) await t.step(`${path}, allowPrivateAddress=${allowPrivateAddress}`, async () => {
6714
+ await withFetchStub((url) => {
6715
+ if (url !== start) return Response.json({});
6716
+ if (path === "redirect") return Response.redirect(target, 302);
6717
+ if (path === "HTML") return new Response(`<link rel="alternate" type="application/activity+json" href="${target}">`, { headers: { "Content-Type": "text/html" } });
6718
+ return new Response("", { headers: {
6719
+ "Content-Type": "text/plain",
6720
+ Link: `<${target}>; rel="alternate"; type="application/activity+json"`
6721
+ } });
6722
+ }, async (fetched) => {
6723
+ await (0, node_assert.rejects)(loader(path === "direct" ? target : start), isCredentialUrlError);
6724
+ (0, node_assert.deepStrictEqual)(fetched, path === "direct" ? [] : [start]);
6725
+ });
6726
+ });
6727
+ for (const url of [
6728
+ "https://user@8.8.8.8/document",
6729
+ "https://:pass@8.8.8.8/document",
6730
+ "https://%75ser:p%40ss@8.8.8.8/document",
6731
+ "http://user:pass@8.8.8.8/document"
6732
+ ]) await t.step(`${url}, allowPrivateAddress=${allowPrivateAddress}`, async () => {
6733
+ await withFetchStub(() => Response.json({}), async (fetched) => {
6734
+ await (0, node_assert.rejects)(loader(url), isCredentialUrlError);
6735
+ (0, node_assert.deepStrictEqual)(fetched, []);
6736
+ });
6737
+ });
6738
+ for (const url of ["https://:@8.8.8.8/document", "https://8.8.8.8/@user?q=@pass"]) await t.step(`allows ${url}, allowPrivateAddress=${allowPrivateAddress}`, async () => {
6739
+ await withFetchStub(() => Response.json({ done: true }), async (fetched) => {
6740
+ (0, node_assert.deepStrictEqual)((await loader(url)).document, { done: true });
6741
+ (0, node_assert.deepStrictEqual)(fetched, [new URL(url).href]);
6742
+ });
6743
+ });
6744
+ }
6745
+ });
6699
6746
  function isUnsupportedProtocolError(error, url) {
6700
6747
  return error instanceof require_url.UrlError && error.message === `Unsupported protocol: ${new URL(url).protocol}` && error.reason === "disallowed";
6701
6748
  }
@@ -1,5 +1,5 @@
1
- import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-zvoIOWWs.mjs";
2
- import { n as MAX_BODY_SIZE, r as readBoundedText } from "./body-CKUDh6i2.mjs";
1
+ import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-BS9N4kB1.mjs";
2
+ import { n as MAX_BODY_SIZE, r as readBoundedText } from "./body-M8IeUMdL.mjs";
3
3
  import { t as HttpHeaderLink } from "./link-NUUWCdnK.mjs";
4
4
  import { o as validatePublicUrl, t as UrlError } from "./url-DzlMS01z.mjs";
5
5
  import { gzipSync } from "node:zlib";
@@ -5843,6 +5843,7 @@ function getDocumentLoader({ allowPrivateAddress, skipPreloadedContexts, userAge
5843
5843
  options?.signal?.throwIfAborted();
5844
5844
  const parsedUrl = new URL(url);
5845
5845
  if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") throw new UrlError(`Unsupported protocol: ${parsedUrl.protocol}`);
5846
+ if (parsedUrl.username !== "" || parsedUrl.password !== "") throw new UrlError("URLs with credentials are not allowed");
5846
5847
  const currentUrl = parsedUrl.href;
5847
5848
  if (!skipPreloadedContexts && currentUrl in preloadedContexts) {
5848
5849
  logger.debug("Using preloaded context: {url}.", { url: currentUrl });
@@ -6713,6 +6714,52 @@ const unsupportedUrls = [
6713
6714
  "file:///collection",
6714
6715
  `data:application/ld+json,${encodeURIComponent(JSON.stringify({ id: "https://example.com/data" }))}`
6715
6716
  ];
6717
+ function isCredentialUrlError(error) {
6718
+ return error instanceof UrlError && error.reason === "disallowed" && error.message === "URLs with credentials are not allowed";
6719
+ }
6720
+ test("getDocumentLoader() rejects URLs with credentials", async (t) => {
6721
+ const start = "https://8.8.8.8/start";
6722
+ const target = "https://user:pass@8.8.8.8/document";
6723
+ for (const allowPrivateAddress of [false, true]) {
6724
+ const loader = getDocumentLoader({ allowPrivateAddress });
6725
+ for (const path of [
6726
+ "direct",
6727
+ "redirect",
6728
+ "Link",
6729
+ "HTML"
6730
+ ]) await t.step(`${path}, allowPrivateAddress=${allowPrivateAddress}`, async () => {
6731
+ await withFetchStub((url) => {
6732
+ if (url !== start) return Response.json({});
6733
+ if (path === "redirect") return Response.redirect(target, 302);
6734
+ if (path === "HTML") return new Response(`<link rel="alternate" type="application/activity+json" href="${target}">`, { headers: { "Content-Type": "text/html" } });
6735
+ return new Response("", { headers: {
6736
+ "Content-Type": "text/plain",
6737
+ Link: `<${target}>; rel="alternate"; type="application/activity+json"`
6738
+ } });
6739
+ }, async (fetched) => {
6740
+ await rejects(loader(path === "direct" ? target : start), isCredentialUrlError);
6741
+ deepStrictEqual(fetched, path === "direct" ? [] : [start]);
6742
+ });
6743
+ });
6744
+ for (const url of [
6745
+ "https://user@8.8.8.8/document",
6746
+ "https://:pass@8.8.8.8/document",
6747
+ "https://%75ser:p%40ss@8.8.8.8/document",
6748
+ "http://user:pass@8.8.8.8/document"
6749
+ ]) await t.step(`${url}, allowPrivateAddress=${allowPrivateAddress}`, async () => {
6750
+ await withFetchStub(() => Response.json({}), async (fetched) => {
6751
+ await rejects(loader(url), isCredentialUrlError);
6752
+ deepStrictEqual(fetched, []);
6753
+ });
6754
+ });
6755
+ for (const url of ["https://:@8.8.8.8/document", "https://8.8.8.8/@user?q=@pass"]) await t.step(`allows ${url}, allowPrivateAddress=${allowPrivateAddress}`, async () => {
6756
+ await withFetchStub(() => Response.json({ done: true }), async (fetched) => {
6757
+ deepStrictEqual((await loader(url)).document, { done: true });
6758
+ deepStrictEqual(fetched, [new URL(url).href]);
6759
+ });
6760
+ });
6761
+ }
6762
+ });
6716
6763
  function isUnsupportedProtocolError(error, url) {
6717
6764
  return error instanceof UrlError && error.message === `Unsupported protocol: ${new URL(url).protocol}` && error.reason === "disallowed";
6718
6765
  }
@@ -1,7 +1,7 @@
1
1
  import process from "node:process";
2
2
  //#region deno.json
3
3
  var name = "@fedify/vocab-runtime";
4
- var version = "2.0.33";
4
+ var version = "2.0.34-dev.2423+4999dc80";
5
5
  //#endregion
6
6
  //#region src/request.ts
7
7
  /**
@@ -3,7 +3,7 @@ let node_process = require("node:process");
3
3
  node_process = require_chunk.__toESM(node_process);
4
4
  //#region deno.json
5
5
  var name = "@fedify/vocab-runtime";
6
- var version = "2.0.33";
6
+ var version = "2.0.34-dev.2423+4999dc80";
7
7
  //#endregion
8
8
  //#region src/request.ts
9
9
  /**
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Do9eywBl.cjs");
2
- const require_request = require("./request-BhX093Vd.cjs");
2
+ const require_request = require("./request-Ds0hJGeF.cjs");
3
3
  let node_test = require("node:test");
4
4
  let node_process = require("node:process");
5
5
  node_process = require_chunk.__toESM(node_process);
@@ -1,4 +1,4 @@
1
- import { o as version, r as getUserAgent } from "./request-zvoIOWWs.mjs";
1
+ import { o as version, r as getUserAgent } from "./request-BS9N4kB1.mjs";
2
2
  import { test } from "node:test";
3
3
  import process from "node:process";
4
4
  import { deepStrictEqual } from "node:assert";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/vocab-runtime",
3
- "version": "2.0.33",
3
+ "version": "2.0.34-dev.2423+4999dc80",
4
4
  "homepage": "https://fedify.dev/",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1093,6 +1093,90 @@ const unsupportedUrls = [
1093
1093
  }`,
1094
1094
  ];
1095
1095
 
1096
+ function isCredentialUrlError(error: unknown): boolean {
1097
+ return error instanceof UrlError && error.reason === "disallowed" &&
1098
+ error.message === "URLs with credentials are not allowed";
1099
+ }
1100
+
1101
+ test("getDocumentLoader() rejects URLs with credentials", async (t) => {
1102
+ const start = "https://8.8.8.8/start";
1103
+ const target = "https://user:pass@8.8.8.8/document";
1104
+ for (const allowPrivateAddress of [false, true]) {
1105
+ const loader = getDocumentLoader({ allowPrivateAddress });
1106
+ for (const path of ["direct", "redirect", "Link", "HTML"]) {
1107
+ await t.step(
1108
+ `${path}, allowPrivateAddress=${allowPrivateAddress}`,
1109
+ async () => {
1110
+ await withFetchStub(
1111
+ (url) => {
1112
+ if (url !== start) return Response.json({});
1113
+ if (path === "redirect") return Response.redirect(target, 302);
1114
+ if (path === "HTML") {
1115
+ return new Response(
1116
+ `<link rel="alternate" type="application/activity+json" href="${target}">`,
1117
+ { headers: { "Content-Type": "text/html" } },
1118
+ );
1119
+ }
1120
+ return new Response("", {
1121
+ headers: {
1122
+ "Content-Type": "text/plain",
1123
+ Link:
1124
+ `<${target}>; rel="alternate"; type="application/activity+json"`,
1125
+ },
1126
+ });
1127
+ },
1128
+ async (fetched) => {
1129
+ await rejects(
1130
+ loader(path === "direct" ? target : start),
1131
+ isCredentialUrlError,
1132
+ );
1133
+ deepStrictEqual(fetched, path === "direct" ? [] : [start]);
1134
+ },
1135
+ );
1136
+ },
1137
+ );
1138
+ }
1139
+ for (
1140
+ const url of [
1141
+ "https://user@8.8.8.8/document",
1142
+ "https://:pass@8.8.8.8/document",
1143
+ "https://%75ser:p%40ss@8.8.8.8/document",
1144
+ "http://user:pass@8.8.8.8/document",
1145
+ ]
1146
+ ) {
1147
+ await t.step(
1148
+ `${url}, allowPrivateAddress=${allowPrivateAddress}`,
1149
+ async () => {
1150
+ await withFetchStub(() => Response.json({}), async (fetched) => {
1151
+ await rejects(loader(url), isCredentialUrlError);
1152
+ deepStrictEqual(fetched, []);
1153
+ });
1154
+ },
1155
+ );
1156
+ }
1157
+ for (
1158
+ const url of [
1159
+ "https://:@8.8.8.8/document",
1160
+ "https://8.8.8.8/@user?q=@pass",
1161
+ ]
1162
+ ) {
1163
+ await t.step(
1164
+ `allows ${url}, allowPrivateAddress=${allowPrivateAddress}`,
1165
+ async () => {
1166
+ await withFetchStub(
1167
+ () => Response.json({ done: true }),
1168
+ async (fetched) => {
1169
+ const document = await loader(url);
1170
+ deepStrictEqual(document.document, { done: true });
1171
+ deepStrictEqual(fetched, [new URL(url).href]);
1172
+ },
1173
+ );
1174
+ },
1175
+ );
1176
+ }
1177
+ }
1178
+ });
1179
+
1096
1180
  function isUnsupportedProtocolError(error: unknown, url: string): boolean {
1097
1181
  return error instanceof UrlError &&
1098
1182
  error.message === `Unsupported protocol: ${new URL(url).protocol}` &&
package/src/docloader.ts CHANGED
@@ -306,6 +306,11 @@ export function getDocumentLoader(
306
306
  if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
307
307
  throw new UrlError(`Unsupported protocol: ${parsedUrl.protocol}`);
308
308
  }
309
+ // When merging forward, keep this guard independent of allowPrivateAddress:
310
+ // private-address opt-in must not permit credentials on any followed URL.
311
+ if (parsedUrl.username !== "" || parsedUrl.password !== "") {
312
+ throw new UrlError("URLs with credentials are not allowed");
313
+ }
309
314
  const currentUrl = parsedUrl.href;
310
315
  if (!skipPreloadedContexts && currentUrl in preloadedContexts) {
311
316
  logger.debug("Using preloaded context: {url}.", { url: currentUrl });