@wrongstack/webui 0.7.5 → 0.7.7
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/server/entry.js +22 -4
- package/dist/server/entry.js.map +1 -1
- package/dist/server/index.js +22 -4
- package/dist/server/index.js.map +1 -1
- package/package.json +5 -5
package/dist/server/index.js
CHANGED
|
@@ -366,7 +366,7 @@ async function startWebUI(opts = {}) {
|
|
|
366
366
|
};
|
|
367
367
|
}
|
|
368
368
|
const wsToken = randomBytes(16).toString("hex");
|
|
369
|
-
console.log(`[WebUI] WS auth token: ${wsToken}`);
|
|
369
|
+
console.log(`[WebUI] WS auth token: ${wsToken.slice(0, 4)}\u2026${wsToken.slice(-4)} (masked)`);
|
|
370
370
|
const isLoopback = (hostname) => hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]";
|
|
371
371
|
const verifyClient = (info) => {
|
|
372
372
|
const origin = info.origin;
|
|
@@ -1522,20 +1522,38 @@ async function startWebUI(opts = {}) {
|
|
|
1522
1522
|
} else {
|
|
1523
1523
|
filePath = path.join(DIST_DIR, "index.html");
|
|
1524
1524
|
}
|
|
1525
|
-
const
|
|
1525
|
+
const resolvedPath = path.resolve(filePath);
|
|
1526
|
+
const resolvedRoot = path.resolve(DIST_DIR);
|
|
1527
|
+
if (!resolvedPath.startsWith(resolvedRoot + path.sep) && resolvedPath !== resolvedRoot) {
|
|
1528
|
+
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
1529
|
+
res.end("Forbidden");
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
const ext = path.extname(resolvedPath);
|
|
1526
1533
|
const contentType = mimeTypes[ext] ?? "application/octet-stream";
|
|
1527
1534
|
res.setHeader("Content-Type", contentType);
|
|
1535
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
1536
|
+
res.setHeader("X-Frame-Options", "DENY");
|
|
1537
|
+
res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
1528
1538
|
if (ext === ".html") {
|
|
1529
1539
|
res.setHeader("Cache-Control", "no-cache");
|
|
1540
|
+
res.setHeader(
|
|
1541
|
+
"Content-Security-Policy",
|
|
1542
|
+
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: wss:; img-src 'self' data:; font-src 'self' data:"
|
|
1543
|
+
);
|
|
1530
1544
|
}
|
|
1531
|
-
const fileContent = await fs2.readFile(
|
|
1545
|
+
const fileContent = await fs2.readFile(resolvedPath);
|
|
1532
1546
|
res.writeHead(200);
|
|
1533
1547
|
res.end(fileContent);
|
|
1534
1548
|
} catch (err) {
|
|
1535
1549
|
if (err.code === "ENOENT") {
|
|
1536
1550
|
try {
|
|
1537
1551
|
const fileContent = await fs2.readFile(path.join(DIST_DIR, "index.html"));
|
|
1538
|
-
res.writeHead(200, {
|
|
1552
|
+
res.writeHead(200, {
|
|
1553
|
+
"Content-Type": "text/html",
|
|
1554
|
+
"X-Content-Type-Options": "nosniff",
|
|
1555
|
+
"X-Frame-Options": "DENY"
|
|
1556
|
+
});
|
|
1539
1557
|
res.end(fileContent);
|
|
1540
1558
|
} catch {
|
|
1541
1559
|
res.writeHead(404);
|