forked from svrjs/svrjs
Move parts of middleware that checks for forbidden paths to separate utils file, and add tests for them.
This commit is contained in:
parent
983133017f
commit
5fab894caf
4 changed files with 245 additions and 80 deletions
|
@ -13,6 +13,7 @@ try {
|
|||
}
|
||||
|
||||
process.dirname = __dirname;
|
||||
process.filename = __filename;
|
||||
|
||||
// TODO: after implementing clustering in new SVR.JS
|
||||
//process.singleThreaded = false;
|
||||
|
|
|
@ -1,81 +1,11 @@
|
|||
const os = require("os");
|
||||
const path = require("path");
|
||||
|
||||
// Function to get URL path for use in forbidden path adding.
|
||||
function getInitializePath(to) {
|
||||
const cwd = process.cwd();
|
||||
if (os.platform() == "win32") {
|
||||
to = to.replace(/\//g, "\\");
|
||||
if (to[0] == "\\") to = cwd.split("\\")[0] + to;
|
||||
}
|
||||
const absoluteTo = path.isAbsolute(to)
|
||||
? to
|
||||
: process.dirname + (os.platform() == "win32" ? "\\" : "/") + to;
|
||||
if (os.platform() == "win32" && cwd[0] != absoluteTo[0]) return "";
|
||||
const relative = path.relative(cwd, absoluteTo);
|
||||
if (os.platform() == "win32") {
|
||||
return "/" + relative.replace(/\\/g, "/");
|
||||
} else {
|
||||
return "/" + relative;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to check if URL path name is a forbidden path.
|
||||
function isForbiddenPath(decodedHref, match) {
|
||||
const forbiddenPath = forbiddenPaths[match];
|
||||
if (!forbiddenPath) return false;
|
||||
if (typeof forbiddenPath === "string") {
|
||||
return (
|
||||
decodedHref === forbiddenPath ||
|
||||
(os.platform() === "win32" &&
|
||||
decodedHref.toLowerCase() === forbiddenPath.toLowerCase())
|
||||
);
|
||||
}
|
||||
if (typeof forbiddenPath === "object") {
|
||||
return forbiddenPath.some(function (forbiddenPathSingle) {
|
||||
return (
|
||||
decodedHref === forbiddenPathSingle ||
|
||||
(os.platform() === "win32" &&
|
||||
decodedHref.toLowerCase() === forbiddenPathSingle.toLowerCase())
|
||||
);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function to check if URL path name is index of one of defined forbidden paths.
|
||||
function isIndexOfForbiddenPath(decodedHref, match) {
|
||||
const forbiddenPath = forbiddenPaths[match];
|
||||
if (!forbiddenPath) return false;
|
||||
if (typeof forbiddenPath === "string") {
|
||||
return (
|
||||
decodedHref === forbiddenPath ||
|
||||
decodedHref.indexOf(forbiddenPath + "/") === 0 ||
|
||||
(os.platform() === "win32" &&
|
||||
(decodedHref.toLowerCase() === forbiddenPath.toLowerCase() ||
|
||||
decodedHref
|
||||
.toLowerCase()
|
||||
.indexOf(forbiddenPath.toLowerCase() + "/") === 0))
|
||||
);
|
||||
}
|
||||
if (typeof forbiddenPath === "object") {
|
||||
return forbiddenPath.some(function (forbiddenPathSingle) {
|
||||
return (
|
||||
decodedHref === forbiddenPathSingle ||
|
||||
decodedHref.indexOf(forbiddenPathSingle + "/") === 0 ||
|
||||
(os.platform() === "win32" &&
|
||||
(decodedHref.toLowerCase() === forbiddenPathSingle.toLowerCase() ||
|
||||
decodedHref
|
||||
.toLowerCase()
|
||||
.indexOf(forbiddenPathSingle.toLowerCase() + "/") === 0))
|
||||
);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up forbidden paths
|
||||
var forbiddenPaths = {};
|
||||
// WARNING: This middleware is optimized for production SVR.JS, and may not work correctly for development SVR.JS.
|
||||
// Use "npm run dev" to test SVR.JS web server itself.
|
||||
const {
|
||||
getInitializePath,
|
||||
isForbiddenPath,
|
||||
isIndexOfForbiddenPath,
|
||||
forbiddenPaths,
|
||||
} = require("../utils/forbiddenPaths.js");
|
||||
|
||||
forbiddenPaths.config = getInitializePath("./config.json");
|
||||
forbiddenPaths.certificates = [];
|
||||
|
@ -96,8 +26,8 @@ if (process.serverConfig.secure) {
|
|||
forbiddenPaths.svrjs = getInitializePath(
|
||||
"./" +
|
||||
(process.dirname[process.dirname.length - 1] != "/"
|
||||
? __filename.replace(process.dirname + "/", "")
|
||||
: __filename.replace(process.dirname, "")),
|
||||
? process.filename.replace(process.dirname + "/", "")
|
||||
: process.filename.replace(process.dirname, "")),
|
||||
);
|
||||
forbiddenPaths.serverSideScripts = [];
|
||||
if (process.serverConfig.useWebRootServerSideScript) {
|
||||
|
|
87
src/utils/forbiddenPaths.js
Normal file
87
src/utils/forbiddenPaths.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
const os = require("os");
|
||||
const path = require("path");
|
||||
|
||||
// Function to get URL path for use in forbidden path adding.
|
||||
function getInitializePath(to) {
|
||||
const isWin32 = os.platform() == "win32";
|
||||
const pathModS = isWin32 ? path.win32 : path.posix; // pathModS needed just for the test suite
|
||||
const cwd = process.cwd();
|
||||
if (isWin32) {
|
||||
to = to.replace(/\//g, "\\");
|
||||
if (to[0] == "\\") to = cwd.split("\\")[0] + to;
|
||||
}
|
||||
const absoluteTo = pathModS.isAbsolute(to)
|
||||
? to
|
||||
: process.dirname + (isWin32 ? "\\" : "/") + to;
|
||||
if (isWin32 && cwd[0] != absoluteTo[0]) return "";
|
||||
const relative = pathModS.relative(cwd, absoluteTo);
|
||||
if (isWin32) {
|
||||
return "/" + relative.replace(/\\/g, "/");
|
||||
} else {
|
||||
return "/" + relative;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to check if URL path name is a forbidden path.
|
||||
function isForbiddenPath(decodedHref, match) {
|
||||
const forbiddenPath = forbiddenPaths[match];
|
||||
if (!forbiddenPath) return false;
|
||||
if (typeof forbiddenPath === "string") {
|
||||
return (
|
||||
decodedHref === forbiddenPath ||
|
||||
(os.platform() === "win32" &&
|
||||
decodedHref.toLowerCase() === forbiddenPath.toLowerCase())
|
||||
);
|
||||
}
|
||||
if (typeof forbiddenPath === "object") {
|
||||
return forbiddenPath.some(function (forbiddenPathSingle) {
|
||||
return (
|
||||
decodedHref === forbiddenPathSingle ||
|
||||
(os.platform() === "win32" &&
|
||||
decodedHref.toLowerCase() === forbiddenPathSingle.toLowerCase())
|
||||
);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function to check if URL path name is index of one of defined forbidden paths.
|
||||
function isIndexOfForbiddenPath(decodedHref, match) {
|
||||
const forbiddenPath = forbiddenPaths[match];
|
||||
if (!forbiddenPath) return false;
|
||||
if (typeof forbiddenPath === "string") {
|
||||
return (
|
||||
decodedHref === forbiddenPath ||
|
||||
decodedHref.indexOf(forbiddenPath + "/") === 0 ||
|
||||
(os.platform() === "win32" &&
|
||||
(decodedHref.toLowerCase() === forbiddenPath.toLowerCase() ||
|
||||
decodedHref
|
||||
.toLowerCase()
|
||||
.indexOf(forbiddenPath.toLowerCase() + "/") === 0))
|
||||
);
|
||||
}
|
||||
if (typeof forbiddenPath === "object") {
|
||||
return forbiddenPath.some(function (forbiddenPathSingle) {
|
||||
return (
|
||||
decodedHref === forbiddenPathSingle ||
|
||||
decodedHref.indexOf(forbiddenPathSingle + "/") === 0 ||
|
||||
(os.platform() === "win32" &&
|
||||
(decodedHref.toLowerCase() === forbiddenPathSingle.toLowerCase() ||
|
||||
decodedHref
|
||||
.toLowerCase()
|
||||
.indexOf(forbiddenPathSingle.toLowerCase() + "/") === 0))
|
||||
);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up forbidden paths
|
||||
let forbiddenPaths = {};
|
||||
|
||||
module.exports = {
|
||||
getInitializePath: getInitializePath,
|
||||
isForbiddenPath: isForbiddenPath,
|
||||
isIndexOfForbiddenPath: isIndexOfForbiddenPath,
|
||||
forbiddenPaths: forbiddenPaths,
|
||||
};
|
147
tests/utils/forbiddenPaths.test.js
Normal file
147
tests/utils/forbiddenPaths.test.js
Normal file
|
@ -0,0 +1,147 @@
|
|||
const {
|
||||
getInitializePath,
|
||||
isForbiddenPath,
|
||||
isIndexOfForbiddenPath,
|
||||
forbiddenPaths,
|
||||
} = require("../../src/utils/forbiddenPaths");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
|
||||
jest.mock("os", () => ({
|
||||
platform: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("Forbidden paths handling", () => {
|
||||
beforeEach(() => {
|
||||
os.platform.mockReset();
|
||||
forbiddenPaths.config = getInitializePath("./config.json");
|
||||
forbiddenPaths.serverSideScriptDirectories = [];
|
||||
forbiddenPaths.serverSideScriptDirectories.push(
|
||||
getInitializePath("./node_modules"),
|
||||
);
|
||||
forbiddenPaths.serverSideScriptDirectories.push(
|
||||
getInitializePath("./mods"),
|
||||
);
|
||||
process.cwd = () => "/usr/lib/mocksvrjs";
|
||||
process.dirname = "/usr/lib/mocksvrjs";
|
||||
process.filename = "/usr/lib/mocksvrjs/svr.js";
|
||||
});
|
||||
|
||||
describe("getInitializePath", () => {
|
||||
test("should return the correct path on Unix", () => {
|
||||
os.platform.mockReturnValue("linux");
|
||||
expect(getInitializePath("./config.json")).toBe("/config.json");
|
||||
});
|
||||
|
||||
test("should return the correct path on Windows", () => {
|
||||
process.cwd = () => "C:\\mocksvrjs";
|
||||
process.dirname = "C:\\mocksvrjs";
|
||||
process.filename = "C:\\mocksvrjs\\svr.js";
|
||||
os.platform.mockReturnValue("win32");
|
||||
expect(getInitializePath("./config.json")).toBe("/config.json");
|
||||
});
|
||||
|
||||
test("should handle absolute paths on Unix", () => {
|
||||
os.platform.mockReturnValue("linux");
|
||||
expect(getInitializePath("/absolute/path")).toBe(
|
||||
"/../../../absolute/path",
|
||||
);
|
||||
});
|
||||
|
||||
test("should handle absolute paths on Windows", () => {
|
||||
process.cwd = () => "C:\\mocksvrjs";
|
||||
process.dirname = "C:\\mocksvrjs";
|
||||
process.filename = "C:\\mocksvrjs\\svr.js";
|
||||
os.platform.mockReturnValue("win32");
|
||||
expect(getInitializePath("C:\\absolute\\path")).toBe("/../absolute/path");
|
||||
});
|
||||
|
||||
test("should handle relative paths on Unix", () => {
|
||||
os.platform.mockReturnValue("linux");
|
||||
expect(getInitializePath("./relative/path")).toBe("/relative/path");
|
||||
});
|
||||
|
||||
test("should handle relative paths on Windows", () => {
|
||||
process.cwd = () => "C:\\mocksvrjs";
|
||||
process.dirname = "C:\\mocksvrjs";
|
||||
process.filename = "C:\\mocksvrjs\\svr.js";
|
||||
os.platform.mockReturnValue("win32");
|
||||
expect(getInitializePath("./relative\\path")).toBe("/relative/path");
|
||||
});
|
||||
});
|
||||
|
||||
describe("isForbiddenPath", () => {
|
||||
test("should return true if the path is forbidden", () => {
|
||||
os.platform.mockReturnValue("linux");
|
||||
expect(isForbiddenPath("/config.json", "config")).toBe(true);
|
||||
});
|
||||
|
||||
test("should return false if the path is not forbidden", () => {
|
||||
os.platform.mockReturnValue("linux");
|
||||
expect(isForbiddenPath("/notconfig.json", "config")).toBe(false);
|
||||
});
|
||||
|
||||
test("should handle case insensitivity on Windows", () => {
|
||||
process.cwd = () => "C:\\mocksvrjs";
|
||||
process.dirname = "C:\\mocksvrjs";
|
||||
process.filename = "C:\\mocksvrjs\\svr.js";
|
||||
os.platform.mockReturnValue("win32");
|
||||
expect(isForbiddenPath("/CONFIG.JSON", "config")).toBe(true);
|
||||
});
|
||||
|
||||
test("should handle array of forbidden paths", () => {
|
||||
os.platform.mockReturnValue("linux");
|
||||
expect(
|
||||
isForbiddenPath("/node_modules", "serverSideScriptDirectories"),
|
||||
).toBe(true);
|
||||
expect(isForbiddenPath("/mods", "serverSideScriptDirectories")).toBe(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
isForbiddenPath("/notforbidden", "serverSideScriptDirectories"),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isIndexOfForbiddenPath", () => {
|
||||
test("should return true if the path is an index of a forbidden path", () => {
|
||||
os.platform.mockReturnValue("linux");
|
||||
expect(isIndexOfForbiddenPath("/config.json", "config")).toBe(true);
|
||||
expect(
|
||||
isIndexOfForbiddenPath("/node_modules/", "serverSideScriptDirectories"),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test("should return false if the path is not an index of a forbidden path", () => {
|
||||
os.platform.mockReturnValue("linux");
|
||||
expect(isIndexOfForbiddenPath("/notconfig.json", "config")).toBe(false);
|
||||
expect(
|
||||
isIndexOfForbiddenPath("/notforbidden/", "serverSideScriptDirectories"),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test("should handle case insensitivity on Windows", () => {
|
||||
process.cwd = () => "C:\\mocksvrjs";
|
||||
process.dirname = "C:\\mocksvrjs";
|
||||
process.filename = "C:\\mocksvrjs\\svr.js";
|
||||
os.platform.mockReturnValue("win32");
|
||||
expect(isIndexOfForbiddenPath("/CONFIG.JSON", "config")).toBe(true);
|
||||
expect(
|
||||
isIndexOfForbiddenPath("/NODE_MODULES/", "serverSideScriptDirectories"),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test("should handle array of forbidden paths", () => {
|
||||
os.platform.mockReturnValue("linux");
|
||||
expect(
|
||||
isIndexOfForbiddenPath("/node_modules/", "serverSideScriptDirectories"),
|
||||
).toBe(true);
|
||||
expect(
|
||||
isIndexOfForbiddenPath("/mods/", "serverSideScriptDirectories"),
|
||||
).toBe(true);
|
||||
expect(
|
||||
isIndexOfForbiddenPath("/notforbidden/", "serverSideScriptDirectories"),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
Reference in a new issue