@inspecto-dev/plugin 0.3.4 → 0.3.5
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
|
@@ -45,7 +45,7 @@ var resolveClientModule = () => {
|
|
|
45
45
|
|
|
46
46
|
// src/server/index.ts
|
|
47
47
|
import http from "http";
|
|
48
|
-
import
|
|
48
|
+
import fs5 from "fs";
|
|
49
49
|
import path6 from "path";
|
|
50
50
|
import os2 from "os";
|
|
51
51
|
import crypto2 from "crypto";
|
|
@@ -569,6 +569,7 @@ function hasOverrides(overrides) {
|
|
|
569
569
|
|
|
570
570
|
// src/server/path-guards.ts
|
|
571
571
|
import path4 from "path";
|
|
572
|
+
import fs3 from "fs";
|
|
572
573
|
function isWindowsAbsolutePath(file) {
|
|
573
574
|
return /^[a-zA-Z]:[\\/]/.test(file) || /^\\\\[^\\]+\\[^\\]+/.test(file);
|
|
574
575
|
}
|
|
@@ -579,9 +580,94 @@ function resolveWorkspacePath(file, cwd) {
|
|
|
579
580
|
return path4.isAbsolute(file) ? path4.resolve(file) : path4.resolve(cwd, file);
|
|
580
581
|
}
|
|
581
582
|
function assertPathWithinProject(file, projectRoot) {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
583
|
+
let realFile = file;
|
|
584
|
+
let realProjectRoot = projectRoot;
|
|
585
|
+
try {
|
|
586
|
+
if (fs3.existsSync(file)) {
|
|
587
|
+
realFile = fs3.realpathSync(file);
|
|
588
|
+
}
|
|
589
|
+
} catch {
|
|
590
|
+
}
|
|
591
|
+
try {
|
|
592
|
+
if (fs3.existsSync(projectRoot)) {
|
|
593
|
+
realProjectRoot = fs3.realpathSync(projectRoot);
|
|
594
|
+
}
|
|
595
|
+
} catch {
|
|
596
|
+
}
|
|
597
|
+
if (isWithinPath(file, projectRoot) || isWithinPath(realFile, realProjectRoot)) {
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
throw new Error(
|
|
601
|
+
`Access denied: File ${normalizeForComparison(realFile)} is outside of project workspace ${normalizeForComparison(realProjectRoot)}`
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
function tryReadPackageName(packageRoot) {
|
|
605
|
+
try {
|
|
606
|
+
const packageJsonPath = path4.join(packageRoot, "package.json");
|
|
607
|
+
if (!fs3.existsSync(packageJsonPath)) return void 0;
|
|
608
|
+
const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf8"));
|
|
609
|
+
return typeof packageJson.name === "string" ? packageJson.name : void 0;
|
|
610
|
+
} catch {
|
|
611
|
+
return void 0;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
function findNearestPackageRoot(file) {
|
|
615
|
+
let current = path4.dirname(file);
|
|
616
|
+
while (true) {
|
|
617
|
+
if (fs3.existsSync(path4.join(current, "package.json"))) {
|
|
618
|
+
return current;
|
|
619
|
+
}
|
|
620
|
+
const parent = path4.dirname(current);
|
|
621
|
+
if (parent === current) {
|
|
622
|
+
return void 0;
|
|
623
|
+
}
|
|
624
|
+
current = parent;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
function normalizeForComparison(file) {
|
|
628
|
+
return isWindowsAbsolutePath(file) ? path4.win32.normalize(file) : path4.normalize(file);
|
|
629
|
+
}
|
|
630
|
+
function pathSeparatorFor(file) {
|
|
631
|
+
return isWindowsAbsolutePath(file) ? path4.win32.sep : path4.sep;
|
|
632
|
+
}
|
|
633
|
+
function isWithinPath(file, root) {
|
|
634
|
+
const normalizedFile = normalizeForComparison(file);
|
|
635
|
+
const normalizedRoot = normalizeForComparison(root);
|
|
636
|
+
const separator = pathSeparatorFor(normalizedRoot);
|
|
637
|
+
const rootWithSep = normalizedRoot.endsWith(separator) ? normalizedRoot : normalizedRoot + separator;
|
|
638
|
+
return normalizedFile === normalizedRoot || normalizedFile.startsWith(rootWithSep);
|
|
639
|
+
}
|
|
640
|
+
function resolveLinkedDependencyEntry(projectRoot, packageName) {
|
|
641
|
+
const packageSegments = packageName.split("/");
|
|
642
|
+
const dependencyPath = path4.join(projectRoot, "node_modules", ...packageSegments);
|
|
643
|
+
if (!fs3.existsSync(dependencyPath)) return void 0;
|
|
644
|
+
try {
|
|
645
|
+
return fs3.realpathSync(dependencyPath);
|
|
646
|
+
} catch {
|
|
647
|
+
return dependencyPath;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
function isLinkedDependencyPath(file, projectRoot, packageName) {
|
|
651
|
+
const linkedDependencyRoot = resolveLinkedDependencyEntry(projectRoot, packageName);
|
|
652
|
+
if (!linkedDependencyRoot) return false;
|
|
653
|
+
return isWithinPath(file, linkedDependencyRoot);
|
|
654
|
+
}
|
|
655
|
+
function isLinkedDependencySourcePath(file, projectRoot) {
|
|
656
|
+
const packageRoot = findNearestPackageRoot(file);
|
|
657
|
+
if (!packageRoot) return false;
|
|
658
|
+
const packageName = tryReadPackageName(packageRoot);
|
|
659
|
+
if (!packageName) return false;
|
|
660
|
+
return isLinkedDependencyPath(file, projectRoot, packageName);
|
|
661
|
+
}
|
|
662
|
+
function assertPathWithinIdeOpenScope(file, projectRoot) {
|
|
663
|
+
try {
|
|
664
|
+
assertPathWithinProject(file, projectRoot);
|
|
665
|
+
return;
|
|
666
|
+
} catch {
|
|
667
|
+
if (isLinkedDependencySourcePath(file, projectRoot)) {
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
throw new Error(`Access denied: File is outside of project workspace`);
|
|
585
671
|
}
|
|
586
672
|
}
|
|
587
673
|
|
|
@@ -786,7 +872,7 @@ var VSCODE_FAMILY_SCHEMES = [
|
|
|
786
872
|
];
|
|
787
873
|
function handleOpenFileRequest(body, serverState2) {
|
|
788
874
|
const absolutePath = resolveWorkspacePath(body.file, serverState2.cwd);
|
|
789
|
-
|
|
875
|
+
assertPathWithinIdeOpenScope(absolutePath, serverState2.projectRoot);
|
|
790
876
|
const userConfig = loadUserConfigSync(false, serverState2.cwd, serverState2.configRoot);
|
|
791
877
|
const configuredIde = userConfig.ide;
|
|
792
878
|
const activeIde = serverState2.ideInfo?.ide;
|
|
@@ -844,7 +930,7 @@ function handleOpenFileRequest(body, serverState2) {
|
|
|
844
930
|
}
|
|
845
931
|
|
|
846
932
|
// src/server/project-root.ts
|
|
847
|
-
import
|
|
933
|
+
import fs4 from "fs";
|
|
848
934
|
import path5 from "path";
|
|
849
935
|
import { execSync } from "child_process";
|
|
850
936
|
var serverLogger3 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
@@ -862,7 +948,7 @@ function resolveProjectRoot() {
|
|
|
862
948
|
let current = start;
|
|
863
949
|
while (!visited.has(current)) {
|
|
864
950
|
visited.add(current);
|
|
865
|
-
if (
|
|
951
|
+
if (fs4.existsSync(path5.join(current, ".inspecto"))) return current;
|
|
866
952
|
if (current === stop) break;
|
|
867
953
|
const parent = path5.dirname(current);
|
|
868
954
|
if (parent === current) break;
|
|
@@ -934,28 +1020,28 @@ async function startServer() {
|
|
|
934
1020
|
const portFile = path6.join(os2.tmpdir(), "inspecto.port.json");
|
|
935
1021
|
try {
|
|
936
1022
|
let portData = {};
|
|
937
|
-
if (
|
|
1023
|
+
if (fs5.existsSync(portFile)) {
|
|
938
1024
|
try {
|
|
939
|
-
portData = JSON.parse(
|
|
1025
|
+
portData = JSON.parse(fs5.readFileSync(portFile, "utf-8"));
|
|
940
1026
|
} catch (e) {
|
|
941
1027
|
}
|
|
942
1028
|
}
|
|
943
1029
|
const rootHash = crypto2.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
944
1030
|
portData[rootHash] = port;
|
|
945
|
-
|
|
1031
|
+
fs5.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
946
1032
|
} catch (e) {
|
|
947
1033
|
serverLogger4.warn("Failed to write port file:", e);
|
|
948
1034
|
}
|
|
949
1035
|
process.once("exit", () => {
|
|
950
1036
|
try {
|
|
951
|
-
if (
|
|
952
|
-
const portData = JSON.parse(
|
|
1037
|
+
if (fs5.existsSync(portFile)) {
|
|
1038
|
+
const portData = JSON.parse(fs5.readFileSync(portFile, "utf-8"));
|
|
953
1039
|
const rootHash = crypto2.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
954
1040
|
delete portData[rootHash];
|
|
955
1041
|
if (Object.keys(portData).length === 0) {
|
|
956
|
-
|
|
1042
|
+
fs5.unlinkSync(portFile);
|
|
957
1043
|
} else {
|
|
958
|
-
|
|
1044
|
+
fs5.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
959
1045
|
}
|
|
960
1046
|
}
|
|
961
1047
|
} catch {
|
|
@@ -1024,8 +1110,10 @@ async function handleRequest(url, req, res) {
|
|
|
1024
1110
|
}
|
|
1025
1111
|
try {
|
|
1026
1112
|
handleOpenFileRequest(body, serverState);
|
|
1027
|
-
} catch {
|
|
1028
|
-
serverLogger4.warn(
|
|
1113
|
+
} catch (err) {
|
|
1114
|
+
serverLogger4.warn(
|
|
1115
|
+
`Security: Blocked path traversal attempt in IDE_OPEN: ${body.file}. Reason: ${err.message}`
|
|
1116
|
+
);
|
|
1029
1117
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
1030
1118
|
res.end(JSON.stringify({ error: "Access denied: File is outside of project workspace" }));
|
|
1031
1119
|
return;
|
|
@@ -1043,8 +1131,10 @@ async function handleRequest(url, req, res) {
|
|
|
1043
1131
|
const absolutePath = resolveWorkspacePath(file, serverState.cwd);
|
|
1044
1132
|
try {
|
|
1045
1133
|
assertPathWithinProject(absolutePath, serverState.projectRoot);
|
|
1046
|
-
} catch {
|
|
1047
|
-
serverLogger4.warn(
|
|
1134
|
+
} catch (err) {
|
|
1135
|
+
serverLogger4.warn(
|
|
1136
|
+
`Security: Blocked path traversal attempt in PROJECT_SNIPPET: ${file}. Reason: ${err.message}`
|
|
1137
|
+
);
|
|
1048
1138
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
1049
1139
|
res.end(
|
|
1050
1140
|
JSON.stringify({
|
|
@@ -1140,10 +1230,20 @@ function getBatchDispatchStatusCode(errorCode, success) {
|
|
|
1140
1230
|
import path7 from "path";
|
|
1141
1231
|
var InspectoWebpack4Plugin = class {
|
|
1142
1232
|
constructor(options = {}) {
|
|
1233
|
+
this.serverPort = null;
|
|
1143
1234
|
this.options = options;
|
|
1144
1235
|
}
|
|
1236
|
+
async ensureServer() {
|
|
1237
|
+
if (this.serverPort === null) {
|
|
1238
|
+
this.serverPort = await startServer();
|
|
1239
|
+
}
|
|
1240
|
+
return this.serverPort;
|
|
1241
|
+
}
|
|
1145
1242
|
apply(compiler) {
|
|
1146
1243
|
const clientPath = resolveClientModule();
|
|
1244
|
+
compiler.hooks.beforeCompile.tapPromise("InspectoWebpack4Plugin", async () => {
|
|
1245
|
+
await this.ensureServer();
|
|
1246
|
+
});
|
|
1147
1247
|
compiler.hooks.afterEnvironment.tap("InspectoWebpack4Plugin", () => {
|
|
1148
1248
|
const inspectoLoader = path7.resolve(__dirname, "loader.cjs");
|
|
1149
1249
|
compiler.options.module.rules.push({
|
|
@@ -1170,7 +1270,7 @@ var InspectoWebpack4Plugin = class {
|
|
|
1170
1270
|
HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync(
|
|
1171
1271
|
"InspectoWebpack4Plugin",
|
|
1172
1272
|
async (data, cb) => {
|
|
1173
|
-
const port = await
|
|
1273
|
+
const port = await this.ensureServer();
|
|
1174
1274
|
data.headTags.unshift({
|
|
1175
1275
|
tagName: "script",
|
|
1176
1276
|
voidTag: false,
|
|
@@ -1184,7 +1284,7 @@ var InspectoWebpack4Plugin = class {
|
|
|
1184
1284
|
compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(
|
|
1185
1285
|
"InspectoWebpack4Plugin",
|
|
1186
1286
|
async (data, cb) => {
|
|
1187
|
-
const port = await
|
|
1287
|
+
const port = await this.ensureServer();
|
|
1188
1288
|
data.head.unshift({
|
|
1189
1289
|
tagName: "script",
|
|
1190
1290
|
voidTag: false,
|