forked from svrjs/svrjs
Update to SVR.JS 4.0.0-beta3
This commit is contained in:
parent
920d942016
commit
c5af172d1e
26 changed files with 201 additions and 184 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ${
|
||||
|
|
|
@ -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 ${
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
64
src/index.js
64
src/index.js
|
@ -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 +
|
||||
":" +
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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 : "");
|
||||
|
|
|
@ -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, ">")}</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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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") {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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"];
|
||||
|
|
|
@ -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."
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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", () => {
|
||||
|
|
|
@ -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("/_");
|
||||
});
|
||||
});
|
||||
|
|
Reference in a new issue