1
0
Fork 0
forked from svrjs/svrjs

Update to SVR.JS 4.0.0-beta3

This commit is contained in:
Dorian Niemiec 2024-08-30 08:09:02 +02:00
parent 920d942016
commit c5af172d1e
26 changed files with 201 additions and 184 deletions

View file

@ -217,17 +217,13 @@ esbuild
archive.pipe(output);
// Add everything in the "dist" directory except for "svr.js" and "svr.compressed"
const distFilesAndDirectories = fs.existsSync(__dirname + "/dist")
? fs.readdirSync(__dirname + "/dist")
: [];
distFilesAndDirectories.forEach((entry) => {
if (entry == "svr.js" || entry == "svr.compressed") return;
const stats = fs.statSync(__dirname + "/dist/" + entry);
if (stats.isDirectory()) {
archive.directory(__dirname + "/dist/" + entry, entry);
} else if (stats.isFile()) {
archive.file(__dirname + "/dist/" + entry, { name: entry });
}
archive.glob("**/*", {
cwd: __dirname + "/dist",
ignore: [
"svr.js",
"svr.compressed"
],
dot: true
});
// Create a stream for the "svr.compressed" file

View file

@ -44,7 +44,7 @@ function clientErrorHandler(err, socket) {
if (err.code === "ECONNRESET" || !socket.writable) {
return;
}
socket.end(x, function () {
socket.end(x, () => {
try {
socket.destroy();
// eslint-disable-next-line no-unused-vars
@ -60,9 +60,9 @@ function clientErrorHandler(err, socket) {
headers = Object.assign({}, headers);
headers["Date"] = new Date().toGMTString();
headers["Connection"] = "close";
Object.keys(headers).forEach(function (headername) {
Object.keys(headers).forEach((headername) => {
if (headername.toLowerCase() == "set-cookie") {
headers[headername].forEach(function (headerValueS) {
headers[headername].forEach((headerValueS) => {
if (
// eslint-disable-next-line no-control-regex
headername.match(/[^\x09\x20-\x7e\x80-\xff]|.:/) ||
@ -105,7 +105,7 @@ function clientErrorHandler(err, socket) {
locmessage: (msg) => serverconsole.locmessage(msg, reqId),
};
socket.on("close", function (hasError) {
socket.on("close", (hasError) => {
if (
!hasError ||
err.code == "ERR_SSL_HTTP_REQUEST" ||
@ -114,7 +114,7 @@ function clientErrorHandler(err, socket) {
logFacilities.locmessage("Client disconnected.");
else logFacilities.locmessage("Client disconnected due to error.");
});
socket.on("error", function () {});
socket.on("error", () => {});
// Header and footer placeholders
let head = "";
@ -178,7 +178,7 @@ function clientErrorHandler(err, socket) {
if (p) callback(p);
else {
if (errorCode == 404) {
fs.access(config.page404, fs.constants.F_OK, function (err) {
fs.access(config.page404, fs.constants.F_OK, (err) => {
if (err) {
fs.access(
"." + errorCode.toString(),
@ -229,7 +229,7 @@ function clientErrorHandler(err, socket) {
getErrorFileName(list, callback, _i + 1);
return;
} else {
fs.access(list[_i].path, fs.constants.F_OK, function (err) {
fs.access(list[_i].path, fs.constants.F_OK, (err) => {
if (err) {
getErrorFileName(list, callback, _i + 1);
} else {
@ -239,7 +239,7 @@ function clientErrorHandler(err, socket) {
}
};
getErrorFileName(config.errorPages, function (errorFile) {
getErrorFileName(config.errorPages, (errorFile) => {
if (Object.prototype.toString.call(stack) === "[object Error]")
stack = generateErrorStack(stack);
if (stack === undefined)
@ -313,7 +313,7 @@ function clientErrorHandler(err, socket) {
);
res.end();
} else {
fs.readFile(errorFile, function (err, data) {
fs.readFile(errorFile, (err, data) => {
try {
if (err) throw err;
res.writeHead(errorCode, http.STATUS_CODES[errorCode], cheaders);

View file

@ -29,8 +29,8 @@ function noproxyHandler(req, socket, head) {
// SVR.JS configuration object (modified)
const config = deepClone(process.serverConfig);
var reqip = socket.remoteAddress;
var reqport = socket.remotePort;
const reqip = socket.remoteAddress;
const reqport = socket.remotePort;
process.reqcounter++;
logFacilities.locmessage(
`Somebody connected to ${

View file

@ -32,12 +32,11 @@ function proxyHandler(req, socket, head) {
// SVR.JS configuration object (modified)
const config = deepClone(process.serverConfig);
config.generateServerString = () => {
return generateServerString(config.exposeServerVersion);
};
config.generateServerString = () =>
generateServerString(config.exposeServerVersion);
var reqip = socket.remoteAddress;
var reqport = socket.remotePort;
const reqip = socket.remoteAddress;
const reqport = socket.remotePort;
process.reqcounter++;
logFacilities.locmessage(
`Somebody connected to ${

View file

@ -34,9 +34,8 @@ function requestHandler(req, res) {
// SVR.JS configuration object (modified)
const config = deepClone(process.serverConfig);
config.generateServerString = () => {
return generateServerString(config.exposeServerVersion);
};
config.generateServerString = () =>
generateServerString(config.exposeServerVersion);
// getCustomHeaders() in SVR.JS 3.x
config.getCustomHeaders = () => {
@ -79,7 +78,7 @@ function requestHandler(req, res) {
if (table == undefined) table = this.tHeaders;
if (table == undefined) table = {};
table = Object.assign({}, table);
Object.keys(table).forEach(function (key) {
Object.keys(table).forEach((key) => {
const al = key.toLowerCase();
if (
al == "transfer-encoding" ||
@ -343,7 +342,7 @@ function requestHandler(req, res) {
if (p) callback(p);
else {
if (errorCode == 404) {
fs.access(config.page404, fs.constants.F_OK, function (err) {
fs.access(config.page404, fs.constants.F_OK, (err) => {
if (err) {
fs.access(
"." + errorCode.toString(),
@ -400,7 +399,7 @@ function requestHandler(req, res) {
getErrorFileName(list, callback, _i + 1);
return;
} else {
fs.access(list[_i].path, fs.constants.F_OK, function (err) {
fs.access(list[_i].path, fs.constants.F_OK, (err) => {
if (err) {
getErrorFileName(list, callback, _i + 1);
} else {
@ -410,7 +409,7 @@ function requestHandler(req, res) {
}
};
getErrorFileName(config.errorPages, function (errorFile) {
getErrorFileName(config.errorPages, (errorFile) => {
// Generate error stack if not provided
if (Object.prototype.toString.call(stack) === "[object Error]")
stack = generateErrorStack(stack);
@ -442,7 +441,7 @@ function requestHandler(req, res) {
cheaders["Allow"] = "GET, POST, HEAD, OPTIONS";
// Read the error file and replace placeholders with error information
fs.readFile(errorFile, function (err, data) {
fs.readFile(errorFile, (err, data) => {
try {
if (err) throw err;
res.writeHead(errorCode, http.STATUS_CODES[errorCode], cheaders);

View file

@ -38,7 +38,7 @@ function serverErrorHandler(err, isRedirect, server, start) {
} catch (err) {
// Probably main process exited
}
setTimeout(function () {
setTimeout(() => {
const errno = os.constants.errno[err.code];
process.exit(errno !== undefined ? errno : 1);
}, 50);

View file

@ -134,16 +134,14 @@ for (
args[i] == "/h" ||
args[i] == "/?"
) {
console.log(name + " usage:");
console.log(`${name} usage:`);
console.log(
"node svr.js [-h] [--help] [-?] [/h] [/?] [--secure] [--reset] [--clean] [--disable-mods] [--single-threaded] [-v] [--version]",
);
console.log("-h -? /h /? --help -- Displays help");
console.log("--clean -- Cleans up files created by " + name);
console.log(
"--reset -- Resets " +
name +
" to default settings (WARNING: DANGEROUS)",
`--reset -- Resets ${name} to default settings (WARNING: DANGEROUS)`,
);
console.log("--secure -- Runs HTTPS server");
console.log("--disable-mods -- Disables mods (safe mode)");
@ -180,17 +178,15 @@ for (
} else if (args[i] == "--single-threaded") {
process.singleThreaded = true;
} else {
console.log("Unrecognized argument: " + args[i]);
console.log(name + " usage:");
console.log(`Unrecognized argument: ${args[i]}`);
console.log(`${name} usage:`);
console.log(
"node svr.js [-h] [--help] [-?] [/h] [/?] [--secure] [--reset] [--clean] [--disable-mods] [--single-threaded] [-v] [--version]",
);
console.log("-h -? /h /? --help -- Displays help");
console.log("--clean -- Cleans up files created by " + name);
console.log(
"--reset -- Resets " +
name +
" to default settings (WARNING: DANGEROUS)",
`--reset -- Resets ${name} to default settings (WARNING: DANGEROUS)`,
);
console.log("--secure -- Runs HTTPS server");
console.log("--disable-mods -- Disables mods (safe mode)");
@ -422,7 +418,7 @@ try {
} catch (err) {
ifaceEx = err;
}
var ips = [];
let ips = [];
const brdIPs = ["255.255.255.255", "127.255.255.255", "0.255.255.255"];
const netIPs = ["127.0.0.0"];
@ -461,7 +457,7 @@ if (ips.length == 0) {
}
// Server IP address
var host = ips[ips.length - 1];
let host = ips[ips.length - 1];
if (!host) host = "[offline]";
// Public IP address-related
@ -821,7 +817,7 @@ if (!disableMods) {
crypto.__disabled__ === undefined
? "var crypto = require('crypto');\r\nvar https = require('https');\r\n"
: ""
}var stream = require('stream');\r\nvar customvar1;\r\nvar customvar2;\r\nvar customvar3;\r\nvar customvar4;\r\n\r\nfunction Mod() {}\r\nMod.prototype.callback = function callback(req, res, serverconsole, responseEnd, href, ext, uobject, search, defaultpage, users, page404, head, foot, fd, elseCallback, configJSON, callServerError, getCustomHeaders, origHref, redirect, parsePostData, authUser) {\r\nreturn () => {\r\nvar disableEndElseCallbackExecute = false;\r\nfunction filterHeaders(e){var r={};return Object.keys(e).forEach(((t) => {null!==e[t]&&void 0!==e[t]&&("object"==typeof e[t]?r[t]=JSON.parse(JSON.stringify(e[t])):r[t]=e[t])})),r}\r\nfunction checkHostname(e){if(void 0===e||"*"==e)return!0;if(req.headers.host&&0==e.indexOf("*.")&&"*."!=e){var r=e.substring(2);if(req.headers.host==r||req.headers.host.indexOf("."+r)==req.headers.host.length-r.length-1)return!0}else if(req.headers.host&&req.headers.host==e)return!0;return!1}\r\nfunction checkHref(e){return href==e||"win32"==os.platform()&&href.toLowerCase()==e.toLowerCase()}\r\n`;
}var stream = require('stream');\r\nvar customvar1;\r\nvar customvar2;\r\nvar customvar3;\r\nvar customvar4;\r\n\r\nfunction Mod() {}\r\nMod.prototype.callback = function callback(req, res, serverconsole, responseEnd, href, ext, uobject, search, defaultpage, users, page404, head, foot, fd, elseCallback, configJSON, callServerError, getCustomHeaders, origHref, redirect, parsePostData, authUser) {\r\nreturn function() {\r\nvar disableEndElseCallbackExecute = false;\r\nfunction filterHeaders(e){var r={};return Object.keys(e).forEach((function(t){null!==e[t]&&void 0!==e[t]&&("object"==typeof e[t]?r[t]=JSON.parse(JSON.stringify(e[t])):r[t]=e[t])})),r}\r\nfunction checkHostname(e){if(void 0===e||"*"==e)return!0;if(req.headers.host&&0==e.indexOf("*.")&&"*."!=e){var r=e.substring(2);if(req.headers.host==r||req.headers.host.indexOf("."+r)==req.headers.host.length-r.length-1)return!0}else if(req.headers.host&&req.headers.host==e)return!0;return!1}\r\nfunction checkHref(e){return href==e||"win32"==os.platform()&&href.toLowerCase()==e.toLowerCase()}\r\n`;
const modfoot =
"\r\nif(!disableEndElseCallbackExecute) {\r\ntry{\r\nelseCallback();\r\n} catch(err) {\r\n}\r\n}\r\n}\r\n}\r\nmodule.exports = Mod;";
// Write the modified server side script to the temp folder
@ -1132,7 +1128,7 @@ if (process.serverConfig.secure) {
key: sniCredentialsSingle.key,
});
try {
var snMatches = sniCredentialsSingle.name.match(
let snMatches = sniCredentialsSingle.name.match(
/^([^:[]*|\[[^]]*\]?)((?::.*)?)$/,
);
if (!snMatches[1][0].match(/^\.+$/))
@ -1414,7 +1410,7 @@ function SVRJSFork() {
"Starting next thread, because previous one hung up/crashed...",
);
// Fork new worker
var newWorker = {};
let newWorker = {};
try {
if (
!threadLimitWarned &&
@ -1518,7 +1514,7 @@ function getWorkerCountToFork() {
}
function forkWorkers(workersToFork, callback) {
for (var i = 0; i < workersToFork; i++) {
for (let i = 0; i < workersToFork; i++) {
if (i == 0) {
SVRJSFork();
} else {
@ -1582,9 +1578,9 @@ function msgListener(message) {
// Save configuration file
function saveConfig() {
for (var i = 0; i < 3; i++) {
for (let i = 0; i < 3; i++) {
try {
var configJSONobj = {};
let configJSONobj = {};
if (fs.existsSync(process.dirname + "/config.json"))
configJSONobj = JSON.parse(
fs.readFileSync(process.dirname + "/config.json").toString(),
@ -1674,12 +1670,14 @@ function saveConfig() {
if (configJSONobj.optOutOfStatisticsServer === undefined)
configJSONobj.optOutOfStatisticsServer = false;
var configString = JSON.stringify(configJSONobj, null, 2) + "\n";
fs.writeFileSync(__dirname + "/config.json", configString);
fs.writeFileSync(
process.dirname + "/config.json",
JSON.stringify(configJSONobj, null, 2) + "\n",
);
break;
} catch (err) {
if (i >= 2) throw err;
var now = Date.now();
const now = Date.now();
while (Date.now() - now < 2);
}
}
@ -1717,9 +1715,7 @@ function start(init) {
/^(?:0\.|1\.0\.|1\.1\.[0-9](?![0-9])|1\.1\.1[0-2](?![0-9]))/,
)
) &&
process.serverConfig.users.some((entry) => {
return entry.pbkdf2;
})
process.serverConfig.users.some((entry) => entry.pbkdf2)
)
serverconsole.locwarnmessage(
"PBKDF2 password hashing function in Bun versions older than v1.1.13 blocks the event loop, which may result in denial of service.",
@ -1967,8 +1963,8 @@ function start(init) {
}, 300000);
} else if (cluster.isPrimary) {
setInterval(() => {
var allWorkers = Object.keys(cluster.workers);
var goodWorkers = [];
let allWorkers = Object.keys(cluster.workers);
let goodWorkers = [];
const checkWorker = (callback, _id) => {
if (typeof _id === "undefined") _id = 0;
@ -2058,8 +2054,8 @@ function start(init) {
commands[line.split(" ")[0]] !== undefined &&
commands[line.split(" ")[0]] !== null
) {
var argss = line.split(" ");
var command = argss.shift();
let argss = line.split(" ");
const command = argss.shift();
commands[command](argss, (msg) => process.send(msg));
process.send("\x12END");
} else {
@ -2087,15 +2083,15 @@ function start(init) {
const command = argss.shift();
if (line != "") {
if (cluster.isPrimary !== undefined) {
var allWorkers = Object.keys(cluster.workers);
let allWorkers = Object.keys(cluster.workers);
if (command == "block")
commands.block(argss, serverconsole.climessage);
if (command == "unblock")
commands.unblock(argss, serverconsole.climessage);
if (command == "restart") {
var stopError = false;
let stopError = false;
exiting = true;
for (var i = 0; i < allWorkers.length; i++) {
for (let i = 0; i < allWorkers.length; i++) {
try {
if (cluster.workers[allWorkers[i]]) {
cluster.workers[allWorkers[i]].kill();
@ -2150,9 +2146,7 @@ function start(init) {
commands[command](argss, serverconsole.climessage);
// eslint-disable-next-line no-unused-vars
} catch (err) {
serverconsole.climessage(
'Unrecognized command "' + command + '".',
);
serverconsole.climessage(`Unrecognized command "${command}".`);
}
}
}
@ -2224,7 +2218,7 @@ function start(init) {
!process.serverConfig.secure
) {
// It doesn't support through Unix sockets or Windows named pipes
var address = (
let address = (
typeof process.serverConfig.port == "number" && listenAddress
? listenAddress
: "localhost"
@ -2232,7 +2226,7 @@ function start(init) {
if (address.indexOf(":") > -1) {
address = "[" + address + "]";
}
var connection = http2.connect(
const connection = http2.connect(
"http://" +
address +
":" +

View file

@ -23,14 +23,14 @@ module.exports.commands = {
if (ip == undefined || JSON.stringify(ip) == "[]") {
if (!cluster.isPrimary === false) log("Cannot block non-existent IP.");
} else {
for (var i = 0; i < ip.length; i++) {
if (ip[i] != "localhost" && ip[i].indexOf(":") == -1) {
ip[i] = "::ffff:" + ip[i];
ip.forEach((ipAddress) => {
if (ipAddress !== "localhost" && ipAddress.indexOf(":") == -1) {
ipAddress = "::ffff:" + ipAddress;
}
if (!blocklist.check(ip[i])) {
blocklist.add(ip[i]);
if (!blocklist.check(ipAddress)) {
blocklist.add(ipAddress);
}
}
});
process.serverConfig.blacklist = blocklist.raw;
if (!cluster.isPrimary === false) log("IPs successfully blocked.");
passCommand(ip, log);
@ -40,12 +40,12 @@ module.exports.commands = {
if (ip == undefined || JSON.stringify(ip) == "[]") {
if (!cluster.isPrimary === false) log("Cannot unblock non-existent IP.");
} else {
for (var i = 0; i < ip.length; i++) {
if (ip[i].indexOf(":") == -1) {
ip[i] = "::ffff:" + ip[i];
ip.forEach((ipAddress) => {
if (ipAddress !== "localhost" && ipAddress.indexOf(":") == -1) {
ipAddress = "::ffff:" + ipAddress;
}
blocklist.remove(ip[i]);
}
blocklist.remove(ipAddress);
});
process.serverConfig.blacklist = blocklist.raw;
if (!cluster.isPrimary === false) log("IPs successfully unblocked.");
passCommand(ip, log);

View file

@ -29,7 +29,7 @@ let passwordHashCacheIntervalId = -1;
// Non-standard code object
let nonStandardCodes = [];
process.serverConfig.nonStandardCodes.forEach((nonStandardCodeRaw) => {
var newObject = {};
let newObject = {};
Object.keys(nonStandardCodeRaw).forEach((nsKey) => {
if (nsKey != "users") {
newObject[nsKey] = nonStandardCodeRaw[nsKey];
@ -42,12 +42,12 @@ process.serverConfig.nonStandardCodes.forEach((nonStandardCodeRaw) => {
if (!cluster.isPrimary) {
passwordHashCacheIntervalId = setInterval(() => {
pbkdf2Cache = pbkdf2Cache.filter((entry) => {
return entry.addDate > new Date() - 3600000;
});
scryptCache = scryptCache.filter((entry) => {
return entry.addDate > new Date() - 3600000;
});
pbkdf2Cache = pbkdf2Cache.filter(
(entry) => entry.addDate > new Date() - 3600000,
);
scryptCache = scryptCache.filter(
(entry) => entry.addDate > new Date() - 3600000,
);
}, 1800000);
}
@ -77,7 +77,7 @@ module.exports = (req, res, logFacilities, config, next) => {
);
if (nonStandardCodes[i].regex) {
// Regex match
var createdRegex = createRegex(nonStandardCodes[i].regex, true);
const createdRegex = createRegex(nonStandardCodes[i].regex, true);
isMatch =
req.url.match(createdRegex) ||
hrefWithoutDuplicateSlashes.match(createdRegex);
@ -192,11 +192,10 @@ module.exports = (req, res, logFacilities, config, next) => {
);
return;
} else {
cacheEntry = scryptCache.find((entry) => {
return (
entry.password == hashedPassword && entry.salt == list[_i].salt
);
});
cacheEntry = scryptCache.find(
(entry) =>
entry.password == hashedPassword && entry.salt == list[_i].salt,
);
if (cacheEntry) {
cb(cacheEntry.hash);
} else {
@ -226,11 +225,10 @@ module.exports = (req, res, logFacilities, config, next) => {
);
return;
} else {
cacheEntry = pbkdf2Cache.find((entry) => {
return (
entry.password == hashedPassword && entry.salt == list[_i].salt
);
});
cacheEntry = pbkdf2Cache.find(
(entry) =>
entry.password == hashedPassword && entry.salt == list[_i].salt,
);
if (cacheEntry) {
cb(cacheEntry.hash);
} else {

View file

@ -9,7 +9,7 @@ module.exports = (req, res, logFacilities, config, next) => {
!config.disableNonEncryptedServer &&
!config.disableToHTTPSRedirect
) {
var hostx = req.headers.host;
const hostx = req.headers.host;
if (hostx === undefined) {
logFacilities.errmessage("Host header is missing.");
res.error(400);
@ -22,7 +22,7 @@ module.exports = (req, res, logFacilities, config, next) => {
return;
}
var isPublicServer = !(
const isPublicServer = !(
req.socket.realRemoteAddress
? req.socket.realRemoteAddress
: req.socket.remoteAddress
@ -30,11 +30,11 @@ module.exports = (req, res, logFacilities, config, next) => {
/^(?:localhost$|::1$|f[c-d][0-9a-f]{2}:|(?:::ffff:)?(?:(?:127|10)\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}|192\.168\.[0-9]{1,3}\.[0-9]{1,3}|172\.(?:1[6-9]|2[0-9]|3[0-1])\.[0-9]{1,3}\.[0-9]{1,3})$)/i,
);
var destinationPort = 0;
let destinationPort = 0;
var parsedHostx = hostx.match(/(\[[^\]]*\]|[^:]*)(?::([0-9]+))?/);
var hostname = parsedHostx[1];
var hostPort = parsedHostx[2] ? parseInt(parsedHostx[2]) : 80;
const parsedHostx = hostx.match(/(\[[^\]]*\]|[^:]*)(?::([0-9]+))?/);
let hostname = parsedHostx[1];
let hostPort = parsedHostx[2] ? parseInt(parsedHostx[2]) : 80;
if (isNaN(hostPort)) hostPort = 80;
if (

View file

@ -1,6 +1,6 @@
module.exports = (req, res, logFacilities, config, next) => {
if (!req.isProxy) {
var hkh = config.getCustomHeaders();
const hkh = config.getCustomHeaders();
Object.keys(hkh).forEach((hkS) => {
try {
res.setHeader(hkS, hkh[hkS]);

View file

@ -30,7 +30,7 @@ module.exports = (req, res, logFacilities, config, next) => {
fs.stat(
"." + decodeURIComponent(req.parsedURL.pathname),
(err, stats) => {
var _fileState = 3;
let _fileState = 3;
if (err) {
_fileState = 3;
} else if (stats.isDirectory()) {
@ -126,7 +126,7 @@ module.exports = (req, res, logFacilities, config, next) => {
logFacilities.errmessage("Content blocked.");
return;
} else if (sHref != req.parsedURL.pathname) {
var rewrittenAgainURL =
const rewrittenAgainURL =
sHref +
(req.parsedURL.search ? req.parsedURL.search : "") +
(req.parsedURL.hash ? req.parsedURL.hash : "");

View file

@ -34,7 +34,7 @@ module.exports = (req, res, logFacilities, config, next) => {
let levelDownCount = 0;
// Loop through the path components
for (var i = 0; i < pathComponents.length; i++) {
for (let i = 0; i < pathComponents.length; i++) {
// If the component is "..", decrement the levelUpCount
if (".." === pathComponents[i]) {
levelUpCount--;
@ -313,7 +313,7 @@ module.exports = (req, res, logFacilities, config, next) => {
// Helper function to check if compression is allowed for the file
const canCompress = (path, list) => {
let canCompress = true;
for (var i = 0; i < list.length; i++) {
for (let i = 0; i < list.length; i++) {
if (createRegex(list[i], true).test(path)) {
canCompress = false;
break;
@ -437,7 +437,7 @@ module.exports = (req, res, logFacilities, config, next) => {
})
.on("open", () => {
try {
var resStream = {};
let resStream = {};
if (useBrotli && isCompressable) {
resStream = zlib.createBrotliCompress();
resStream.pipe(res);
@ -738,7 +738,7 @@ module.exports = (req, res, logFacilities, config, next) => {
// Get stats for all files in the directory and generate the listing
getStatsForAllFiles(list, readFrom, (filelist) => {
let directoryListingRows = [];
for (var i = 0; i < filelist.length; i++) {
for (let i = 0; i < filelist.length; i++) {
if (filelist[i].name[0] !== ".") {
const estats = filelist[i].stats;
const ename = filelist[i].name;
@ -773,7 +773,7 @@ module.exports = (req, res, logFacilities, config, next) => {
.replace(/>/g, "&gt;")}</a></td><td>${
estats.isDirectory()
? "-"
: sizify(estats.size.toString())
: sizify(estats.size)
}</td><td>${estats.mtime.toDateString()}</td></tr>\r\n`;
// Determine the file type and set the appropriate image and alt text

View file

@ -26,9 +26,7 @@ if (!process.singleThreaded) {
cluster.worker = {
id: parseInt(process.env.NODE_UNIQUE_ID),
process: process,
isDead: () => {
return false;
},
isDead: () => false,
send: (message, ...params) => {
process.send(message, ...params);
},
@ -98,9 +96,7 @@ if (!process.singleThreaded) {
});
newWorker.process = newWorker;
newWorker.isDead = () => {
return newWorker.exitCode !== null || newWorker.killed;
};
newWorker.isDead = () => newWorker.exitCode !== null || newWorker.killed;
newWorker.id = newEnvironment.NODE_UNIQUE_ID;
function checkSendImplementation(worker) {

View file

@ -54,16 +54,23 @@ function isIndexOfForbiddenPath(decodedHref, match) {
if (typeof forbiddenPath === "string") {
const forbiddenPathLower = isWin32 ? forbiddenPath.toLowerCase() : null;
return isWin32
? decodedHrefLower.indexOf(forbiddenPathLower) == 0
: decodedHref.indexOf(forbiddenPath) == 0;
? decodedHrefLower === forbiddenPathLower ||
decodedHrefLower.indexOf(forbiddenPathLower + "/") == 0
: decodedHref === forbiddenPath ||
decodedHref.indexOf(forbiddenPath + "/") == 0;
}
if (typeof forbiddenPath === "object") {
return isWin32
? forbiddenPath.some(
(path) => decodedHrefLower.indexOf(path.toLowerCase()) == 0,
(path) =>
decodedHrefLower === path.toLowerCase() ||
decodedHrefLower.indexOf(path.toLowerCase() + "/") == 0,
)
: forbiddenPath.some((path) => decodedHref.indexOf(path) == 0);
: forbiddenPath.some(
(path) =>
decodedHref === path || decodedHref.indexOf(path + "/") == 0,
);
}
return false;

View file

@ -1,19 +1,19 @@
// Generate V8-style error stack from Error object.
function generateErrorStack(errorObject) {
// Split the error stack by newlines.
var errorStack = errorObject.stack ? errorObject.stack.split("\n") : [];
const errorStack = errorObject.stack ? errorObject.stack.split("\n") : [];
// If the error stack starts with the error name, return the original stack (it is V8-style then).
if (
errorStack.some((errorStackLine) => {
return errorStackLine.indexOf(errorObject.name) == 0;
})
errorStack.some(
(errorStackLine) => errorStackLine.indexOf(errorObject.name) == 0,
)
) {
return errorObject.stack;
}
// Create a new error stack with the error name and code (if available).
var newErrorStack = [
let newErrorStack = [
errorObject.name +
(errorObject.code ? ": " + errorObject.code : "") +
(errorObject.message == "" ? "" : ": " + errorObject.message),
@ -23,12 +23,12 @@ function generateErrorStack(errorObject) {
errorStack.forEach((errorStackLine) => {
if (errorStackLine != "") {
// Split the line into function and location parts (if available).
var errorFrame = errorStackLine.split("@");
var location = "";
let errorFrame = errorStackLine.split("@");
let location = "";
if (errorFrame.length > 1 && errorFrame[0] == "global code")
errorFrame.shift();
if (errorFrame.length > 1) location = errorFrame.pop();
var func = errorFrame.join("@");
const func = errorFrame.join("@");
// Build the new error stack entry with function and location information.
newErrorStack.push(

View file

@ -1,12 +1,12 @@
const os = require("os");
function getOS() {
var osType = os.type();
var platform = os.platform();
const osType = os.type();
const platform = os.platform();
if (platform == "android") {
return "Android";
} else if (osType == "Windows_NT" || osType == "WindowsNT") {
var arch = os.arch();
const arch = os.arch();
if (arch == "ia32") {
return "Win32";
} else if (arch == "x64") {

View file

@ -2,7 +2,7 @@
function ipBlockList(rawBlockList) {
// Initialize the instance with empty arrays
if (rawBlockList === undefined) rawBlockList = [];
var instance = {
const instance = {
raw: [],
rawtoPreparedMap: [],
prepared: [],
@ -10,9 +10,8 @@ function ipBlockList(rawBlockList) {
};
// Function to normalize IPv4 address (remove leading zeros)
const normalizeIPv4Address = (address) => {
return address.replace(/(^|\.)(?:0(?!\.|$))+/g, "$1");
};
const normalizeIPv4Address = (address) =>
address.replace(/(^|\.)(?:0(?!\.|$))+/g, "$1");
// Function to expand IPv6 address to full format
const expandIPv6Address = (address) => {
@ -236,9 +235,7 @@ function ipBlockList(rawBlockList) {
? checkIfIPv4CIDRMatches
: checkIfIPv6CIDRMatches;
return instance.cidrs.some((iCidr) => {
return checkMethod(ipParsedObject, iCidr);
});
return instance.cidrs.some((iCidr) => checkMethod(ipParsedObject, iCidr));
};
// Add initial raw block list values to the instance

View file

@ -4,9 +4,8 @@ function ipMatch(IP1, IP2) {
if (!IP2) return false;
// Function to normalize IPv4 address (remove leading zeros)
const normalizeIPv4Address = (address) => {
return address.replace(/(^|\.)(?:0(?!\.|$))+/g, "$1");
};
const normalizeIPv4Address = (address) =>
address.replace(/(^|\.)(?:0(?!\.|$))+/g, "$1");
// Function to expand IPv6 address to full format
const expandIPv6Address = (address) => {

View file

@ -14,7 +14,7 @@ function calculateBroadcastIPv4FromCidr(ipWithCidr) {
.split(".")
.map((num, index) => {
// Calculate resulting 8-bit
var power = Math.max(Math.min(mask - index * 8, 8), 0);
const power = Math.max(Math.min(mask - index * 8, 8), 0);
return (
(parseInt(num) & ((Math.pow(2, power) - 1) << (8 - power))) |
(Math.pow(2, 8 - power) - 1)
@ -39,7 +39,7 @@ function calculateNetworkIPv4FromCidr(ipWithCidr) {
.split(".")
.map((num, index) => {
// Calculate resulting 8-bit
var power = Math.max(Math.min(mask - index * 8, 8), 0);
const power = Math.max(Math.min(mask - index * 8, 8), 0);
return (
parseInt(num) &
((Math.pow(2, power) - 1) << (8 - power))

View file

@ -78,7 +78,7 @@ function LOG(s) {
}
// Server console function
var serverconsole = {
const serverconsole = {
climessage: (msg, reqId) => {
if (msg.indexOf("\n") != -1) {
msg.split("\n").forEach((nmsg) => {

View file

@ -22,37 +22,14 @@ function sha256(s) {
return (msw << 16) | (lsw & 0xffff);
};
const S = (X, n) => {
return (X >>> n) | (X << (32 - n));
};
const R = (X, n) => {
return X >>> n;
};
const Ch = (x, y, z) => {
return (x & y) ^ (~x & z);
};
const Maj = (x, y, z) => {
return (x & y) ^ (x & z) ^ (y & z);
};
const Sigma0256 = (x) => {
return S(x, 2) ^ S(x, 13) ^ S(x, 22);
};
const Sigma1256 = (x) => {
return S(x, 6) ^ S(x, 11) ^ S(x, 25);
};
const Gamma0256 = (x) => {
return S(x, 7) ^ S(x, 18) ^ R(x, 3);
};
const Gamma1256 = (x) => {
return S(x, 17) ^ S(x, 19) ^ R(x, 10);
};
const S = (X, n) => (X >>> n) | (X << (32 - n));
const R = (X, n) => X >>> n;
const Ch = (x, y, z) => (x & y) ^ (~x & z);
const Maj = (x, y, z) => (x & y) ^ (x & z) ^ (y & z);
const Sigma0256 = (x) => S(x, 2) ^ S(x, 13) ^ S(x, 22);
const Sigma1256 = (x) => S(x, 6) ^ S(x, 11) ^ S(x, 25);
const Gamma0256 = (x) => S(x, 7) ^ S(x, 18) ^ R(x, 3);
const Gamma1256 = (x) => S(x, 17) ^ S(x, 19) ^ R(x, 10);
function coreSha256(m, l) {
const K = new Array(

View file

@ -1,5 +1,5 @@
function sizify(bytes, addI) {
if (bytes === 0) return "0";
if (bytes == 0) return "0";
if (bytes < 0) bytes = -bytes;
const prefixes = ["", "K", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q"];

View file

@ -1,11 +1,11 @@
{
"version": "4.0.0-beta2",
"version": "4.0.0-beta3",
"name": "SVR.JS",
"documentationURL": "https://svrjs.org/docs/tentative",
"statisticsServerCollectEndpoint": "https://statistics.svrjs.org/collect.svr",
"changes": [
"Fixed the bug with \"ext\" variable for .tar.gz mods.",
"Fixed the regular expression in the URL parser.",
"Optimized many functions"
"Fixed the bug related to forbidden path checking.",
"Fixed \"NaN\" file sizes in directory listings.",
"SVR.JS zip archives now include empty directories."
]
}

View file

@ -117,6 +117,13 @@ describe("Forbidden paths handling", () => {
expect(
isIndexOfForbiddenPath("/notforbidden/", "serverSideScriptDirectories"),
).toBe(false);
expect(isIndexOfForbiddenPath("/config.json.fake", "config")).toBe(false);
expect(
isIndexOfForbiddenPath(
"/node_modules_fake/",
"serverSideScriptDirectories",
),
).toBe(false);
});
test("should handle case insensitivity on Windows", () => {

View file

@ -51,4 +51,52 @@ describe("URL sanitizer", () => {
test('should return "/" for empty sanitized resource', () => {
expect(sanitizeURL("/../..")).toBe("/");
});
test("should encode special characters", () => {
expect(sanitizeURL("/test<path>")).toBe("/test%3Cpath%3E");
expect(sanitizeURL("/test^path")).toBe("/test%5Epath");
expect(sanitizeURL("/test`path")).toBe("/test%60path");
expect(sanitizeURL("/test{path}")).toBe("/test%7Bpath%7D");
expect(sanitizeURL("/test|path")).toBe("/test%7Cpath");
});
test("should preserve certain characters", () => {
expect(sanitizeURL("/test!path")).toBe("/test!path");
expect(sanitizeURL("/test$path")).toBe("/test$path");
expect(sanitizeURL("/test&path")).toBe("/test&path");
expect(sanitizeURL("/test-path")).toBe("/test-path");
expect(sanitizeURL("/test=path")).toBe("/test=path");
expect(sanitizeURL("/test@path")).toBe("/test@path");
expect(sanitizeURL("/test_path")).toBe("/test_path");
expect(sanitizeURL("/test~path")).toBe("/test~path");
});
test("should decode URL-encoded characters while preserving certain characters", () => {
expect(sanitizeURL("/test%20path")).toBe("/test%20path");
expect(sanitizeURL("/test%21path")).toBe("/test!path");
expect(sanitizeURL("/test%22path")).toBe("/test%22path");
expect(sanitizeURL("/test%24path")).toBe("/test$path");
expect(sanitizeURL("/test%25path")).toBe("/test%25path");
expect(sanitizeURL("/test%26path")).toBe("/test&path");
expect(sanitizeURL("/test%2Dpath")).toBe("/test-path");
expect(sanitizeURL("/test%3Cpath")).toBe("/test%3Cpath");
expect(sanitizeURL("/test%3Dpath")).toBe("/test=path");
expect(sanitizeURL("/test%3Epath")).toBe("/test%3Epath");
expect(sanitizeURL("/test%40path")).toBe("/test@path");
expect(sanitizeURL("/test%5Fpath")).toBe("/test_path");
expect(sanitizeURL("/test%7Dpath")).toBe("/test%7Dpath");
expect(sanitizeURL("/test%7Epath")).toBe("/test~path");
});
test("should decode URL-encoded alphanumeric characters while preserving certain characters", () => {
expect(sanitizeURL("/conf%69g.json")).toBe("/config.json");
expect(sanitizeURL("/CONF%49G.JSON")).toBe("/CONFIG.JSON");
expect(sanitizeURL("/svr%32.js")).toBe("/svr2.js");
expect(sanitizeURL("/%73%76%72%32%2E%6A%73")).toBe("/svr2.js");
});
test("should decode URL-encoded characters regardless of the letter case of the URL encoding", () => {
expect(sanitizeURL("/%5f")).toBe("/_");
expect(sanitizeURL("/%5F")).toBe("/_");
});
});