@inspecto-dev/plugin 0.3.4 → 0.3.6
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/index.cjs +179 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +179 -44
- package/dist/index.js.map +1 -1
- package/dist/legacy/rspack/index.cjs +108 -18
- package/dist/legacy/rspack/index.cjs.map +1 -1
- package/dist/legacy/rspack/index.js +108 -18
- package/dist/legacy/rspack/index.js.map +1 -1
- package/dist/legacy/rspack/loader.cjs +49 -4
- package/dist/legacy/rspack/loader.cjs.map +1 -1
- package/dist/legacy/rspack/loader.js +49 -4
- package/dist/legacy/rspack/loader.js.map +1 -1
- package/dist/legacy/webpack4/index.cjs +120 -20
- package/dist/legacy/webpack4/index.cjs.map +1 -1
- package/dist/legacy/webpack4/index.d.cts +2 -0
- package/dist/legacy/webpack4/index.d.ts +2 -0
- package/dist/legacy/webpack4/index.js +120 -20
- package/dist/legacy/webpack4/index.js.map +1 -1
- package/dist/legacy/webpack4/loader.cjs +49 -4
- package/dist/legacy/webpack4/loader.cjs.map +1 -1
- package/dist/legacy/webpack4/loader.js +49 -4
- package/dist/legacy/webpack4/loader.js.map +1 -1
- package/dist/rollup.cjs +179 -44
- package/dist/rollup.cjs.map +1 -1
- package/dist/rollup.js +179 -44
- package/dist/rollup.js.map +1 -1
- package/dist/rspack.cjs +179 -44
- package/dist/rspack.cjs.map +1 -1
- package/dist/rspack.js +179 -44
- package/dist/rspack.js.map +1 -1
- package/dist/vite.cjs +179 -44
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.js +179 -44
- package/dist/vite.js.map +1 -1
- package/dist/webpack.cjs +179 -44
- package/dist/webpack.cjs.map +1 -1
- package/dist/webpack.js +179 -44
- package/dist/webpack.js.map +1 -1
- package/package.json +2 -2
|
@@ -14,7 +14,7 @@ var __dirname = /* @__PURE__ */ getDirname();
|
|
|
14
14
|
|
|
15
15
|
// src/server/index.ts
|
|
16
16
|
import http from "http";
|
|
17
|
-
import
|
|
17
|
+
import fs5 from "fs";
|
|
18
18
|
import path6 from "path";
|
|
19
19
|
import os2 from "os";
|
|
20
20
|
import crypto2 from "crypto";
|
|
@@ -538,6 +538,7 @@ function hasOverrides(overrides) {
|
|
|
538
538
|
|
|
539
539
|
// src/server/path-guards.ts
|
|
540
540
|
import path4 from "path";
|
|
541
|
+
import fs3 from "fs";
|
|
541
542
|
function isWindowsAbsolutePath(file) {
|
|
542
543
|
return /^[a-zA-Z]:[\\/]/.test(file) || /^\\\\[^\\]+\\[^\\]+/.test(file);
|
|
543
544
|
}
|
|
@@ -548,9 +549,94 @@ function resolveWorkspacePath(file, cwd) {
|
|
|
548
549
|
return path4.isAbsolute(file) ? path4.resolve(file) : path4.resolve(cwd, file);
|
|
549
550
|
}
|
|
550
551
|
function assertPathWithinProject(file, projectRoot) {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
552
|
+
let realFile = file;
|
|
553
|
+
let realProjectRoot = projectRoot;
|
|
554
|
+
try {
|
|
555
|
+
if (fs3.existsSync(file)) {
|
|
556
|
+
realFile = fs3.realpathSync(file);
|
|
557
|
+
}
|
|
558
|
+
} catch {
|
|
559
|
+
}
|
|
560
|
+
try {
|
|
561
|
+
if (fs3.existsSync(projectRoot)) {
|
|
562
|
+
realProjectRoot = fs3.realpathSync(projectRoot);
|
|
563
|
+
}
|
|
564
|
+
} catch {
|
|
565
|
+
}
|
|
566
|
+
if (isWithinPath(file, projectRoot) || isWithinPath(realFile, realProjectRoot)) {
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
throw new Error(
|
|
570
|
+
`Access denied: File ${normalizeForComparison(realFile)} is outside of project workspace ${normalizeForComparison(realProjectRoot)}`
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
function tryReadPackageName(packageRoot) {
|
|
574
|
+
try {
|
|
575
|
+
const packageJsonPath = path4.join(packageRoot, "package.json");
|
|
576
|
+
if (!fs3.existsSync(packageJsonPath)) return void 0;
|
|
577
|
+
const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf8"));
|
|
578
|
+
return typeof packageJson.name === "string" ? packageJson.name : void 0;
|
|
579
|
+
} catch {
|
|
580
|
+
return void 0;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
function findNearestPackageRoot(file) {
|
|
584
|
+
let current = path4.dirname(file);
|
|
585
|
+
while (true) {
|
|
586
|
+
if (fs3.existsSync(path4.join(current, "package.json"))) {
|
|
587
|
+
return current;
|
|
588
|
+
}
|
|
589
|
+
const parent = path4.dirname(current);
|
|
590
|
+
if (parent === current) {
|
|
591
|
+
return void 0;
|
|
592
|
+
}
|
|
593
|
+
current = parent;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
function normalizeForComparison(file) {
|
|
597
|
+
return isWindowsAbsolutePath(file) ? path4.win32.normalize(file) : path4.normalize(file);
|
|
598
|
+
}
|
|
599
|
+
function pathSeparatorFor(file) {
|
|
600
|
+
return isWindowsAbsolutePath(file) ? path4.win32.sep : path4.sep;
|
|
601
|
+
}
|
|
602
|
+
function isWithinPath(file, root) {
|
|
603
|
+
const normalizedFile = normalizeForComparison(file);
|
|
604
|
+
const normalizedRoot = normalizeForComparison(root);
|
|
605
|
+
const separator = pathSeparatorFor(normalizedRoot);
|
|
606
|
+
const rootWithSep = normalizedRoot.endsWith(separator) ? normalizedRoot : normalizedRoot + separator;
|
|
607
|
+
return normalizedFile === normalizedRoot || normalizedFile.startsWith(rootWithSep);
|
|
608
|
+
}
|
|
609
|
+
function resolveLinkedDependencyEntry(projectRoot, packageName) {
|
|
610
|
+
const packageSegments = packageName.split("/");
|
|
611
|
+
const dependencyPath = path4.join(projectRoot, "node_modules", ...packageSegments);
|
|
612
|
+
if (!fs3.existsSync(dependencyPath)) return void 0;
|
|
613
|
+
try {
|
|
614
|
+
return fs3.realpathSync(dependencyPath);
|
|
615
|
+
} catch {
|
|
616
|
+
return dependencyPath;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
function isLinkedDependencyPath(file, projectRoot, packageName) {
|
|
620
|
+
const linkedDependencyRoot = resolveLinkedDependencyEntry(projectRoot, packageName);
|
|
621
|
+
if (!linkedDependencyRoot) return false;
|
|
622
|
+
return isWithinPath(file, linkedDependencyRoot);
|
|
623
|
+
}
|
|
624
|
+
function isLinkedDependencySourcePath(file, projectRoot) {
|
|
625
|
+
const packageRoot = findNearestPackageRoot(file);
|
|
626
|
+
if (!packageRoot) return false;
|
|
627
|
+
const packageName = tryReadPackageName(packageRoot);
|
|
628
|
+
if (!packageName) return false;
|
|
629
|
+
return isLinkedDependencyPath(file, projectRoot, packageName);
|
|
630
|
+
}
|
|
631
|
+
function assertPathWithinIdeOpenScope(file, projectRoot) {
|
|
632
|
+
try {
|
|
633
|
+
assertPathWithinProject(file, projectRoot);
|
|
634
|
+
return;
|
|
635
|
+
} catch {
|
|
636
|
+
if (isLinkedDependencySourcePath(file, projectRoot)) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
throw new Error(`Access denied: File is outside of project workspace`);
|
|
554
640
|
}
|
|
555
641
|
}
|
|
556
642
|
|
|
@@ -755,7 +841,7 @@ var VSCODE_FAMILY_SCHEMES = [
|
|
|
755
841
|
];
|
|
756
842
|
function handleOpenFileRequest(body, serverState3) {
|
|
757
843
|
const absolutePath = resolveWorkspacePath(body.file, serverState3.cwd);
|
|
758
|
-
|
|
844
|
+
assertPathWithinIdeOpenScope(absolutePath, serverState3.projectRoot);
|
|
759
845
|
const userConfig = loadUserConfigSync(false, serverState3.cwd, serverState3.configRoot);
|
|
760
846
|
const configuredIde = userConfig.ide;
|
|
761
847
|
const activeIde = serverState3.ideInfo?.ide;
|
|
@@ -813,7 +899,7 @@ function handleOpenFileRequest(body, serverState3) {
|
|
|
813
899
|
}
|
|
814
900
|
|
|
815
901
|
// src/server/project-root.ts
|
|
816
|
-
import
|
|
902
|
+
import fs4 from "fs";
|
|
817
903
|
import path5 from "path";
|
|
818
904
|
import { execSync } from "child_process";
|
|
819
905
|
var serverLogger3 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
@@ -831,7 +917,7 @@ function resolveProjectRoot() {
|
|
|
831
917
|
let current = start;
|
|
832
918
|
while (!visited.has(current)) {
|
|
833
919
|
visited.add(current);
|
|
834
|
-
if (
|
|
920
|
+
if (fs4.existsSync(path5.join(current, ".inspecto"))) return current;
|
|
835
921
|
if (current === stop) break;
|
|
836
922
|
const parent = path5.dirname(current);
|
|
837
923
|
if (parent === current) break;
|
|
@@ -903,28 +989,28 @@ async function startServer() {
|
|
|
903
989
|
const portFile = path6.join(os2.tmpdir(), "inspecto.port.json");
|
|
904
990
|
try {
|
|
905
991
|
let portData = {};
|
|
906
|
-
if (
|
|
992
|
+
if (fs5.existsSync(portFile)) {
|
|
907
993
|
try {
|
|
908
|
-
portData = JSON.parse(
|
|
994
|
+
portData = JSON.parse(fs5.readFileSync(portFile, "utf-8"));
|
|
909
995
|
} catch (e) {
|
|
910
996
|
}
|
|
911
997
|
}
|
|
912
998
|
const rootHash = crypto2.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
913
999
|
portData[rootHash] = port;
|
|
914
|
-
|
|
1000
|
+
fs5.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
915
1001
|
} catch (e) {
|
|
916
1002
|
serverLogger4.warn("Failed to write port file:", e);
|
|
917
1003
|
}
|
|
918
1004
|
process.once("exit", () => {
|
|
919
1005
|
try {
|
|
920
|
-
if (
|
|
921
|
-
const portData = JSON.parse(
|
|
1006
|
+
if (fs5.existsSync(portFile)) {
|
|
1007
|
+
const portData = JSON.parse(fs5.readFileSync(portFile, "utf-8"));
|
|
922
1008
|
const rootHash = crypto2.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
923
1009
|
delete portData[rootHash];
|
|
924
1010
|
if (Object.keys(portData).length === 0) {
|
|
925
|
-
|
|
1011
|
+
fs5.unlinkSync(portFile);
|
|
926
1012
|
} else {
|
|
927
|
-
|
|
1013
|
+
fs5.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
928
1014
|
}
|
|
929
1015
|
}
|
|
930
1016
|
} catch {
|
|
@@ -993,8 +1079,10 @@ async function handleRequest(url, req, res) {
|
|
|
993
1079
|
}
|
|
994
1080
|
try {
|
|
995
1081
|
handleOpenFileRequest(body, serverState);
|
|
996
|
-
} catch {
|
|
997
|
-
serverLogger4.warn(
|
|
1082
|
+
} catch (err) {
|
|
1083
|
+
serverLogger4.warn(
|
|
1084
|
+
`Security: Blocked path traversal attempt in IDE_OPEN: ${body.file}. Reason: ${err.message}`
|
|
1085
|
+
);
|
|
998
1086
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
999
1087
|
res.end(JSON.stringify({ error: "Access denied: File is outside of project workspace" }));
|
|
1000
1088
|
return;
|
|
@@ -1012,8 +1100,10 @@ async function handleRequest(url, req, res) {
|
|
|
1012
1100
|
const absolutePath = resolveWorkspacePath(file, serverState.cwd);
|
|
1013
1101
|
try {
|
|
1014
1102
|
assertPathWithinProject(absolutePath, serverState.projectRoot);
|
|
1015
|
-
} catch {
|
|
1016
|
-
serverLogger4.warn(
|
|
1103
|
+
} catch (err) {
|
|
1104
|
+
serverLogger4.warn(
|
|
1105
|
+
`Security: Blocked path traversal attempt in PROJECT_SNIPPET: ${file}. Reason: ${err.message}`
|
|
1106
|
+
);
|
|
1017
1107
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
1018
1108
|
res.end(
|
|
1019
1109
|
JSON.stringify({
|