elit 3.6.8 → 3.6.9

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/Cargo.lock CHANGED
@@ -1211,7 +1211,7 @@ dependencies = [
1211
1211
 
1212
1212
  [[package]]
1213
1213
  name = "elit-desktop"
1214
- version = "3.6.8"
1214
+ version = "3.6.9"
1215
1215
  dependencies = [
1216
1216
  "eframe",
1217
1217
  "http",
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "elit-desktop"
3
- version = "3.6.8"
3
+ version = "3.6.9"
4
4
  edition = "2021"
5
5
  build = "desktop/build.rs"
6
6
 
package/dist/cli.cjs CHANGED
@@ -58249,11 +58249,11 @@ function readdirp(root, options = {}) {
58249
58249
  options.root = root;
58250
58250
  return new ReaddirpStream(options);
58251
58251
  }
58252
- var import_promises, import_node_stream, import_node_path28, EntryTypes, defaultOptions3, RECURSIVE_ERROR_CODE, NORMAL_FLOW_ERRORS, ALL_TYPES, DIR_TYPES, FILE_TYPES, isNormalFlowError, wantBigintFsStats, emptyFn, normalizeFilter, ReaddirpStream;
58252
+ var import_promises2, import_node_stream, import_node_path28, EntryTypes, defaultOptions3, RECURSIVE_ERROR_CODE, NORMAL_FLOW_ERRORS, ALL_TYPES, DIR_TYPES, FILE_TYPES, isNormalFlowError, wantBigintFsStats, emptyFn, normalizeFilter, ReaddirpStream;
58253
58253
  var init_esm = __esm({
58254
58254
  "node_modules/readdirp/esm/index.js"() {
58255
58255
  "use strict";
58256
- import_promises = require("fs/promises");
58256
+ import_promises2 = require("fs/promises");
58257
58257
  import_node_stream = require("stream");
58258
58258
  import_node_path28 = require("path");
58259
58259
  EntryTypes = {
@@ -58320,7 +58320,7 @@ var init_esm = __esm({
58320
58320
  const { root, type } = opts;
58321
58321
  this._fileFilter = normalizeFilter(opts.fileFilter);
58322
58322
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
58323
- const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
58323
+ const statMethod = opts.lstat ? import_promises2.lstat : import_promises2.stat;
58324
58324
  if (wantBigintFsStats) {
58325
58325
  this._stat = (path) => statMethod(path, { bigint: true });
58326
58326
  } else {
@@ -58391,7 +58391,7 @@ var init_esm = __esm({
58391
58391
  async _exploreDir(path, depth) {
58392
58392
  let files;
58393
58393
  try {
58394
- files = await (0, import_promises.readdir)(path, this._rdOptions);
58394
+ files = await (0, import_promises2.readdir)(path, this._rdOptions);
58395
58395
  } catch (error) {
58396
58396
  this._onError(error);
58397
58397
  }
@@ -58429,8 +58429,8 @@ var init_esm = __esm({
58429
58429
  if (stats && stats.isSymbolicLink()) {
58430
58430
  const full = entry.fullPath;
58431
58431
  try {
58432
- const entryRealPath = await (0, import_promises.realpath)(full);
58433
- const entryRealPathStats = await (0, import_promises.lstat)(entryRealPath);
58432
+ const entryRealPath = await (0, import_promises2.realpath)(full);
58433
+ const entryRealPathStats = await (0, import_promises2.lstat)(entryRealPath);
58434
58434
  if (entryRealPathStats.isFile()) {
58435
58435
  return "file";
58436
58436
  }
@@ -58475,12 +58475,12 @@ function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
58475
58475
  return void 0;
58476
58476
  }
58477
58477
  }
58478
- var import_fs25, import_promises2, sysPath, import_os, STR_DATA, STR_END, STR_CLOSE, EMPTY_FN, pl, isWindows2, isMacos, isLinux, isFreeBSD, isIBMi, EVENTS, EV, THROTTLE_MODE_WATCH, statMethods, KEY_LISTENERS, KEY_ERR, KEY_RAW, HANDLER_KEYS, binaryExtensions, isBinaryPath, foreach, addAndConvert, clearItem, delFromSet, isEmptySet, FsWatchInstances, fsWatchBroadcast, setFsWatchListener, FsWatchFileInstances, setFsWatchFileListener, NodeFsHandler;
58478
+ var import_fs25, import_promises3, sysPath, import_os, STR_DATA, STR_END, STR_CLOSE, EMPTY_FN, pl, isWindows2, isMacos, isLinux, isFreeBSD, isIBMi, EVENTS, EV, THROTTLE_MODE_WATCH, statMethods, KEY_LISTENERS, KEY_ERR, KEY_RAW, HANDLER_KEYS, binaryExtensions, isBinaryPath, foreach, addAndConvert, clearItem, delFromSet, isEmptySet, FsWatchInstances, fsWatchBroadcast, setFsWatchListener, FsWatchFileInstances, setFsWatchFileListener, NodeFsHandler;
58479
58479
  var init_handler = __esm({
58480
58480
  "node_modules/chokidar/esm/handler.js"() {
58481
58481
  "use strict";
58482
58482
  import_fs25 = require("fs");
58483
- import_promises2 = require("fs/promises");
58483
+ import_promises3 = require("fs/promises");
58484
58484
  sysPath = __toESM(require("path"), 1);
58485
58485
  import_os = require("os");
58486
58486
  STR_DATA = "data";
@@ -58507,7 +58507,7 @@ var init_handler = __esm({
58507
58507
  };
58508
58508
  EV = EVENTS;
58509
58509
  THROTTLE_MODE_WATCH = "watch";
58510
- statMethods = { lstat: import_promises2.lstat, stat: import_promises2.stat };
58510
+ statMethods = { lstat: import_promises3.lstat, stat: import_promises3.stat };
58511
58511
  KEY_LISTENERS = "listeners";
58512
58512
  KEY_ERR = "errHandlers";
58513
58513
  KEY_RAW = "rawEmitters";
@@ -58847,7 +58847,7 @@ var init_handler = __esm({
58847
58847
  cont.watcherUnusable = true;
58848
58848
  if (isWindows2 && error.code === "EPERM") {
58849
58849
  try {
58850
- const fd = await (0, import_promises2.open)(path, "r");
58850
+ const fd = await (0, import_promises3.open)(path, "r");
58851
58851
  await fd.close();
58852
58852
  broadcastErr(error);
58853
58853
  } catch (err) {
@@ -58976,7 +58976,7 @@ var init_handler = __esm({
58976
58976
  return;
58977
58977
  if (!newStats || newStats.mtimeMs === 0) {
58978
58978
  try {
58979
- const newStats2 = await (0, import_promises2.stat)(file);
58979
+ const newStats2 = await (0, import_promises3.stat)(file);
58980
58980
  if (this.fsw.closed)
58981
58981
  return;
58982
58982
  const at = newStats2.atimeMs;
@@ -59031,7 +59031,7 @@ var init_handler = __esm({
59031
59031
  this.fsw._incrReadyCount();
59032
59032
  let linkPath;
59033
59033
  try {
59034
- linkPath = await (0, import_promises2.realpath)(path);
59034
+ linkPath = await (0, import_promises3.realpath)(path);
59035
59035
  } catch (e) {
59036
59036
  this.fsw._emitReady();
59037
59037
  return true;
@@ -59179,7 +59179,7 @@ var init_handler = __esm({
59179
59179
  let closer;
59180
59180
  if (stats.isDirectory()) {
59181
59181
  const absPath = sysPath.resolve(path);
59182
- const targetPath = follow ? await (0, import_promises2.realpath)(path) : path;
59182
+ const targetPath = follow ? await (0, import_promises3.realpath)(path) : path;
59183
59183
  if (this.fsw.closed)
59184
59184
  return;
59185
59185
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -59189,7 +59189,7 @@ var init_handler = __esm({
59189
59189
  this.fsw._symlinkPaths.set(absPath, targetPath);
59190
59190
  }
59191
59191
  } else if (stats.isSymbolicLink()) {
59192
- const targetPath = follow ? await (0, import_promises2.realpath)(path) : path;
59192
+ const targetPath = follow ? await (0, import_promises3.realpath)(path) : path;
59193
59193
  if (this.fsw.closed)
59194
59194
  return;
59195
59195
  const parent = sysPath.dirname(wh.watchPath);
@@ -59296,12 +59296,12 @@ function watch3(paths, options = {}) {
59296
59296
  watcher.add(paths);
59297
59297
  return watcher;
59298
59298
  }
59299
- var import_fs26, import_promises3, import_events4, sysPath2, SLASH, SLASH_SLASH, ONE_DOT, TWO_DOTS, STRING_TYPE, BACK_SLASH_RE, DOUBLE_SLASH_RE, DOT_RE, REPLACER_RE, isMatcherObject, unifyPaths, toUnix, normalizePathToUnix, normalizeIgnored, getAbsolutePath, EMPTY_SET, DirEntry, STAT_METHOD_F, STAT_METHOD_L, WatchHelper, FSWatcher2, esm_default;
59299
+ var import_fs26, import_promises4, import_events4, sysPath2, SLASH, SLASH_SLASH, ONE_DOT, TWO_DOTS, STRING_TYPE, BACK_SLASH_RE, DOUBLE_SLASH_RE, DOT_RE, REPLACER_RE, isMatcherObject, unifyPaths, toUnix, normalizePathToUnix, normalizeIgnored, getAbsolutePath, EMPTY_SET, DirEntry, STAT_METHOD_F, STAT_METHOD_L, WatchHelper, FSWatcher2, esm_default;
59300
59300
  var init_esm2 = __esm({
59301
59301
  "node_modules/chokidar/esm/index.js"() {
59302
59302
  "use strict";
59303
59303
  import_fs26 = require("fs");
59304
- import_promises3 = require("fs/promises");
59304
+ import_promises4 = require("fs/promises");
59305
59305
  import_events4 = require("events");
59306
59306
  sysPath2 = __toESM(require("path"), 1);
59307
59307
  init_esm();
@@ -59374,7 +59374,7 @@ var init_esm2 = __esm({
59374
59374
  return;
59375
59375
  const dir = this.path;
59376
59376
  try {
59377
- await (0, import_promises3.readdir)(dir);
59377
+ await (0, import_promises4.readdir)(dir);
59378
59378
  } catch (err) {
59379
59379
  if (this._removeWatcher) {
59380
59380
  this._removeWatcher(sysPath2.dirname(dir), sysPath2.basename(dir));
@@ -59699,7 +59699,7 @@ var init_esm2 = __esm({
59699
59699
  const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path) : path;
59700
59700
  let stats2;
59701
59701
  try {
59702
- stats2 = await (0, import_promises3.stat)(fullPath);
59702
+ stats2 = await (0, import_promises4.stat)(fullPath);
59703
59703
  } catch (err) {
59704
59704
  }
59705
59705
  if (!stats2 || this.closed)
@@ -81590,6 +81590,217 @@ function watch2(paths, options) {
81590
81590
  var import_node_http = require("http");
81591
81591
  var import_node_https = require("https");
81592
81592
  var import_node_net = require("net");
81593
+ var import_promises = require("dns/promises");
81594
+ var BLOCKED_IPV4_PREFIXES = [
81595
+ "0.",
81596
+ "10.",
81597
+ "100.64.",
81598
+ "100.65.",
81599
+ "100.66.",
81600
+ "100.67.",
81601
+ "100.68.",
81602
+ "100.69.",
81603
+ "100.70.",
81604
+ "100.71.",
81605
+ "100.72.",
81606
+ "100.73.",
81607
+ "100.74.",
81608
+ "100.75.",
81609
+ "100.76.",
81610
+ "100.77.",
81611
+ "100.78.",
81612
+ "100.79.",
81613
+ "100.80.",
81614
+ "100.81.",
81615
+ "100.82.",
81616
+ "100.83.",
81617
+ "100.84.",
81618
+ "100.85.",
81619
+ "100.86.",
81620
+ "100.87.",
81621
+ "100.88.",
81622
+ "100.89.",
81623
+ "100.90.",
81624
+ "100.91.",
81625
+ "100.92.",
81626
+ "100.93.",
81627
+ "100.94.",
81628
+ "100.95.",
81629
+ "100.96.",
81630
+ "100.97.",
81631
+ "100.98.",
81632
+ "100.99.",
81633
+ "100.100.",
81634
+ "100.101.",
81635
+ "100.102.",
81636
+ "100.103.",
81637
+ "100.104.",
81638
+ "100.105.",
81639
+ "100.106.",
81640
+ "100.107.",
81641
+ "100.108.",
81642
+ "100.109.",
81643
+ "100.110.",
81644
+ "100.111.",
81645
+ "100.112.",
81646
+ "100.113.",
81647
+ "100.114.",
81648
+ "100.115.",
81649
+ "100.116.",
81650
+ "100.117.",
81651
+ "100.118.",
81652
+ "100.119.",
81653
+ "100.120.",
81654
+ "100.121.",
81655
+ "100.122.",
81656
+ "100.123.",
81657
+ "100.124.",
81658
+ "100.125.",
81659
+ "100.126.",
81660
+ "100.127.",
81661
+ "127.",
81662
+ "169.254.",
81663
+ "172.16.",
81664
+ "172.17.",
81665
+ "172.18.",
81666
+ "172.19.",
81667
+ "172.20.",
81668
+ "172.21.",
81669
+ "172.22.",
81670
+ "172.23.",
81671
+ "172.24.",
81672
+ "172.25.",
81673
+ "172.26.",
81674
+ "172.27.",
81675
+ "172.28.",
81676
+ "172.29.",
81677
+ "172.30.",
81678
+ "172.31.",
81679
+ "192.0.2.",
81680
+ "192.88.99.",
81681
+ "192.168.",
81682
+ "198.18.",
81683
+ "198.19.",
81684
+ "198.51.100.",
81685
+ "203.0.113.",
81686
+ "224.",
81687
+ "225.",
81688
+ "226.",
81689
+ "227.",
81690
+ "228.",
81691
+ "229.",
81692
+ "230.",
81693
+ "231.",
81694
+ "232.",
81695
+ "233.",
81696
+ "234.",
81697
+ "235.",
81698
+ "236.",
81699
+ "237.",
81700
+ "238.",
81701
+ "239.",
81702
+ "240.",
81703
+ "241.",
81704
+ "242.",
81705
+ "243.",
81706
+ "244.",
81707
+ "245.",
81708
+ "246.",
81709
+ "247.",
81710
+ "248.",
81711
+ "249.",
81712
+ "250.",
81713
+ "251.",
81714
+ "252.",
81715
+ "253.",
81716
+ "254.",
81717
+ "255."
81718
+ ];
81719
+ var ALLOWED_PROXY_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
81720
+ function isBlockedIpv4(hostname) {
81721
+ const octets = hostname.split(".");
81722
+ if (octets.length !== 4) return false;
81723
+ const joined = hostname;
81724
+ return BLOCKED_IPV4_PREFIXES.some((prefix) => joined.startsWith(prefix));
81725
+ }
81726
+ function isBlockedIpv6(hostname) {
81727
+ const lower = hostname.toLowerCase();
81728
+ if (lower === "::1" || lower === "::" || lower === "0:0:0:0:0:0:0:1" || lower === "0:0:0:0:0:0:0:0") {
81729
+ return true;
81730
+ }
81731
+ const ffffMatch = lower.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/);
81732
+ if (ffffMatch) {
81733
+ return isBlockedIpv4(ffffMatch[1]);
81734
+ }
81735
+ const compatMatch = lower.match(/^::(\d+\.\d+\.\d+\.\d+)$/);
81736
+ if (compatMatch) {
81737
+ return isBlockedIpv4(compatMatch[1]);
81738
+ }
81739
+ return false;
81740
+ }
81741
+ function isSafeHostname(hostname) {
81742
+ if (!hostname) return false;
81743
+ if (/^\d{1,3}(\.\d{1,3}){3}$/.test(hostname)) return !isBlockedIpv4(hostname);
81744
+ if (/^\[.*\]$/.test(hostname)) return !isBlockedIpv6(hostname.slice(1, -1));
81745
+ if (hostname.includes(":")) return !isBlockedIpv6(hostname);
81746
+ return true;
81747
+ }
81748
+ async function safeResolveHostname(hostname) {
81749
+ try {
81750
+ const result2 = await (0, import_promises.lookup)(hostname);
81751
+ const ip = result2.address;
81752
+ if (isBlockedIpv4(ip) || isBlockedIpv6(ip)) {
81753
+ throw new Error(`PM proxy target resolved to a blocked address: ${ip}`);
81754
+ }
81755
+ return ip;
81756
+ } catch (error) {
81757
+ if (error instanceof Error && error.message.includes("blocked address")) {
81758
+ throw error;
81759
+ }
81760
+ throw new Error(`PM proxy failed to resolve target hostname "${hostname}": ${error instanceof Error ? error.message : String(error)}`);
81761
+ }
81762
+ }
81763
+ async function validateProxyTargetUrl(target) {
81764
+ if (!ALLOWED_PROXY_PROTOCOLS.has(target.protocol)) {
81765
+ throw new Error(`PM proxy target protocol "${target.protocol}" is not allowed. Only http: and https: are permitted.`);
81766
+ }
81767
+ const hostname = target.hostname;
81768
+ if (!isSafeHostname(hostname)) {
81769
+ throw new Error(`PM proxy target "${hostname}" resolves to a blocked address and is not allowed.`);
81770
+ }
81771
+ if (!/^\d{1,3}(\.\d{1,3}){3}$/.test(hostname) && !/^\[.*\]$/.test(hostname)) {
81772
+ await safeResolveHostname(hostname);
81773
+ }
81774
+ }
81775
+ function sanitizeProxyRequestPath(requestUrl) {
81776
+ if (!requestUrl || requestUrl === "/") return "/";
81777
+ try {
81778
+ const normalizedInput = requestUrl.replace(/\\/g, "/");
81779
+ const parsed = new URL(normalizedInput, "http://placeholder");
81780
+ if (parsed.username || parsed.password || parsed.hostname !== "placeholder" || parsed.port) {
81781
+ return "/";
81782
+ }
81783
+ const pathname = parsed.pathname || "/";
81784
+ let decodedPathname = pathname;
81785
+ try {
81786
+ decodedPathname = decodeURIComponent(pathname);
81787
+ } catch {
81788
+ return "/";
81789
+ }
81790
+ const lowerPath = pathname.toLowerCase();
81791
+ if (lowerPath.includes("%2f") || lowerPath.includes("%5c") || lowerPath.includes("%40") || lowerPath.includes("%00")) {
81792
+ return "/";
81793
+ }
81794
+ const segments = decodedPathname.split("/");
81795
+ if (segments.some((segment) => segment === "." || segment === "..")) {
81796
+ return "/";
81797
+ }
81798
+ const sanitized = pathname + parsed.search;
81799
+ return sanitized.startsWith("/") ? sanitized || "/" : `/${sanitized}`;
81800
+ } catch {
81801
+ return "/";
81802
+ }
81803
+ }
81593
81804
  function resolvePmProxyHost(proxy) {
81594
81805
  return proxy.host?.trim() || "0.0.0.0";
81595
81806
  }
@@ -81679,6 +81890,9 @@ async function createPmProxyController(proxy) {
81679
81890
  nextTargetIndex = (nextTargetIndex + 1) % targets.length;
81680
81891
  return target;
81681
81892
  };
81893
+ const validateTarget = async (target) => {
81894
+ await validateProxyTargetUrl(target);
81895
+ };
81682
81896
  const server = (0, import_node_http.createServer)((req, res) => {
81683
81897
  const target = pickTarget();
81684
81898
  if (!target) {
@@ -81686,29 +81900,45 @@ async function createPmProxyController(proxy) {
81686
81900
  res.end("PM proxy target is not ready.");
81687
81901
  return;
81688
81902
  }
81903
+ const sanitizedPath = sanitizeProxyRequestPath(req.url || "/");
81689
81904
  const requestLib = target.protocol === "https:" ? import_node_https.request : import_node_http.request;
81690
- const targetUrl = new URL(req.url || "/", target);
81691
81905
  const headers = buildPmProxyHeaders(req.headers, target.host);
81692
- const proxyReq = requestLib(targetUrl, {
81693
- method: req.method,
81694
- headers
81695
- }, (proxyRes) => {
81696
- const outgoingHeaders = {};
81697
- for (const [key, value] of Object.entries(proxyRes.headers)) {
81698
- if (value !== void 0) {
81699
- outgoingHeaders[key] = value;
81906
+ if (!ALLOWED_PROXY_PROTOCOLS.has(target.protocol)) {
81907
+ res.statusCode = 400;
81908
+ res.end("PM proxy rejected unsafe target protocol.");
81909
+ return;
81910
+ }
81911
+ validateTarget(target).then(() => {
81912
+ const proxyReq = requestLib({
81913
+ protocol: target.protocol,
81914
+ hostname: target.hostname,
81915
+ port: target.port || void 0,
81916
+ path: sanitizedPath,
81917
+ method: req.method,
81918
+ headers
81919
+ }, (proxyRes) => {
81920
+ const outgoingHeaders = {};
81921
+ for (const [key, value] of Object.entries(proxyRes.headers)) {
81922
+ if (value !== void 0) {
81923
+ outgoingHeaders[key] = value;
81924
+ }
81700
81925
  }
81701
- }
81702
- res.writeHead(proxyRes.statusCode || 200, outgoingHeaders);
81703
- proxyRes.pipe(res);
81704
- });
81705
- proxyReq.on("error", (error) => {
81926
+ res.writeHead(proxyRes.statusCode || 200, outgoingHeaders);
81927
+ proxyRes.pipe(res);
81928
+ });
81929
+ proxyReq.on("error", (error) => {
81930
+ if (!res.headersSent) {
81931
+ res.statusCode = 502;
81932
+ }
81933
+ res.end(`PM proxy error: ${error.message}`);
81934
+ });
81935
+ req.pipe(proxyReq);
81936
+ }).catch((error) => {
81706
81937
  if (!res.headersSent) {
81707
- res.statusCode = 502;
81938
+ res.statusCode = 403;
81708
81939
  }
81709
- res.end(`PM proxy error: ${error.message}`);
81940
+ res.end(`PM proxy blocked target: ${error instanceof Error ? error.message : String(error)}`);
81710
81941
  });
81711
- req.pipe(proxyReq);
81712
81942
  });
81713
81943
  server.on("upgrade", (req, socket, head) => {
81714
81944
  const target = pickTarget();
@@ -81720,38 +81950,56 @@ async function createPmProxyController(proxy) {
81720
81950
  socket.destroy();
81721
81951
  return;
81722
81952
  }
81953
+ const sanitizedPath = sanitizeProxyRequestPath(req.url || "/");
81723
81954
  const requestLib = target.protocol === "https:" ? import_node_https.request : import_node_http.request;
81724
- const targetUrl = new URL(req.url || "/", target);
81725
- const proxyReq = requestLib(targetUrl, {
81726
- method: req.method,
81727
- headers: buildPmProxyHeaders(req.headers, target.host)
81728
- });
81729
- proxyReq.on("upgrade", (proxyRes, proxySocket, proxyHead) => {
81730
- writeRawHttpResponse(socket, proxyRes.statusCode || 101, proxyRes.statusMessage || "Switching Protocols", proxyRes.headers);
81731
- if (head.length > 0) {
81732
- proxySocket.write(head);
81733
- }
81734
- if (proxyHead.length > 0) {
81735
- socket.write(proxyHead);
81736
- }
81737
- socket.on("error", () => proxySocket.destroy());
81738
- proxySocket.on("error", () => socket.destroy());
81739
- proxySocket.pipe(socket);
81740
- socket.pipe(proxySocket);
81741
- });
81742
- proxyReq.on("response", (proxyRes) => {
81743
- writeRawHttpResponse(socket, proxyRes.statusCode || 502, proxyRes.statusMessage || "Bad Gateway", proxyRes.headers);
81744
- proxyRes.pipe(socket);
81745
- });
81746
- proxyReq.on("error", (error) => {
81747
- writeRawHttpResponse(socket, 502, "Bad Gateway", {
81955
+ const targetUrl = new URL(sanitizedPath, target);
81956
+ if (targetUrl.hostname !== target.hostname || targetUrl.port !== target.port || !ALLOWED_PROXY_PROTOCOLS.has(targetUrl.protocol)) {
81957
+ writeRawHttpResponse(socket, 400, "Bad Request", {
81958
+ connection: "close",
81959
+ "content-length": 0
81960
+ });
81961
+ socket.destroy();
81962
+ return;
81963
+ }
81964
+ validateTarget(target).then(() => {
81965
+ const proxyReq = requestLib(targetUrl, {
81966
+ method: req.method,
81967
+ headers: buildPmProxyHeaders(req.headers, target.host)
81968
+ });
81969
+ proxyReq.on("upgrade", (proxyRes, proxySocket, proxyHead) => {
81970
+ writeRawHttpResponse(socket, proxyRes.statusCode || 101, proxyRes.statusMessage || "Switching Protocols", proxyRes.headers);
81971
+ if (head.length > 0) {
81972
+ proxySocket.write(head);
81973
+ }
81974
+ if (proxyHead.length > 0) {
81975
+ socket.write(proxyHead);
81976
+ }
81977
+ socket.on("error", () => proxySocket.destroy());
81978
+ proxySocket.on("error", () => socket.destroy());
81979
+ proxySocket.pipe(socket);
81980
+ socket.pipe(proxySocket);
81981
+ });
81982
+ proxyReq.on("response", (proxyRes) => {
81983
+ writeRawHttpResponse(socket, proxyRes.statusCode || 502, proxyRes.statusMessage || "Bad Gateway", proxyRes.headers);
81984
+ proxyRes.pipe(socket);
81985
+ });
81986
+ proxyReq.on("error", (error) => {
81987
+ writeRawHttpResponse(socket, 502, "Bad Gateway", {
81988
+ connection: "close",
81989
+ "content-type": "text/plain; charset=utf-8",
81990
+ "content-length": Buffer.byteLength(`PM proxy error: ${error.message}`)
81991
+ });
81992
+ socket.end(`PM proxy error: ${error.message}`);
81993
+ });
81994
+ proxyReq.end();
81995
+ }).catch((error) => {
81996
+ writeRawHttpResponse(socket, 403, "Forbidden", {
81748
81997
  connection: "close",
81749
81998
  "content-type": "text/plain; charset=utf-8",
81750
- "content-length": Buffer.byteLength(`PM proxy error: ${error.message}`)
81999
+ "content-length": Buffer.byteLength(`PM proxy blocked target: ${error instanceof Error ? error.message : String(error)}`)
81751
82000
  });
81752
- socket.end(`PM proxy error: ${error.message}`);
82001
+ socket.end(`PM proxy blocked target: ${error instanceof Error ? error.message : String(error)}`);
81753
82002
  });
81754
- proxyReq.end();
81755
82003
  });
81756
82004
  await new Promise((resolve26, reject) => {
81757
82005
  server.once("error", reject);
@@ -81759,10 +82007,25 @@ async function createPmProxyController(proxy) {
81759
82007
  });
81760
82008
  return {
81761
82009
  setTarget(targetUrl) {
81762
- setResolvedTargets(targetUrl ? [new URL(targetUrl)] : []);
82010
+ if (targetUrl) {
82011
+ const parsed = new URL(targetUrl);
82012
+ validateProxyTargetUrl(parsed).then(() => {
82013
+ setResolvedTargets([parsed]);
82014
+ }).catch((error) => {
82015
+ console.error(`[PM proxy] Blocked setTarget: ${error instanceof Error ? error.message : String(error)}`);
82016
+ setResolvedTargets([]);
82017
+ });
82018
+ } else {
82019
+ setResolvedTargets([]);
82020
+ }
81763
82021
  },
81764
82022
  setTargets(targetUrls) {
81765
- setResolvedTargets(targetUrls.map((targetUrl) => new URL(targetUrl)));
82023
+ Promise.all(targetUrls.map((url) => validateProxyTargetUrl(new URL(url)))).then(() => {
82024
+ setResolvedTargets(targetUrls.map((targetUrl) => new URL(targetUrl)));
82025
+ }).catch((error) => {
82026
+ console.error(`[PM proxy] Blocked setTargets: ${error instanceof Error ? error.message : String(error)}`);
82027
+ setResolvedTargets([]);
82028
+ });
81766
82029
  },
81767
82030
  close() {
81768
82031
  return new Promise((resolve26, reject) => {
@@ -86181,7 +86444,7 @@ function parsePreviewArgs(args) {
86181
86444
  // package.json
86182
86445
  var package_default = {
86183
86446
  name: "elit",
86184
- version: "3.6.8",
86447
+ version: "3.6.9",
86185
86448
  description: "Optimized lightweight library for creating DOM elements with reactive state",
86186
86449
  main: "dist/index.js",
86187
86450
  module: "dist/index.mjs",