@@ -37,7 +37,7 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-
Packages used by SVR.JS 3.6.4 and utilities
+
Packages used by SVR.JS 3.7.0 and utilities
License: MIT
diff --git a/mods/easteregg.tar.gz b/mods/easteregg.tar.gz
new file mode 100644
index 0000000..83c2ef0
Binary files /dev/null and b/mods/easteregg.tar.gz differ
diff --git a/serverSideScript.js b/serverSideScript.js
index 747a3c8..99b7b6d 100644
--- a/serverSideScript.js
+++ b/serverSideScript.js
@@ -62,13 +62,19 @@ if(href == "/hello.svr") {
callServerError(403,"SVR.JS-exampleproxy"); //Server error
serverconsole.errmessage("Client fails to recieve content."); //Log into SVR.JS
} else if(href.indexOf("/proxy.svr/") == 0) {
+ var hn = href.split("/")[2]; //Hostname
+ if(hn != "this" && !(req.socket.realRemoteAddress ? req.socket.realRemoteAddress : req.socket.remoteAddress).match(/^(?: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) ) {
+ //Prevent open proxy
+ callServerError(403,"SVR.JS-exampleproxy"); //Server error
+ serverconsole.errmessage("Client fails to recieve content."); //Log into SVR.JS
+ }
var hdrs = req.headers;
- hdrs["Host"] = (href.split("/")[2] == "this" ? req.headers.host : href.split("/")[2]);
+ hdrs["Host"] = (hn == "this" ? req.headers.host : hn);
hdrs["Origin"] = (req.headers.host == undefined ? "" : req.headers.host);
var options = {
- hostname: (href.split("/")[2] == "this" ? req.headers.host.split(":")[0] : href.split("/")[2].split(":")[0]),
- port: (href.split("/")[2] == "this" ? req.headers.host.split(":")[1] : (href.split("/")[2].split(":")[1] == undefined ? 80 : href.split("/")[2].split(":")[1])),
- path: req.url.replace("/proxy.svr/" + href.split("/")[2],""),
+ hostname: (hn == "this" ? req.headers.host.split(":")[0] : hn.split(":")[0]),
+ port: (hn == "this" ? req.headers.host.split(":")[1] : (hn.split(":")[1] == undefined ? 80 : hn.split(":")[1])),
+ path: req.url.replace("/proxy.svr/" + hn,""),
method: req.method,
headers: filterHeaders(hdrs)
};
diff --git a/svr.js b/svr.js
index 8c31ee2..306208e 100644
--- a/svr.js
+++ b/svr.js
@@ -27,13 +27,16 @@
//Check if SVR.JS is running on Node.JS-compatible runtime. If not, just error it out.
if (typeof require === "undefined") {
if (typeof ActiveXObject !== "undefined" && typeof WScript !== "undefined") {
+ // If it runs on Windows Script Host, display an error message.
var shell = new ActiveXObject("WScript.Shell");
shell.Popup("SVR.JS doesn't work on Windows Script Host. SVR.JS requires use of Node.JS (or compatible JS runtime).", undefined, "Can't start SVR.JS", 16);
WScript.quit();
} else {
if (typeof alert !== "undefined" && typeof document !== "undefined") {
+ // If it runs on web browser, display an alert.
alert("SVR.JS doesn't work on web browser. SVR.JS requires use of Node.JS (or compatible JS runtime).");
}
+ // If it's not, throw an error.
if (typeof document !== "undefined") {
throw new Error("SVR.JS doesn't work on web browser. SVR.JS requires use of Node.JS (or compatible JS runtime).");
} else {
@@ -41,6 +44,7 @@ if (typeof require === "undefined") {
}
}
}
+
var secure = false;
var disableMods = false;
@@ -77,7 +81,7 @@ function deleteFolderRecursive(path) {
}
var os = require("os");
-var version = "3.6.4";
+var version = "3.7.0";
var singlethreaded = false;
if (process.versions) process.versions.svrjs = version; //Inject SVR.JS into process.versions
@@ -142,8 +146,10 @@ if (!singlethreaded) {
}
// Cluster & IPC shim for Bun
- if (process.isBun && cluster.isMaster === undefined) {
+
+ cluster.bunShim = function () {
cluster.isMaster = !process.env.NODE_UNIQUE_ID;
+ cluster.isPrimary = cluster.isMaster;
cluster.isWorker = !cluster.isMaster;
if (cluster.isWorker) {
@@ -185,6 +191,12 @@ if (!singlethreaded) {
fakeIPCConnection.end(message);
});
};
+
+ process.removeFakeIPC = function() {
+ // Close IPC server
+ process.send = function() {};
+ fakeIPCServer.close();
+ }
}
}
@@ -215,18 +227,32 @@ if (!singlethreaded) {
sendImplemented = false;
}
+ oldLog = console.log;
+ console.log = function(a,b,c,d,e,f) {
+ if(a == "ChildProcess.prototype.send() - Sorry! Not implemented yet") {
+ throw new Error("NOT IMPLEMENTED");
+ } else {
+ oldLog(a,b,c,d,e,f);
+ }
+ }
+
try {
- eval("'use strict';(" + String(worker.send).replace(/console\.log *\( *(["'])ChildProcess\.prototype\.send\(\) - Sorry! Not implemented yet\1 *\) *;?/, "throw new Error(\"NOT IMPLEMENTED\"); //") + ")(undefined)");
+ worker.send(undefined);
} catch (err) {
if (err.message === "NOT IMPLEMENTED") {
sendImplemented = false;
}
}
+ console.log = oldLog;
+
return sendImplemented;
}
if (!checkSendImplementation(newWorker)) {
+ var net = require("net");
+ var os = require("os");
+
// Create a fake IPC server for worker process to receive messages
var fakeWorkerIPCServer = net.createServer(function (socket) {
var receivedData = "";
@@ -238,7 +264,8 @@ if (!singlethreaded) {
socket.on("end", function () {
newWorker.emit("message", receivedData);
});
- }).listen(os.platform() === "win32" ? path.join("\\\\?\\pipe", __dirname, "temp/.P" + newWorker.process.pid + ".ipc") : (__dirname + "/temp/.P" + newWorker.process.pid + ".ipc"));
+ });
+ fakeWorkerIPCServer.listen(os.platform() === "win32" ? path.join("\\\\?\\pipe", __dirname, "temp/.P" + newWorker.process.pid + ".ipc") : (__dirname + "/temp/.P" + newWorker.process.pid + ".ipc"));
// Cleanup when worker process exits
newWorker.on("exit", function () {
@@ -255,11 +282,8 @@ if (!singlethreaded) {
fakeWorkerIPCConnection.end(message);
});
} catch (err) {
- if (tries > 25) throw err;
-
- setTimeout(function () {
- newWorker.send(message, undefined, undefined, tries + 1);
- }, 10);
+ if (tries > 50) throw err;
+ newWorker.send(message, fakeParam2, fakeParam3, fakeParam4, tries + 1);
}
};
}
@@ -269,17 +293,31 @@ if (!singlethreaded) {
return newWorker;
};
}
+
+ if (process.isBun && (cluster.isMaster === undefined || (cluster.isMaster && process.env.NODE_UNIQUE_ID))) {
+ cluster.bunShim();
+ }
+
+ // Shim cluster.isPrimary field
+ if (cluster.isPrimary === undefined && cluster.isMaster !== undefined) cluster.isPrimary = cluster.isMaster;
}
-var bruteForceDb = {};
-
+// ETag-related
var ETagDB = {};
-
function generateETag(filePath, stat) {
if(!ETagDB[filePath + "-" + stat.size + "-" + stat.mtime]) ETagDB[filePath + "-" + stat.size + "-" + stat.mtime] = sha256(filePath + "-" + stat.size + "-" + stat.mtime);
return ETagDB[filePath + "-" + stat.size + "-" + stat.mtime];
}
+// Brute force-related
+var bruteForceDb = {};
+
+// PBKDF2 cache
+var pbkdf2Cache = [];
+var scryptCache = [];
+var pbkdf2CacheIntervalId = -1;
+
+// SVR.JS worker spawn-related
var SVRJSInitialized = false;
var exiting = false;
var reallyExiting = false;
@@ -289,7 +327,18 @@ function SVRJSFork() {
//Log
if (SVRJSInitialized) serverconsole.locmessage("Starting next thread, because previous one hung up/crashed...");
//Fork new worker
- var newWorker = cluster.fork();
+ var newWorker = {};
+ try {
+ newWorker = cluster.fork();
+ } catch (err) {
+ if(err.name == "NotImplementedError") {
+ // If cluster.fork throws a NotImplementedError, shim cluster module
+ cluster.bunShim();
+ newWorker = cluster.fork();
+ } else {
+ throw err;
+ }
+ }
newWorker.on("error", function (err) {
if(!reallyExiting) serverconsole.locwarnmessage("There was a problem when handling SVR.JS worker! (from master process side) Reason: " + err.message);
});
@@ -494,7 +543,7 @@ function createRegex(regex, isPath) {
//IP Block list object
function ipBlockList(rawBlockList) {
-
+
// Initialize the instance with empty arrays
if (rawBlockList === undefined) rawBlockList = [];
var instance = {
@@ -521,9 +570,9 @@ function ipBlockList(rawBlockList) {
var validateIpv4 = /((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})/;
if (validateIpv4.test(address)) {
- groups = address.match(extractIpv4);
- for (var i = 1; i < groups.length; i++) {
- ipv4 += ("00" + (parseInt(groups[i], 10).toString(16))).slice(-2) + (i == 2 ? ":" : "");
+ var oldGroups = address.match(extractIpv4);
+ for (var i = 1; i < oldGroups.length; i++) {
+ ipv4 += ("00" + (parseInt(oldGroups[i], 10).toString(16))).slice(-2) + (i == 2 ? ":" : "");
}
address = address.replace(extractIpv4, ipv4);
}
@@ -533,19 +582,19 @@ function ipBlockList(rawBlockList) {
} else {
var sides = address.split("::");
var groupsPresent = 0;
- for (var i = 0; i < sides.length; i++) {
- groupsPresent += sides[i].split(":").length;
- }
+ sides.forEach(function (side) {
+ groupsPresent += side.split(":").length;
+ });
fullAddress += sides[0] + ":";
- for (var i = 0; i < validGroupCount - groupsPresent; i++) {
- fullAddress += "0000:";
+ if(validGroupCount - groupsPresent > 1) {
+ fullAddress += "0000:".repeat(validGroupCount - groupsPresent);
}
fullAddress += sides[1];
}
var groups = fullAddress.split(":");
for (var i = 0; i < validGroupCount; i++) {
- while (groups[i].length < validGroupSize) {
- groups[i] = "0" + groups[i];
+ if (groups[i].length < validGroupSize) {
+ groups[i] = "0".repeat(validGroupSize - groups[i].length) + groups[i];
}
expandedAddress += (i != validGroupCount - 1) ? groups[i] + ":" : groups[i];
}
@@ -574,9 +623,9 @@ function ipBlockList(rawBlockList) {
function ipv6ToBlocks(ip) {
var ips = ip.split(":");
var ip2s = [];
- for (var i = 0; i < ips.length; i++) {
- ip2s.push(parseInt(ips[i]));
- }
+ ips.forEach(function (ipe) {
+ ip2s.push(parseInt(ipe));
+ });
return ip2s;
}
@@ -701,18 +750,17 @@ function ipBlockList(rawBlockList) {
if (instance.cidrs.length == 0) return false;
var ipParsedObject = (!isIPv6 ? ipv4ToInt : ipv6ToBlocks)(rawValue);
var checkMethod = (!isIPv6 ? checkIfIPv4CIDRMatches : checkIfIPv6CIDRMatches);
- for (var i = 0; i < instance.cidrs.length; i++) {
- if (checkMethod(ipParsedObject, instance.cidrs[i])) return true;
- }
-
- return false;
+
+ return instance.cidrs.some(function(iCidr) {
+ return checkMethod(ipParsedObject, iCidr);
+ });
};
// Add initial raw block list values to the instance
- for (var i = 0; i < rawBlockList.length; i++) {
- instance.add(rawBlockList[i]);
- }
-
+ rawBlockList.forEach(function (rbe) {
+ instance.add(rbe);
+ });
+
return instance;
}
@@ -722,18 +770,20 @@ function generateErrorStack(errorObject) {
var 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).
- for (var i = 0; i < errorStack.length; i++) {
- if (errorStack[i].indexOf(errorObject.name) == 0) return errorObject.stack;
+ if (errorStack.some(function (errorStackLine) {
+ return (errorStackLine.indexOf(errorObject.name) == 0);
+ })) {
+ return errorObject.stack;
}
// Create a new error stack with the error name and code (if available).
var newErrorStack = [errorObject.name + (errorObject.code ? ": " + errorObject.code : "") + (errorObject.message == "" ? "" : ": " + errorObject.message)];
// Process each line of the original error stack.
- for (var i = 0; i < errorStack.length; i++) {
- if (errorStack[i] != "") {
+ errorStack.forEach(function (errorStackLine) {
+ if (errorStackLine != "") {
// Split the line into function and location parts (if available).
- var errorFrame = errorStack[i].split("@");
+ var errorFrame = errorStackLine.split("@");
var location = "";
if (errorFrame.length > 1) location = errorFrame.pop();
var func = errorFrame.join("@");
@@ -741,7 +791,7 @@ function generateErrorStack(errorObject) {
// Build the new error stack entry with function and location information.
newErrorStack.push(" at " + (func == "" ? (!location || location == "" ? "" : location) : (func + (!location || location == "" ? "" : " (" + location + ")"))));
}
- }
+ });
// Join the new error stack entries with newlines and return the final stack.
return newErrorStack.join("\n");
@@ -943,6 +993,8 @@ var sni = {};
var disableNonEncryptedServer = false;
var disableToHTTPSRedirect = false;
var nonStandardCodesRaw = [];
+var disableUnusedWorkerTermination = false;
+var rewriteDirtyURLs = false;
//Get properties from config.json
if (configJSON.blacklist != undefined) rawBlackList = configJSON.blacklist;
@@ -967,11 +1019,13 @@ if (configJSON.secure != undefined) secure = secure || configJSON.secure;
if (configJSON.sni != undefined) sni = configJSON.sni;
if (configJSON.disableNonEncryptedServer != undefined) disableNonEncryptedServer = configJSON.disableNonEncryptedServer;
if (configJSON.disableToHTTPSRedirect != undefined) disableToHTTPSRedirect = configJSON.disableToHTTPSRedirect;
+if (configJSON.disableUnusedWorkerTermination != undefined) disableUnusedWorkerTermination = configJSON.disableUnusedWorkerTermination;
+if (configJSON.rewriteDirtyURLs != undefined) rewriteDirtyURLs = configJSON.rewriteDirtyURLs;
if (configJSON.wwwroot != undefined) {
var wwwroot = configJSON.wwwroot;
- if (cluster.isMaster || cluster.isMaster === undefined) process.chdir(wwwroot);
+ if (cluster.isPrimary || cluster.isPrimary === undefined) process.chdir(wwwroot);
} else {
- if (cluster.isMaster || cluster.isMaster === undefined) process.chdir(__dirname);
+ if (cluster.isPrimary || cluster.isPrimary === undefined) process.chdir(__dirname);
}
//Compability for older mods
@@ -981,18 +1035,17 @@ configJSON.productName = "SVR.JS";
var blacklist = ipBlockList(rawBlackList);
var nonStandardCodes = [];
-for (var i = 0; i < nonStandardCodesRaw.length; i++) {
+nonStandardCodesRaw.forEach(function (nonStandardCodeRaw) {
var nO = {};
- var nsKeys = Object.keys(nonStandardCodesRaw[i]);
- for (var j = 0; j < nsKeys.length; j++) {
- if (nsKeys[j] != "users") {
- nO[nsKeys[j]] = nonStandardCodesRaw[i][nsKeys[j]];
+ Object.keys(nonStandardCodeRaw).forEach(function (nsKey) {
+ if (nsKey != "users") {
+ nO[nsKey] = nonStandardCodeRaw[nsKey];
} else {
- nO["users"] = ipBlockList(nonStandardCodesRaw[i].users);
+ nO["users"] = ipBlockList(nonStandardCodeRaw.users);
}
- }
+ });
nonStandardCodes.push(nO);
-}
+});
var customHeaders = (configJSON.customHeaders == undefined ? {} : JSON.parse(JSON.stringify(configJSON.customHeaders)));
if (exposeServerVersion) {
@@ -1026,7 +1079,12 @@ function sanitizeURL(resource) {
// Decode URL-encoded characters while preserving certain characters
resource = resource.replace(/%([0-9a-f]{2})/gi, function (match, hex) {
var decodedChar = String.fromCharCode(parseInt(hex, 16));
- return /(?![;?:@&=+$,#%])[!-~]/.test(decodedChar) ? decodedChar : "%" + hex;
+ return /(?!["<>^`{|}?#%])[!-~]/.test(decodedChar) ? decodedChar : "%" + hex;
+ });
+ // Encode certain characters
+ resource = resource.replace(/[<>^`{|}]]/g, function (character) {
+ var charCode = character.charCodeAt(0);
+ return "%" + (charcode < 16 ? "0" : "") + charCode.toString(16).toUpperCase();
});
var sanitizedResource = resource;
// Ensure the resource starts with a slash
@@ -1043,6 +1101,20 @@ function sanitizeURL(resource) {
else return sanitizedResource;
}
+function fixNodeMojibakeURL(string) {
+ var encoded = "";
+ Buffer.from(string, "latin1").forEach(function (value) {
+ if(value > 127) {
+ encoded += "%" + (value < 16 ? "0" : "") + value.toString(16).toUpperCase();
+ } else {
+ encoded += String.fromCodePoint(value);
+ }
+ });
+ return encoded.replace(/%[0-9a-f-A-F]{2}/g, function (match) {
+ return match.toUpperCase();
+ });
+}
+
var key = "";
var cert = "";
@@ -1083,10 +1155,10 @@ function LOG(s) {
try {
if (configJSON.enableLogging || configJSON.enableLogging == undefined) {
if (logSync) {
- fs.appendFileSync(__dirname + "/log/" + (cluster.isMaster ? "master" : (cluster.isMaster === undefined ? "singlethread" : "worker")) + "-" + timestamp + ".log", "[" + new Date().toISOString() + "] " + s + "\r\n");
+ fs.appendFileSync(__dirname + "/log/" + (cluster.isPrimary ? "master" : (cluster.isPrimary === undefined ? "singlethread" : "worker")) + "-" + timestamp + ".log", "[" + new Date().toISOString() + "] " + s + "\r\n");
} else {
if (!logFile) {
- logFile = fs.createWriteStream(__dirname + "/log/" + (cluster.isMaster ? "master" : (cluster.isMaster === undefined ? "singlethread" : "worker")) + "-" + timestamp + ".log", {
+ logFile = fs.createWriteStream(__dirname + "/log/" + (cluster.isPrimary ? "master" : (cluster.isPrimary === undefined ? "singlethread" : "worker")) + "-" + timestamp + ".log", {
flags: "a",
autoClose: false
});
@@ -1106,10 +1178,9 @@ function LOG(s) {
var serverconsole = {
climessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.climessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.climessage(nmsg);
+ });
return;
}
console.log("SERVER CLI MESSAGE: " + msg);
@@ -1118,10 +1189,9 @@ var serverconsole = {
},
reqmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.reqmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.reqmessage(nmsg);
+ });
return;
}
console.log("\x1b[34mSERVER REQUEST MESSAGE: " + msg + "\x1b[37m\x1b[0m");
@@ -1130,10 +1200,9 @@ var serverconsole = {
},
resmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.resmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.resmessage(nmsg);
+ });
return;
}
console.log("\x1b[32mSERVER RESPONSE MESSAGE: " + msg + "\x1b[37m\x1b[0m");
@@ -1142,10 +1211,9 @@ var serverconsole = {
},
errmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.errmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.errmessage(nmsg);
+ });
return;
}
console.log("\x1b[31mSERVER RESPONSE ERROR MESSAGE: " + msg + "\x1b[37m\x1b[0m");
@@ -1154,10 +1222,9 @@ var serverconsole = {
},
locerrmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locerrmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locerrmessage(nmsg);
+ });
return;
}
console.log("\x1b[41mSERVER ERROR MESSAGE: " + msg + "\x1b[40m\x1b[0m");
@@ -1166,10 +1233,9 @@ var serverconsole = {
},
locwarnmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locwarnmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locwarnmessage(nmsg);
+ });
return;
}
console.log("\x1b[43mSERVER WARNING MESSAGE: " + msg + "\x1b[40m\x1b[0m");
@@ -1178,10 +1244,9 @@ var serverconsole = {
},
locmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locmessage(nmsg);
+ });
return;
}
console.log("SERVER MESSAGE: " + msg);
@@ -1229,22 +1294,22 @@ process.exit = function (code) {
if (!disableMods) {
// Define the modloader folder name
var modloaderFolderName = "modloader";
- if (cluster.isMaster === false) {
+ if (cluster.isPrimary === false) {
// If not the master process, create a unique modloader folder name for each worker
modloaderFolderName = ".modloader_w" + Math.floor(Math.random() * 65536);
}
-
+
// Define the temporary server-side JavaScript file name
var tempServerSideScriptName = "serverSideScript.js";
- if (!process.isBun && cluster.isMaster === false) {
+ if (!process.isBun && cluster.isPrimary === false) {
// If not the master process and it's not Bun, create a unique temporary server-side JavaScript file name for each worker
tempServerSideScriptName = ".serverSideScript_w" + Math.floor(Math.random() * 65536) + ".js";
}
// Iterate through the list of mod files
- for (var i = 0; i < modFiles.length; i++) {
+ modFiles.forEach(function (modFileRaw) {
// Build the path to the current mod file
- var modFile = __dirname + "/mods/" + modFiles[i];
+ var modFile = __dirname + "/mods/" + modFileRaw;
try {
// Try creating the modloader folder (if not already exists)
@@ -1265,7 +1330,7 @@ if (!disableMods) {
}
// Create a subfolder for the current mod within the modloader folder
- fs.mkdirSync(__dirname + "/temp/" + modloaderFolderName + "/" + modFiles[i]);
+ fs.mkdirSync(__dirname + "/temp/" + modloaderFolderName + "/" + modFileRaw);
} catch (err) {
// If there was an error creating the folder, ignore it if it's a known error
if (err.code != "EEXIST" && err.code != "ENOENT") throw err;
@@ -1282,12 +1347,12 @@ if (!disableMods) {
tar.x({
file: modFile,
sync: true,
- C: __dirname + "/temp/" + modloaderFolderName + "/" + modFiles[i]
+ C: __dirname + "/temp/" + modloaderFolderName + "/" + modFileRaw
});
} else {
// If it's not a ".tar.gz" file, unpack it using `svrmodpack`
if (svrmodpack._errored) throw svrmodpack._errored;
- svrmodpack.unpack(modFile, __dirname + "/temp/" + modloaderFolderName + "/" + modFiles[i]);
+ svrmodpack.unpack(modFile, __dirname + "/temp/" + modloaderFolderName + "/" + modFileRaw);
}
// Initialize variables for mod loading
@@ -1297,7 +1362,7 @@ if (!disableMods) {
// Attempt to require the mod's index.js file, retrying up to 3 times in case of syntax errors
for (var j = 0; j < 3; j++) {
try {
- Mod = require("./temp/" + modloaderFolderName + "/" + modFiles[i] + "/index.js");
+ Mod = require("./temp/" + modloaderFolderName + "/" + modFileRaw + "/index.js");
mod = new Mod();
break;
} catch (err) {
@@ -1315,13 +1380,13 @@ if (!disableMods) {
// Attempt to read the mod's info file, retrying up to 3 times
for (var j = 0; j < 3; j++) {
try {
- modInfos.push(JSON.parse(fs.readFileSync(__dirname + "/temp/" + modloaderFolderName + "/" + modFiles[i] + "/mod.info")));
+ modInfos.push(JSON.parse(fs.readFileSync(__dirname + "/temp/" + modloaderFolderName + "/" + modFileRaw + "/mod.info")));
break;
} catch (err) {
if (j >= 2) {
// If failed to read info file, add a placeholder entry to modInfos with an error message
modInfos.push({
- name: "Unknown mod (" + modFiles[i] + ";" + err.message + ")",
+ name: "Unknown mod (" + modFileRaw + ";" + err.message + ")",
version: "ERROR"
});
}
@@ -1333,14 +1398,14 @@ if (!disableMods) {
}
} catch (err) {
// If there was an error during mod loading, log it to the console
- if (cluster.isMaster || cluster.isMaster === undefined) {
- serverconsole.locwarnmessage("There was a problem while loading a \"" + modFiles[i] + "\" mod.");
+ if (cluster.isPrimary || cluster.isPrimary === undefined) {
+ serverconsole.locwarnmessage("There was a problem while loading a \"" + modFileRaw + "\" mod.");
serverconsole.locwarnmessage("Stack:");
serverconsole.locwarnmessage(generateErrorStack(err));
}
}
}
- }
+ });
// Check if a custom server side script file exists
if (fs.existsSync("./serverSideScript.js") && fs.statSync("./serverSideScript.js").isFile()) {
@@ -1374,7 +1439,7 @@ if (!disableMods) {
mods.push(amod);
} catch (err) {
// If there was an error during server side script loading, log it to the console
- if (cluster.isMaster || cluster.isMaster === undefined) {
+ if (cluster.isPrimary || cluster.isPrimary === undefined) {
serverconsole.locwarnmessage("There was a problem while loading server side JavaScript.");
serverconsole.locwarnmessage("Stack:");
serverconsole.locwarnmessage(generateErrorStack(err));
@@ -1552,11 +1617,9 @@ function isForbiddenPath(decodedHref, match) {
return decodedHref === forbiddenPath || (os.platform() === "win32" && decodedHref.toLowerCase() === forbiddenPath.toLowerCase());
}
if (typeof forbiddenPath === "object") {
- for (var i = 0; i < forbiddenPath.length; i++) {
- if (decodedHref === forbiddenPath[i] || (os.platform() === "win32" && decodedHref.toLowerCase() === forbiddenPath[i].toLowerCase())) {
- return true;
- }
- }
+ return forbiddenPath.some(function (forbiddenPathSingle) {
+ return (decodedHref === forbiddenPathSingle || (os.platform() === "win32" && decodedHref.toLowerCase() === forbiddenPathSingle.toLowerCase()));
+ });
}
return false;
}
@@ -1568,11 +1631,9 @@ function isIndexOfForbiddenPath(decodedHref, match) {
return decodedHref === forbiddenPath || decodedHref.indexOf(forbiddenPath + "/") === 0 || (os.platform() === "win32" && (decodedHref.toLowerCase() === forbiddenPath.toLowerCase() || decodedHref.toLowerCase().indexOf(forbiddenPath.toLowerCase() + "/") === 0));
}
if (typeof forbiddenPath === "object") {
- for (var i = 0; i < forbiddenPath.length; i++) {
- if (decodedHref === forbiddenPath[i] || decodedHref.indexOf(forbiddenPath[i] + "/") === 0 || (os.platform() === "win32" && (decodedHref.toLowerCase() === forbiddenPath[i].toLowerCase() || decodedHref.toLowerCase().indexOf(forbiddenPath[i].toLowerCase() + "/") === 0))) {
- return true;
- }
- }
+ 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;
}
@@ -1585,10 +1646,10 @@ forbiddenPaths.certificates = [];
if (secure) {
forbiddenPaths.certificates.push(getInitializePath(configJSON.cert));
forbiddenPaths.certificates.push(getInitializePath(configJSON.key));
- for (var i = 0; i < Object.keys(sni).length; i++) {
- forbiddenPaths.certificates.push(getInitializePath(sni[Object.keys(sni)[i]].cert));
- forbiddenPaths.certificates.push(getInitializePath(sni[Object.keys(sni)[i]].key));
- }
+ Object.keys(sni).forEach(function (sniHostName) {
+ forbiddenPaths.certificates.push(getInitializePath(sni[sniHostName].cert));
+ forbiddenPaths.certificates.push(getInitializePath(sni[sniHostName].key));
+ });
}
forbiddenPaths.svrjs = getInitializePath("./" + ((__dirname[__dirname.length - 1] != "/") ? __filename.replace(__dirname + "/", "") : __filename.replace(__dirname, "")));
forbiddenPaths.serverSideScripts = [];
@@ -1601,8 +1662,9 @@ forbiddenPaths.serverSideScriptDirectories.push(getInitializePath("./mods"));
forbiddenPaths.log = getInitializePath("./log");
//Create server
-if (!cluster.isMaster) {
+if (!cluster.isPrimary) {
var reqcounter = 0;
+ var reqcounterKillReq = 0;
var server = {};
var server2 = {};
try {
@@ -1620,10 +1682,9 @@ if (!cluster.isMaster) {
var serverconsole = {
climessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.climessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.climessage(nmsg);
+ });
return;
}
console.log("SERVER CLI MESSAGE [Request Id: " + reqId + "]: " + msg);
@@ -1632,10 +1693,9 @@ if (!cluster.isMaster) {
},
reqmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.reqmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.reqmessage(nmsg);
+ });
return;
}
console.log("\x1b[34mSERVER REQUEST MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -1644,10 +1704,9 @@ if (!cluster.isMaster) {
},
resmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.resmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.resmessage(nmsg);
+ });
return;
}
console.log("\x1b[32mSERVER RESPONSE MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -1656,10 +1715,9 @@ if (!cluster.isMaster) {
},
errmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.errmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.errmessage(nmsg);
+ });
return;
}
console.log("\x1b[31mSERVER RESPONSE ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -1668,10 +1726,9 @@ if (!cluster.isMaster) {
},
locerrmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locerrmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locerrmessage(nmsg);
+ });
return;
}
console.log("\x1b[41mSERVER ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m");
@@ -1680,10 +1737,9 @@ if (!cluster.isMaster) {
},
locwarnmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locwarnmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locwarnmessage(nmsg);
+ });
return;
}
console.log("\x1b[43mSERVER WARNING MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m");
@@ -1692,10 +1748,9 @@ if (!cluster.isMaster) {
},
locmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locmessage(nmsg);
+ });
return;
}
console.log("SERVER MESSAGE [Request Id: " + reqId + "]: " + msg);
@@ -1711,6 +1766,7 @@ if (!cluster.isMaster) {
var reqip = socket.remoteAddress;
var reqport = socket.remotePort;
serverconsole.locmessage("Somebody connected to " + (typeof port == "number" ? "port " : "socket ") + port + "...");
+ reqcounter++;
serverconsole.reqmessage("Client " + ((!reqip || reqip == "") ? "[unknown client]" : (reqip + ((reqport && reqport !== 0) && reqport != "" ? ":" + reqport : ""))) + " wants to proxy " + request.url + " through this server");
if (request.headers["user-agent"] != undefined) serverconsole.reqmessage("Client uses " + request.headers["user-agent"]);
serverconsole.errmessage("This server will never be a proxy.");
@@ -1732,65 +1788,72 @@ if (!cluster.isMaster) {
}
server2.on("error", function (err) {
- if (err.code == "EADDRINUSE" || err.code == "EADDRNOTAVAIL" || err.code == "EACCES") {
- attmtsRedir--;
- if (cluster.isMaster === undefined) {
- if (err.code == "EADDRINUSE") {
- serverconsole.locerrmessage("Address is already in use by another process.");
- } else if (err.code == "EADDRNOTAVAIL") {
- serverconsole.locerrmessage("Address is not available on this machine.");
- } else if (err.code == "EACCES") {
- serverconsole.locerrmessage("Permission denied. You may not have sufficient privileges to access the requested address.");
- } else if (err.code == "EAFNOSUPPORT") {
- serverconsole.locerrmessage("Address family not supported. The address family (IPv4 or IPv6) of the requested address is not supported.");
- } else if (err.code == "EALREADY") {
- serverconsole.locerrmessage("Operation already in progress. The server is already in the process of establishing a connection on the requested address.");
- } else if (err.code == "ECONNABORTED") {
- serverconsole.locerrmessage("Connection aborted. The connection to the server was terminated abruptly.");
- } else if (err.code == "ECONNREFUSED") {
- serverconsole.locerrmessage("Connection refused. The server refused the connection attempt.");
- } else if (err.code == "ECONNRESET") {
- serverconsole.locerrmessage("Connection reset by peer. The connection to the server was reset by the remote host.");
- } else if (err.code == "EDESTADDRREQ") {
- serverconsole.locerrmessage("Destination address required. The destination address must be specified.");
- } else if (err.code == "ENETDOWN") {
- serverconsole.locerrmessage("Network is down. The network interface used for the connection is not available.");
- } else if (err.code == "ENETUNREACH") {
- serverconsole.locerrmessage("Network is unreachable. The network destination is not reachable from this host.");
- } else if (err.code == "ENOBUFS") {
- serverconsole.locerrmessage("No buffer space available. Insufficient buffer space is available for the server to process the request.");
- } else if (err.code == "ENOTSOCK") {
- serverconsole.locerrmessage("Not a socket. The file descriptor provided is not a valid socket.");
- } else if (err.code == "EPROTO") {
- serverconsole.locerrmessage("Protocol error. An unspecified protocol error occurred.");
- } else if (err.code == "EPROTONOSUPPORT") {
- serverconsole.locerrmessage("Protocol not supported. The requested network protocol is not supported.");
- } else if (err.code == "ETIMEDOUT") {
- serverconsole.locerrmessage("Connection timed out. The server did not respond within the specified timeout period.");
- } else {
- serverconsole.locerrmessage("There was an unknown error with the server.");
- }
- serverconsole.locmessage(attmtsRedir + " attempts left.");
+ attmtsRedir--;
+ if (cluster.isPrimary === undefined && attmtsRedir >= 0) {
+ if (err.code == "EADDRINUSE") {
+ serverconsole.locerrmessage("Address is already in use by another process.");
+ } else if (err.code == "EADDRNOTAVAIL") {
+ serverconsole.locerrmessage("Address is not available on this machine.");
+ } else if (err.code == "EACCES") {
+ serverconsole.locerrmessage("Permission denied. You may not have sufficient privileges to access the requested address.");
+ } else if (err.code == "EAFNOSUPPORT") {
+ serverconsole.locerrmessage("Address family not supported. The address family (IPv4 or IPv6) of the requested address is not supported.");
+ } else if (err.code == "EALREADY") {
+ serverconsole.locerrmessage("Operation already in progress. The server is already in the process of establishing a connection on the requested address.");
+ } else if (err.code == "ECONNABORTED") {
+ serverconsole.locerrmessage("Connection aborted. The connection to the server was terminated abruptly.");
+ } else if (err.code == "ECONNREFUSED") {
+ serverconsole.locerrmessage("Connection refused. The server refused the connection attempt.");
+ } else if (err.code == "ECONNRESET") {
+ serverconsole.locerrmessage("Connection reset by peer. The connection to the server was reset by the remote host.");
+ } else if (err.code == "EDESTADDRREQ") {
+ serverconsole.locerrmessage("Destination address required. The destination address must be specified.");
+ } else if (err.code == "ENETDOWN") {
+ serverconsole.locerrmessage("Network is down. The network interface used for the connection is not available.");
+ } else if (err.code == "ENETUNREACH") {
+ serverconsole.locerrmessage("Network is unreachable. The network destination is not reachable from this host.");
+ } else if (err.code == "ENOBUFS") {
+ serverconsole.locerrmessage("No buffer space available. Insufficient buffer space is available for the server to process the request.");
+ } else if (err.code == "ENOTSOCK") {
+ serverconsole.locerrmessage("Not a socket. The file descriptor provided is not a valid socket.");
+ } else if (err.code == "EPROTO") {
+ serverconsole.locerrmessage("Protocol error. An unspecified protocol error occurred.");
+ } else if (err.code == "EPROTONOSUPPORT") {
+ serverconsole.locerrmessage("Protocol not supported. The requested network protocol is not supported.");
+ } else if (err.code == "ETIMEDOUT") {
+ serverconsole.locerrmessage("Connection timed out. The server did not respond within the specified timeout period.");
} else {
- process.send("\x12ERRLIST" + attmtsRedir + err.code);
- }
- if (attmtsRedir > 0) {
- server2.close();
- setTimeout(start, 900);
- } else {
- if (cluster.isMaster !== undefined) process.send("\x12" + err.code);
- process.exit(errors[err.code]);
+ serverconsole.locerrmessage("There was an unknown error with the server.");
}
+ serverconsole.locmessage(attmtsRedir + " attempts left.");
} else {
- serverconsole.locerrmessage("There was a problem starting SVR.JS!!!");
- serverconsole.locerrmessage("Stack:");
- serverconsole.locerrmessage(generateErrorStack(err));
- if (cluster.isMaster !== undefined) process.send("\x12CRASH");
- process.exit(err.code ? errors[err.code] : 1);
+ try {
+ process.send("\x12ERRLIST" + attmtsRedir + err.code);
+ } catch(ex) {
+ // Probably main process exited
+ }
+ }
+ if (attmtsRedir > 0) {
+ server2.close();
+ setTimeout(start, 900);
+ } else {
+ try {
+ if (cluster.isPrimary !== undefined) process.send("\x12ERRCRASH" + err.code);
+ } catch(ex) {
+ // Probably main process exited
+ }
+ setTimeout(function () {
+ var errno = errors[err.code];
+ if(errno) {
+ process.exit(errno);
+ } else {
+ process.exit(1);
+ }
+ }, 50);
}
});
- server2.once("listening", function () {
+ server2.on("listening", function () {
listeningMessage();
});
@@ -1826,12 +1889,12 @@ if (!cluster.isMaster) {
}
}
if (secure) {
- for (var i = 0; i < sniCredentials.length; i++) {
- server.addContext(sniCredentials[i].name, {
- cert: sniCredentials[i].cert,
- key: sniCredentials[i].key
+ sniCredentials.forEach(function (sniCredentialsSingle) {
+ server.addContext(sniCredentialsSingle.name, {
+ cert: sniCredentialsSingle.cert,
+ key: sniCredentialsSingle.key
});
- }
+ });
}
server.on("request", reqhandler);
server.on("checkExpectation", reqhandler);
@@ -1919,10 +1982,9 @@ if (!cluster.isMaster) {
var serverconsole = {
climessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.climessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.climessage(nmsg);
+ });
return;
}
console.log("SERVER CLI MESSAGE [Request Id: " + reqId + "]: " + msg);
@@ -1931,10 +1993,9 @@ if (!cluster.isMaster) {
},
reqmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.reqmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.reqmessage(nmsg);
+ });
return;
}
console.log("\x1b[34mSERVER REQUEST MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -1943,10 +2004,9 @@ if (!cluster.isMaster) {
},
resmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.resmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.resmessage(nmsg);
+ });
return;
}
console.log("\x1b[32mSERVER RESPONSE MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -1955,10 +2015,9 @@ if (!cluster.isMaster) {
},
errmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.errmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.errmessage(nmsg);
+ });
return;
}
console.log("\x1b[31mSERVER RESPONSE ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -1967,10 +2026,9 @@ if (!cluster.isMaster) {
},
locerrmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locerrmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locerrmessage(nmsg);
+ });
return;
}
console.log("\x1b[41mSERVER ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m");
@@ -1979,10 +2037,9 @@ if (!cluster.isMaster) {
},
locwarnmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locwarnmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locwarnmessage(nmsg);
+ });
return;
}
console.log("\x1b[43mSERVER WARNING MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m");
@@ -1991,10 +2048,9 @@ if (!cluster.isMaster) {
},
locmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locmessage(nmsg);
+ });
return;
}
console.log("SERVER MESSAGE [Request Id: " + reqId + "]: " + msg);
@@ -2005,22 +2061,21 @@ if (!cluster.isMaster) {
function getCustomHeaders() {
var ph = JSON.parse(JSON.stringify(customHeaders));
- var phk = Object.keys(ph);
- for (var i = 0; i < phk.length; i++) {
- if (typeof ph[phk[i]] == "string") ph[phk[i]] = ph[phk[i]].replace(/\{path\}/g, req.url);
- }
+ Object.keys(ph).forEach(function (phk) {
+ if (typeof ph[phk] == "string") ph[phk] = ph[phk].replace(/\{path\}/g, req.url);
+ });
return ph;
}
- if (req.headers["x-svr-js-from-main-thread"] == "true") {
- res.writeHead(204, "No Content", getCustomHeaders());
+
+ if (req.headers["x-svr-js-from-main-thread"] == "true" && (!req.socket.remoteAddress || req.socket.remoteAddress == "::1" || req.socket.remoteAddress == "::ffff:127.0.0.1" || req.socket.remoteAddress == "127.0.0.1" || req.socket.remoteAddress == "localhost")) {
+ var headers = getCustomHeaders();
+ res.writeHead(204, "No Content", headers);
res.end();
return;
}
- try {
- req.url = encodeURI(Buffer.from(req.url, "latin1").toString("utf8")).replace(/%25/gi, "%");
- } catch (err) {
- //URL not converted...
- }
+
+ req.url = fixNodeMojibakeURL(req.url);
+
res.writeHeadNative = res.writeHead;
res.writeHead = function (a, b, c) {
if (parseInt(a) >= 400 && parseInt(a) <= 599) {
@@ -2030,6 +2085,7 @@ if (!cluster.isMaster) {
}
res.writeHeadNative(a, b, c);
};
+
var finished = false;
res.on("finish", function () {
if (!finished) {
@@ -2069,7 +2125,7 @@ if (!cluster.isMaster) {
400: "The request you made is invalid.",
417: "Expectation in Expect property couldn't be satisfied.",
500: "The server had an unexpected error. Below, the error stack is shown: {stack}
Please contact with developer/administrator at {contact}.",
- 501: "The request requires use of a function, which isn't implemented (yet) by the server."
+ 501: "The request requires use of a function, which isn't currently implemented by the server."
};
//Server error calling method
@@ -2092,17 +2148,16 @@ if (!cluster.isMaster) {
var cheaders = getCustomHeaders();
if (ch) {
var chon = Object.keys(cheaders);
- var chn = Object.keys(ch);
- for (var i = 0; i < chn.length; i++) {
- var nhn = chn[i];
+ Object.keys(ch).forEach(function (chnS) {
+ var nhn = chnS;
for (var j = 0; j < chon.length; j++) {
- if (chon[j].toLowerCase() == chn[i].toLowerCase()) {
+ if (chon[j].toLowerCase() == chnS.toLowerCase()) {
nhn = chon[j];
break;
}
}
- if (ch[chn[i]]) cheaders[nhn] = ch[chn[i]];
- }
+ if (ch[chnS]) cheaders[nhn] = ch[chnS];
+ });
}
cheaders["Content-Type"] = "text/html; charset=utf-8";
if (errorCode == 405 && !cheaders["Allow"]) cheaders["Allow"] = "GET, POST, HEAD, OPTIONS";
@@ -2121,7 +2176,7 @@ if (!cluster.isMaster) {
} else if (err.code == "EACCES") {
additionalError = 403;
} else if (err.code == "EMFILE") {
- additionalError = 429;
+ additionalError = 503;
} else if (err.code == "ELOOP") {
additionalError = 508;
}
@@ -2130,7 +2185,6 @@ if (!cluster.isMaster) {
res.end();
}
});
-
}
}
@@ -2178,7 +2232,7 @@ if (!cluster.isMaster) {
reqip = req.socket.remoteAddress;
reqport = req.socket.remotePort;
}
-
+ reqcounter++;
if (!isProxy) serverconsole.reqmessage("Client " + ((!reqip || reqip == "") ? "[unknown client]" : (reqip + ((reqport && reqport !== 0) && reqport != "" ? ":" + reqport : ""))) + " wants " + (req.method == "GET" ? "content in " : (req.method == "POST" ? "to post content in " : (req.method == "PUT" ? "to add content in " : (req.method == "DELETE" ? "to delete content in " : (req.method == "PATCH" ? "to patch content in " : "to access content using " + req.method + " method in "))))) + (req.headers.host == undefined ? "" : req.headers.host) + req.url);
else serverconsole.reqmessage("Client " + ((!reqip || reqip == "") ? "[unknown client]" : (reqip + ((reqport && reqport !== 0) && reqport != "" ? ":" + reqport : ""))) + " wants " + (req.method == "GET" ? "content in " : (req.method == "POST" ? "to post content in " : (req.method == "PUT" ? "to add content in " : (req.method == "DELETE" ? "to delete content in " : (req.method == "PATCH" ? "to patch content in " : "to access content using " + req.method + " method in "))))) + req.url);
if (req.headers["user-agent"] != undefined) serverconsole.reqmessage("Client uses " + req.headers["user-agent"]);
@@ -2232,7 +2286,6 @@ if (!cluster.isMaster) {
if (nuobject.pathname) {
nuobject.path = nuobject.pathname + (nuobject.search ? nuobject.search : "");
}
- //if(nuobject.path != "" && uobject.password != "") nuobject.path = nuobject.pathname + nuobject.href;
nuobject.query = {};
uobject.searchParams.forEach(function (value, key) {
nuobject.query[key] = value;
@@ -2313,7 +2366,6 @@ if (!cluster.isMaster) {
serverconsole.errmessage(generateErrorStack(err));
callServerError(500, undefined, generateErrorStack(err));
}
-
}
}
@@ -2345,19 +2397,18 @@ if (!cluster.isMaster) {
var headers = JSON.parse(JSON.stringify(headers));
headers["Date"] = (new Date()).toGMTString();
headers["Connection"] = "close";
- var headernames = Object.keys(headers);
- for (var i = 0; i < headernames.length; i++) {
- if (headernames[i].toLowerCase() == "set-cookie") {
- for (var j = 0; j < headers[headernames[i]]; j++) {
- if (headernames[i].match(/[^\x09\x20-\x7e\x80-\xff]|.:/) || headers[headernames[i]][j].match(/[^\x09\x20-\x7e\x80-\xff]/)) throw new Error("Invalid header!!! (" + headernames[i] + ")");
- head += (headernames[i] + ": " + headers[headernames[i]][j]);
- }
+ Object.keys(headers).forEach(function (headername) {
+ if (headername.toLowerCase() == "set-cookie") {
+ headers[headername].forEach(function (headerValueS) {
+ if (headername.match(/[^\x09\x20-\x7e\x80-\xff]|.:/) || headerValueS.match(/[^\x09\x20-\x7e\x80-\xff]/)) throw new Error("Invalid header!!! (" + headername + ")");
+ head += (headername + ": " + headerValueS);
+ });
} else {
- if (headernames[i].match(/[^\x09\x20-\x7e\x80-\xff]|.:/) || headers[headernames[i]].match(/[^\x09\x20-\x7e\x80-\xff]/)) throw new Error("Invalid header!!! (" + headernames[i] + ")");
- head += (headernames[i] + ": " + headers[headernames[i]]);
+ if (headername.match(/[^\x09\x20-\x7e\x80-\xff]|.:/) || headers[headername].match(/[^\x09\x20-\x7e\x80-\xff]/)) throw new Error("Invalid header!!! (" + headername + ")");
+ head += (headername + ": " + headers[headername]);
}
head += "\r\n";
- }
+ });
head += ("\r\n");
res.write(head);
};
@@ -2367,10 +2418,9 @@ if (!cluster.isMaster) {
var serverconsole = {
climessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.climessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.climessage(nmsg);
+ });
return;
}
console.log("SERVER CLI MESSAGE [Request Id: " + reqId + "]: " + msg);
@@ -2379,10 +2429,9 @@ if (!cluster.isMaster) {
},
reqmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.reqmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.reqmessage(nmsg);
+ });
return;
}
console.log("\x1b[34mSERVER REQUEST MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -2391,10 +2440,9 @@ if (!cluster.isMaster) {
},
resmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.resmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.resmessage(nmsg);
+ });
return;
}
console.log("\x1b[32mSERVER RESPONSE MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -2403,10 +2451,9 @@ if (!cluster.isMaster) {
},
errmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.errmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.errmessage(nmsg);
+ });
return;
}
console.log("\x1b[31mSERVER RESPONSE ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -2415,10 +2462,9 @@ if (!cluster.isMaster) {
},
locerrmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locerrmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locerrmessage(nmsg);
+ });
return;
}
console.log("\x1b[41mSERVER ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m");
@@ -2427,10 +2473,9 @@ if (!cluster.isMaster) {
},
locwarnmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locwarnmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locwarnmessage(nmsg);
+ });
return;
}
console.log("\x1b[43mSERVER WARNING MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m");
@@ -2439,10 +2484,9 @@ if (!cluster.isMaster) {
},
locmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locmessage(nmsg);
+ });
return;
}
console.log("SERVER MESSAGE [Request Id: " + reqId + "]: " + msg);
@@ -2497,17 +2541,16 @@ if (!cluster.isMaster) {
var cheaders = getCustomHeaders();
if (ch) {
var chon = Object.keys(cheaders);
- var chn = Object.keys(ch);
- for (var i = 0; i < chn.length; i++) {
- var nhn = chn[i];
+ Object.keys(ch).forEach(function (chnS) {
+ var nhn = chnS;
for (var j = 0; j < chon.length; j++) {
- if (chon[j].toLowerCase() == chn[i].toLowerCase()) {
+ if (chon[j].toLowerCase() == chnS.toLowerCase()) {
nhn = chon[j];
break;
}
}
- if (ch[chn[i]]) cheaders[nhn] = ch[chn[i]];
- }
+ if (ch[chnS]) cheaders[nhn] = ch[chnS];
+ });
}
cheaders["Content-Type"] = "text/html; charset=utf-8";
if (errorCode == 405 && !cheaders["Allow"]) cheaders["Allow"] = "GET, POST, HEAD, OPTIONS";
@@ -2526,7 +2569,7 @@ if (!cluster.isMaster) {
} else if (err.code == "EACCES") {
additionalError = 403;
} else if (err.code == "EMFILE") {
- additionalError = 429;
+ additionalError = 503;
} else if (err.code == "ELOOP") {
additionalError = 508;
}
@@ -2540,6 +2583,7 @@ if (!cluster.isMaster) {
}
var reqip = socket.remoteAddress;
var reqport = socket.remotePort;
+ reqcounter++;
serverconsole.locmessage("Somebody connected to " + (secure && fromMain ? ((typeof sport == "number" ? "port " : "socket ") + sport) : ((typeof port == "number" ? "port " : "socket ") + port)) + "...");
serverconsole.reqmessage("Client " + ((!reqip || reqip == "") ? "[unknown client]" : (reqip + ((reqport && reqport !== 0) && reqport != "" ? ":" + reqport : ""))) + " sent invalid request.");
try {
@@ -2554,7 +2598,7 @@ if (!cluster.isMaster) {
return;
}
}
-
+
if (err.code && err.code.indexOf("ERR_HTTP2_") == 0) {
serverconsole.errmessage("An HTTP/2 error occured: " + err.code);
callServerError(400);
@@ -2639,10 +2683,9 @@ if (!cluster.isMaster) {
var serverconsole = {
climessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.climessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.climessage(nmsg);
+ });
return;
}
console.log("SERVER CLI MESSAGE [Request Id: " + reqId + "]: " + msg);
@@ -2651,10 +2694,9 @@ if (!cluster.isMaster) {
},
reqmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.reqmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.reqmessage(nmsg);
+ });
return;
}
console.log("\x1b[34mSERVER REQUEST MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -2663,10 +2705,9 @@ if (!cluster.isMaster) {
},
resmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.resmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.resmessage(nmsg);
+ });
return;
}
console.log("\x1b[32mSERVER RESPONSE MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -2675,10 +2716,9 @@ if (!cluster.isMaster) {
},
errmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.errmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.errmessage(nmsg);
+ });
return;
}
console.log("\x1b[31mSERVER RESPONSE ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -2687,10 +2727,9 @@ if (!cluster.isMaster) {
},
locerrmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locerrmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locerrmessage(nmsg);
+ });
return;
}
console.log("\x1b[41mSERVER ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m");
@@ -2699,10 +2738,9 @@ if (!cluster.isMaster) {
},
locwarnmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locwarnmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locwarnmessage(nmsg);
+ });
return;
}
console.log("\x1b[43mSERVER WARNING MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m");
@@ -2711,10 +2749,9 @@ if (!cluster.isMaster) {
},
locmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locmessage(nmsg);
+ });
return;
}
console.log("SERVER MESSAGE [Request Id: " + reqId + "]: " + msg);
@@ -2731,20 +2768,21 @@ if (!cluster.isMaster) {
var reqip = socket.remoteAddress;
var reqport = socket.remotePort;
+ reqcounter++;
serverconsole.locmessage("Somebody connected to " + (secure ? ((typeof sport == "number" ? "port " : "socket ") + sport) : ((typeof port == "number" ? "port " : "socket ") + port)) + "...");
serverconsole.reqmessage("Client " + ((!reqip || reqip == "") ? "[unknown client]" : (reqip + ((reqport && reqport !== 0) && reqport != "" ? ":" + reqport : ""))) + " wants to proxy " + request.url + " through this server");
if (request.headers["user-agent"] != undefined) serverconsole.reqmessage("Client uses " + request.headers["user-agent"]);
function modExecute(mods, ffinals) {
var proxyMods = [];
- for (var i = 0; i < mods.length; i++) {
- if (mods[i].proxyCallback !== undefined) proxyMods.push(mods[i]);
- }
+ mods.forEach(function (mod) {
+ if (mod.proxyCallback !== undefined) proxyMods.push(mod);
+ });
var modFunction = ffinals;
- for (var i = proxyMods.length - 1; i >= 0; i--) {
- modFunction = proxyMods[i].callback(req, socket, head, configJSON, serverconsole, modFunction);
- }
+ proxyMods.reverse().forEach(function(proxyMod) {
+ modFunction = proxyMod.proxyCallback(req, socket, head, configJSON, serverconsole, modFunction);
+ });
modFunction();
}
@@ -2764,10 +2802,9 @@ if (!cluster.isMaster) {
var serverconsole = {
climessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.climessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.climessage(nmsg);
+ });
return;
}
console.log("SERVER CLI MESSAGE [Request Id: " + reqId + "]: " + msg);
@@ -2776,10 +2813,9 @@ if (!cluster.isMaster) {
},
reqmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.reqmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.reqmessage(nmsg);
+ });
return;
}
console.log("\x1b[34mSERVER REQUEST MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -2788,10 +2824,9 @@ if (!cluster.isMaster) {
},
resmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.resmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.resmessage(nmsg);
+ });
return;
}
console.log("\x1b[32mSERVER RESPONSE MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -2800,10 +2835,9 @@ if (!cluster.isMaster) {
},
errmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.errmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.errmessage(nmsg);
+ });
return;
}
console.log("\x1b[31mSERVER RESPONSE ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[37m\x1b[0m");
@@ -2812,10 +2846,9 @@ if (!cluster.isMaster) {
},
locerrmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locerrmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locerrmessage(nmsg);
+ });
return;
}
console.log("\x1b[41mSERVER ERROR MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m");
@@ -2824,10 +2857,9 @@ if (!cluster.isMaster) {
},
locwarnmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locwarnmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locwarnmessage(nmsg);
+ });
return;
}
console.log("\x1b[43mSERVER WARNING MESSAGE [Request Id: " + reqId + "]: " + msg + "\x1b[40m\x1b[0m");
@@ -2836,10 +2868,9 @@ if (!cluster.isMaster) {
},
locmessage: function (msg) {
if (msg.indexOf("\n") != -1) {
- var nmsg = msg.split("\n");
- for (var i = 0; i < nmsg.length; i++) {
- serverconsole.locmessage(nmsg[i]);
- }
+ msg.split("\n").forEach(function (nmsg) {
+ serverconsole.locmessage(nmsg);
+ });
return;
}
console.log("SERVER MESSAGE [Request Id: " + reqId + "]: " + msg);
@@ -2850,10 +2881,9 @@ if (!cluster.isMaster) {
function getCustomHeaders() {
var ph = JSON.parse(JSON.stringify(customHeaders));
- var phk = Object.keys(ph);
- for (var i = 0; i < phk.length; i++) {
- if (typeof ph[phk[i]] == "string") ph[phk[i]] = ph[phk[i]].replace(/\{path\}/g, request.url);
- }
+ Object.keys(ph).forEach(function (phk) {
+ if (typeof ph[phk] == "string") ph[phk] = ph[phk].replace(/\{path\}/g, request.url);
+ });
return ph;
}
@@ -2886,7 +2916,7 @@ if (!cluster.isMaster) {
if (!request.headers.host) request.headers.host = request.headers[":authority"];
(request.headers[":path"] == undefined ? (function () {})() : request.url = request.headers[":path"]);
request.protocol = request.headers[":scheme"];
- var headers = [":path" || ":method"];
+ var headers = [":path", ":method"];
for (var i = 0; i < headers.length; i++) {
if (request.headers[headers[i]] == undefined) {
var cheaders = getCustomHeaders();
@@ -2908,17 +2938,14 @@ if (!cluster.isMaster) {
}
}
- if (request.headers["x-svr-js-from-main-thread"] == "true") {
- response.writeHead(204, "No Content", getCustomHeaders());
+ if (request.headers["x-svr-js-from-main-thread"] == "true" && (!request.socket.remoteAddress || request.socket.remoteAddress == "::1" || request.socket.remoteAddress == "::ffff:127.0.0.1" || request.socket.remoteAddress == "127.0.0.1" || request.socket.remoteAddress == "localhost")) {
+ var headers = getCustomHeaders();
+ response.writeHead(204, "No Content", headers);
response.end();
return;
}
-
- try {
- request.url = encodeURI(Buffer.from(request.url, "latin1").toString("utf8")).replace(/%25/gi, "%");
- } catch (err) {
- //Request URL not modified...
- }
+
+ request.url = fixNodeMojibakeURL(request.url);
var headWritten = false;
var lastStatusCode = null;
@@ -3034,6 +3061,8 @@ if (!cluster.isMaster) {
reqport = request.socket.remotePort;
}
+ reqcounter++;
+
if (!isProxy) serverconsole.reqmessage("Client " + ((!reqip || reqip == "") ? "[unknown client]" : (reqip + ((reqport && reqport !== 0) && reqport != "" ? ":" + reqport : ""))) + " wants " + (request.method == "GET" ? "content in " : (request.method == "POST" ? "to post content in " : (request.method == "PUT" ? "to add content in " : (request.method == "DELETE" ? "to delete content in " : (request.method == "PATCH" ? "to patch content in " : "to access content using " + request.method + " method in "))))) + (request.headers.host == undefined ? "" : request.headers.host) + request.url);
else serverconsole.reqmessage("Client " + ((!reqip || reqip == "") ? "[unknown client]" : (reqip + ((reqport && reqport !== 0) && reqport != "" ? ":" + reqport : ""))) + " wants " + (request.method == "GET" ? "content in " : (request.method == "POST" ? "to post content in " : (request.method == "PUT" ? "to add content in " : (request.method == "DELETE" ? "to delete content in " : (request.method == "PATCH" ? "to patch content in " : "to access content using " + request.method + " method in "))))) + request.url);
if (request.headers["user-agent"] != undefined) serverconsole.reqmessage("Client uses " + request.headers["user-agent"]);
@@ -3114,9 +3143,9 @@ if (!cluster.isMaster) {
431: "The request you sent contains headers, that are too large.",
451: "The requested file isn't accessible for legal reasons.",
500: "The server had an unexpected error. Below, the error stack is shown:
{stack}
Please contact with developer/administrator at {contact}.",
- 501: "The request requires use of a function, which isn't implemented (yet) by the server.",
+ 501: "The request requires use of a function, which isn't currently implemented by the server.",
502: "The server had an error, while it was acting as a gateway.
Please contact with developer/administrator at {contact}.",
- 503: "Service provided by the server isn't available (yet).
Please contact with developer/administrator at {contact}.",
+ 503: "The service provided by the server is currently unavailable, possibly due to maintenance downtime or capacity problems. Please try again later.
Please contact with developer/administrator at {contact}.",
504: "The server couldn't get response in time, while it was acting as a gateway.
Please contact with developer/administrator at {contact}.",
505: "The server doesn't support HTTP version used in the request.",
506: "Variant header is configured to be engaged in content negotiation.
Please contact with developer/administrator at {contact}.",
@@ -3129,7 +3158,6 @@ if (!cluster.isMaster) {
599: "The server couldn't connect in time, while it was acting as a proxy."
};
- //Server error calling method
// Server error calling method
function callServerError(errorCode, extName, stack, ch) {
if (typeof errorCode !== "number") {
@@ -3179,17 +3207,16 @@ if (!cluster.isMaster) {
// Process custom headers if provided
if (ch) {
var chon = Object.keys(cheaders);
- var chn = Object.keys(ch);
- for (var i = 0; i < chn.length; i++) {
- var nhn = chn[i];
+ Object.keys(ch).forEach(function (chnS) {
+ var nhn = chnS;
for (var j = 0; j < chon.length; j++) {
- if (chon[j].toLowerCase() == chn[i].toLowerCase()) {
+ if (chon[j].toLowerCase() == chnS.toLowerCase()) {
nhn = chon[j];
break;
}
}
- if (ch[chn[i]]) cheaders[nhn] = ch[chn[i]];
- }
+ if (ch[chnS]) cheaders[nhn] = ch[chnS];
+ });
}
cheaders["Content-Type"] = "text/html; charset=utf-8";
@@ -3214,7 +3241,7 @@ if (!cluster.isMaster) {
} else if (err.code == "EACCES") {
additionalError = 403;
} else if (err.code == "EMFILE") {
- additionalError = 429;
+ additionalError = 503;
} else if (err.code == "ELOOP") {
additionalError = 508;
}
@@ -3521,21 +3548,10 @@ if (!cluster.isMaster) {
return;
}
- if (href == "/invoke500.svr" || (os.platform() == "win32" && href.toLowerCase() == "/invoke500.svr")) {
- if (version.indexOf("Nightly-") === 0 && uobject.query.crash !== undefined) throw new Error("Intentionally crashed");
+ if (version.indexOf("Nightly-") === 0 && (href == "/invoke500.svr" || (os.platform() == "win32" && href.toLowerCase() == "/invoke500.svr"))) {
+ if (uobject.query.crash !== undefined) throw new Error("Intentionally crashed");
try {
- if (uobject.query.aprilfools === undefined) throw new Error("This page is intended to return 500 code.");
- var hdhds = getCustomHeaders();
- hdhds["Content-Type"] = "text/html; charset=utf-8";
- if (uobject.query.activate === undefined) {
- res.writeHead(599, "You may be a victim of software counterfeiting.", hdhds);
- res.end("
To use all DorianTech SVR.JS features, such as all directory traversal protections; use server-side JS; and recieve product support, your copy of DorianTech SVR.JS must be validated as genuine.
This copy of SVR.JS is not genuine.");
- serverconsole.resmessage("You may be a victim of software counterfeiting.");
- } else {
- res.writeHead(200, "OK", hdhds);
- res.end("\n\n\n\nSVR.JS Genuine Advantage\n\n\n
Activate SVR.JS
\nYou will then be able to use all of SVR.JS features through SVR.JS Genuine Advantage!\n\n
Wait...
\n\n\n\nThis copy of SVR.JS is not genuine.");
- }
- return;
+ throw new Error("This page is intended to return 500 code.");
} catch (err) {
callServerError(500, undefined, generateErrorStack(err));
return;
@@ -3551,35 +3567,15 @@ if (!cluster.isMaster) {
res.writeHead(200, "OK", hdhds);
res.end((head == "" ? "SVR.JS status" + (request.headers.host == undefined ? "" : " for " + String(req.headers.host).replace(/&/g, "&").replace(//g, ">")) + "" : head.replace(//i, "SVR.JS status" + (request.headers.host == undefined ? "" : " for " + String(req.headers.host).replace(/&/g, "&").replace(//g, ">")) + "")) + "
And Satan created Mammon. His work won people from all over the school. When people abandoned them through the Piracy Window, so Satan went back in time and created the Server to continue to wreak havoc all over the school.
\n
from The Summary of Book of ZSOiE
\n \n \n");
- return;
- }
- var randomValue = Math.random();
- if (randomValue > 0.85714) {
- res.end("\n\n\n\n \n The Book of ZSOiE, 7:28\n \n \n \n \n \n \n
The Server continues to cultivate it's Dafa. The Author found the Robot and asked him for help. Then the Robot started to help the Author to improve his Server. And the Author tries to create yet another server without using the main node...
\n
from The Book of ZSOiE, 7:28
\n \n \n");
- } else if (randomValue > 0.71429) {
- res.end("\n\n\n\n \n The Book of ZSOiE, 7:16\n \n \n \n \n \n \n
The Server is still going. But the Author commanded to the Server: \"thou shalt you split to two branches.\". And the Server did split it's Dafa. One of two branches stopped serving on old and rusty node. Other one is still serving on that, but it will later vanish... \"Mammon will get confused\" - said the Author.
\n
from The Book of ZSOiE, 7:16
\n \n \n");
- } else if (randomValue > 0.57143) {
- res.end("\n\n\n\n \n The Book of ZSOiE, 7:2\n \n \n \n \n \n \n
The old Server forces died. The all-powerful new Server rosen from ashes of old Server like phoenix followed the ways of Durability-Ease-Reliability and cultivated his Dafa. Then, the Author and Whyvn appeared on best former Mammon's disciples paper.
\n
from The Book of ZSOiE, 7:2
\n \n \n");
- } else if (randomValue > 0.42857) {
- res.end("\n\n\n\n \n The Book of ZSOiE, 6:24\n \n \n \n \n \n \n
Mammon had enough karmic retribution. The Author tried it's Server on main node's substitute. Then, the Author saw, that Server's Dafa is good, and that main node, it's substitute, and older Mammon are good. Meanwhile the Author, Whyvn, and Snovbyn rejoiced even more from their success over older Mammon.
\n
from The Book of ZSOiE, 6:24
\n \n \n");
- } else if (randomValue > 0.32143) {
- res.end("\n\n\n\n \n The Book of ZSOiE, 6:6\n \n \n \n \n \n \n
And the Server is about to come. The Author along with Whyvn and Snovbyn passing the Mammon's test rejoiced their success over older Mammon.
\n
from The Book of ZSOiE, 6:6
\n \n \n");
- } else if (randomValue > 0.14286) {
- res.end("\n\n\n\n \n The Book of ZSOiE, 5:25\n \n \n \n \n \n \n
The twins of Mammon quarrelled. The Author with it's Server and it's main node plunged the Mammon's servers into darkness. Meanwhile Whyvn and Snovbyn helped him to break Mammon's servers.
\n
from The Book of ZSOiE, 5:25
\n \n \n");
- } else {
- res.end("\n\n\n\n \n The Book of ZSOiE, 3:16\n \n \n \n \n \n \n
Mammon slept. Meanwhile, the Author, Whyvn and Snovbyn being in very skill-requiring challenge casted tcpdump and mongodb on him.
\n
from The Book of ZSOiE, 3:16
\n \n \n");
- }
- return;
} else if (version.indexOf("Nightly-") === 0 && (href == "/crash.svr" || (os.platform() == "win32" && href.toLowerCase() == "/crash.svr"))) {
throw new Error("Intentionally crashed");
}
-
+
+ /////////////////////////////////////////////
+ ////THERE IS NO MORE "THE BOOK OF ZSOIE"!////
+ //// But it's in easteregg.tar.gz mod... ////
+ /////////////////////////////////////////////
+
var pth = decodeURIComponent(href).replace(/\/+/g, "/").substr(1);
var readFrom = "./" + pth;
fs.stat(readFrom, function (err, stats) {
@@ -3609,7 +3605,7 @@ if (!cluster.isMaster) {
serverconsole.errmessage("Access denied.");
return;
} else if (err.code == "EMFILE") {
- callServerError(500, undefined, generateErrorStack(err)); // Too many file descriptors or open files were reached by the process. It is an internal server issue.
+ callServerError(503);
return;
} else if (err.code == "ELOOP") {
callServerError(508); // The symbolic link loop is detected during file system operations.
@@ -3681,10 +3677,10 @@ if (!cluster.isMaster) {
: (fs.existsSync("." + decodeURIComponent(href) + "/FOOT.html".replace(/\/+/g, "/")) && (os.platform != "win32" || href != "/"))
? fs.readFileSync("." + decodeURIComponent(href) + "/FOOT.html".replace(/\/+/g, "/")).toString()
: "";
-
+
// Check if custom header has HTML tag
var headerHasHTMLTag = customDirListingHeader.replace(/|$)/gs, "").match(/])*(?:>|$)/si);
-
+
// Generate HTML head and footer based on configuration and custom content
var htmlHead = (!configJSON.enableDirectoryListingWithDefaultHead || head == ""
? (!headerHasHTMLTag
@@ -3764,8 +3760,7 @@ if (!cluster.isMaster) {
getStatsForAllFiles(list, "." + decodeURIComponent(href), function (filelist) {
// Function to check file extension
function checkEXT(filename, ext) {
- if (filename.length < ext.length) return false;
- return filename.toLowerCase().indexOf(ext) === filename.length - ext.length;
+ return filename.match(new RegExp("\\." + ext.replace(/^\./,"").replace(/([.+*?^$()\[\]{}|\\])/,"\\$1") + "$","i"));
}
var directoryListingRows = [];
@@ -3882,7 +3877,7 @@ if (!cluster.isMaster) {
callServerError(403);
serverconsole.errmessage("Access denied.");
} else if (err.code == "EMFILE") {
- callServerError(500, undefined, generateErrorStack(err)); // Too many file descriptors or open files were reached by the process. It is an internal server issue.
+ callServerError(503);
} else if (err.code == "ELOOP") {
callServerError(508); // The symbolic link loop is detected during file system operations.
serverconsole.errmessage("Symbolic link loop detected.");
@@ -3896,12 +3891,12 @@ if (!cluster.isMaster) {
callServerError(403);
serverconsole.errmessage("Directory listing is disabled.");
}
-
+
} else {
var acceptEncoding = req.headers["accept-encoding"];
if (!acceptEncoding) acceptEncoding = "";
-
+
// Check if the requested file exists and handle errors
fs.stat(readFrom, function (err, stats) {
if (err) {
@@ -3915,7 +3910,7 @@ if (!cluster.isMaster) {
callServerError(403);
serverconsole.errmessage("Access denied.");
} else if (err.code == "EMFILE") {
- callServerError(500, undefined, generateErrorStack(err)); // Too many file descriptors or open files were reached by the process. It is an internal server issue.
+ callServerError(503);
} else if (err.code == "ELOOP") {
callServerError(508); // The symbolic link loop is detected during file system operations.
serverconsole.errmessage("Symbolic link loop detected.");
@@ -3937,23 +3932,23 @@ if (!cluster.isMaster) {
}
var filelen = stats.size;
-
+
//ETag code
var fileETag = undefined;
if (configJSON.enableETag == undefined || configJSON.enableETag) {
fileETag = generateETag(href, stats);
// Check if the client's request matches the ETag value (If-None-Match)
- var clientETag = req.headers['if-none-match'];
+ var clientETag = req.headers["if-none-match"];
if (clientETag === fileETag) {
var headers = getCustomHeaders();
headers.ETag = clientETag;
- res.writeHead(304, 'Not Modified', headers);
+ res.writeHead(304, "Not Modified", headers);
res.end();
return;
}
// Check if the client's request doesn't match the ETag value (If-Match)
- var ifMatchETag = req.headers['if-match'];
+ var ifMatchETag = req.headers["if-match"];
if (ifMatchETag && ifMatchETag !== "*" && ifMatchETag !== fileETag) {
var headers = getCustomHeaders();
headers.ETag = clientETag;
@@ -3961,7 +3956,7 @@ if (!cluster.isMaster) {
return;
}
}
-
+
// Helper function to check if compression is allowed for the file
function canCompress(path, list) {
var canCompress = true;
@@ -4019,7 +4014,7 @@ if (!cluster.isMaster) {
rhd["Content-Length"] = end - begin + 1;
if (!(mime.contentType(ext) == false) && ext != "") rhd["Content-Type"] = mime.contentType(ext);
if(fileETag) rhd["ETag"] = fileETag;
-
+
if (req.method != "HEAD") {
var readStream = fs.createReadStream(readFrom, {
start: begin,
@@ -4036,7 +4031,7 @@ if (!cluster.isMaster) {
callServerError(403);
serverconsole.errmessage("Access denied.");
} else if (err.code == "EMFILE") {
- callServerError(500, undefined, generateErrorStack(err)); // Too many file descriptors or open files were reached by the process. It is an internal server issue.
+ callServerError(503);
} else if (err.code == "ELOOP") {
callServerError(508); // The symbolic link loop is detected during file system operations.
serverconsole.errmessage("Symbolic link loop detected.");
@@ -4095,7 +4090,7 @@ if (!cluster.isMaster) {
callServerError(403);
serverconsole.errmessage("Access denied.");
} else if (err.code == "EMFILE") {
- callServerError(500, undefined, generateErrorStack(err)); // Too many file descriptors or open files were reached by the process. It is an internal server issue.
+ callServerError(503);
} else if (err.code == "ELOOP") {
callServerError(508); // The symbolic link loop is detected during file system operations.
serverconsole.errmessage("Symbolic link loop detected.");
@@ -4202,10 +4197,27 @@ if (!cluster.isMaster) {
sanitizedURL.slashes = null;
sanitizedURL = url.format(sanitizedURL);
serverconsole.resmessage("URL sanitized: " + req.url + " => " + sanitizedURL);
- redirect(sanitizedURL, false);
- return;
+ if(rewriteDirtyURLs) {
+ req.url = sanitizedURL;
+ uobject = parseURL(req.url);
+ search = uobject.search;
+ href = uobject.pathname;
+ ext = path.extname(href).toLowerCase();
+ ext = ext.substr(1, ext.length);
+ try {
+ decodedHref = decodeURIComponent(href);
+ } catch (err) {
+ //Return 400 error
+ callServerError(400);
+ serverconsole.errmessage("Bad request!");
+ return;
+ }
+ } else {
+ redirect(sanitizedURL, false);
+ return;
+ }
}
-
+
//URL REWRITING
function rewriteURL(address, map) {
var rewrittenAddress = address;
@@ -4251,6 +4263,11 @@ if (!cluster.isMaster) {
rewrittenAgainURL.path = null;
rewrittenAgainURL.href = null;
rewrittenAgainURL.pathname = sHref;
+ rewrittenAgainURL.hostname = null;
+ rewrittenAgainURL.host = null;
+ rewrittenAgainURL.port = null;
+ rewrittenAgainURL.protocol = null;
+ rewrittenAgainURL.slashes = null;
rewrittenAgainURL = url.format(rewrittenAgainURL);
serverconsole.resmessage("URL sanitized: " + req.url + " => " + rewrittenAgainURL);
req.url = rewrittenAgainURL;
@@ -4270,10 +4287,9 @@ if (!cluster.isMaster) {
}
}
}
-
+
//Set response headers
if (!isProxy) {
- reqcounter++;
var hkh = getCustomHeaders();
var hk = Object.keys(hkh);
for (var i = 0; i < hk.length; i++) {
@@ -4284,7 +4300,7 @@ if (!cluster.isMaster) {
}
}
}
-
+
//Check if path is forbidden
if ((isForbiddenPath(decodedHref, "config") || isForbiddenPath(decodedHref, "certificates")) && !isProxy) {
callServerError(403);
@@ -4310,7 +4326,7 @@ if (!cluster.isMaster) {
for (var i = 0; i < nonStandardCodes.length; i++) {
var isMatch = false;
if (nonStandardCodes[i].regex) {
- var createdRegex = createRegex(nonStandardCodes[i].regex, true)
+ var createdRegex = createRegex(nonStandardCodes[i].regex, true);
isMatch = req.url.match(createdRegex) || href.match(createdRegex);
regexI.push(createdRegex);
} else {
@@ -4371,11 +4387,73 @@ if (!cluster.isMaster) {
return;
}
}
-
+
// Handle HTTP authentication
if (authIndex > -1) {
var authcode = nonStandardCodes[authIndex];
-
+
+ function checkIfPasswordMatches(list, password, callback, _i) {
+ if(!_i) _i = 0;
+ var cb = function (hash) {
+ var matches = (hash == list[_i].pass);
+ if(matches) {
+ callback(true);
+ } else if(_i >= list.length-1) {
+ callback(false);
+ } else {
+ checkIfPasswordMatches(list, password, callback, _i+1);
+ }
+ }
+ var hashedPassword = sha256(password + list[_i].salt);
+ if(list[_i].scrypt) {
+ if(!crypto.scrypt) {
+ callServerError(500, undefined, new Error("SVR.JS doesn't support scrypt-hashed passwords on Node.JS versions without scrypt hash support."));
+ return;
+ } else {
+ var cacheEntry = scryptCache.find(function(entry) {
+ return (entry.password == hashedPassword && entry.salt == list[_i].salt)
+ });
+ if(cacheEntry) {
+ cb(cacheEntry.hash);
+ } else {
+ crypto.scrypt(password, list[_i].salt, 64, function(err, derivedKey) {
+ if(err) {
+ callServerError(500, undefined, err);
+ } else {
+ var key = derivedKey.toString("hex");
+ scryptCache.push({hash: key, password: hashedPassword, salt: list[_i].salt, addDate: new Date()});
+ cb(key);
+ }
+ });
+ }
+ }
+ } else if(list[_i].pbkdf2) {
+ if(crypto.__disabled__ !== undefined) {
+ callServerError(500, undefined, new Error("SVR.JS doesn't support PBKDF2-hashed passwords on Node.JS versions without crypto support."));
+ return;
+ } else {
+ var cacheEntry = pbkdf2Cache.find(function(entry) {
+ return (entry.password == hashedPassword && entry.salt == list[_i].salt)
+ });
+ if(cacheEntry) {
+ cb(cacheEntry.hash);
+ } else {
+ crypto.pbkdf2(password, list[_i].salt, 36250, 64, "sha512", function(err, derivedKey) {
+ if(err) {
+ callServerError(500, undefined, err);
+ } else {
+ var key = derivedKey.toString("hex");
+ pbkdf2Cache.push({hash: key, password: hashedPassword, salt: list[_i].salt, addDate: new Date()});
+ cb(key);
+ }
+ });
+ }
+ }
+ } else {
+ cb(hashedPassword);
+ }
+ }
+
function authorizedCallback(bruteProtection) {
var ha = getCustomHeaders();
ha["WWW-Authenticate"] = "Basic realm=\"" + (authcode.realm ? authcode.realm.replace(/(\\|")/g, "\\$1") : "SVR.JS HTTP Basic Authorization") + "\", charset=\"UTF-8\"";
@@ -4400,42 +4478,42 @@ if (!cluster.isMaster) {
}
var username = decodedCredentialsMatch[1];
var password = decodedCredentialsMatch[2];
- var authorized = false;
- for (var i = 0; i < users.length; i++) {
- var hash = sha256(password + users[i].salt);
- if (users[i].name == username && users[i].pass == hash) {
- authorized = true;
- break;
- }
+ var usernameMatch = users.filter(function (entry) {
+ return entry.name == username;
+ });
+ if(usernameMatch.length == 0) {
+ usernameMatch.push({name: username, pass: "FAKEPASS", salt: "FAKESALT"}); //Fake credentials
}
- if (!authorized) {
- if (bruteProtection) {
- if (process.send) {
- process.send("\x12AUTHW" + reqip);
- } else {
- if (!bruteForceDb[reqip]) bruteForceDb[reqip] = {
- invalidAttempts: 0
- };
- bruteForceDb[reqip].invalidAttempts++;
- if (bruteForceDb[reqip].invalidAttempts >= 10) {
- bruteForceDb[reqip].lastAttemptDate = new Date();
+ checkIfPasswordMatches(usernameMatch, password, function(authorized) {
+ if (!authorized) {
+ if (bruteProtection) {
+ if (process.send) {
+ process.send("\x12AUTHW" + reqip);
+ } else {
+ if (!bruteForceDb[reqip]) bruteForceDb[reqip] = {
+ invalidAttempts: 0
+ };
+ bruteForceDb[reqip].invalidAttempts++;
+ if (bruteForceDb[reqip].invalidAttempts >= 10) {
+ bruteForceDb[reqip].lastAttemptDate = new Date();
+ }
}
}
- }
- callServerError(401, undefined, undefined, ha);
- serverconsole.errmessage("User " + username + " failed to log in.");
- } else {
- if (bruteProtection) {
- if (process.send) {
- process.send("\x12AUTHR" + reqip);
- } else {
- if (bruteForceDb[reqip]) bruteForceDb[reqip] = {
- invalidAttempts: 0
- };
+ callServerError(401, undefined, undefined, ha);
+ serverconsole.errmessage("User " + username + " failed to log in.");
+ } else {
+ if (bruteProtection) {
+ if (process.send) {
+ process.send("\x12AUTHR" + reqip);
+ } else {
+ if (bruteForceDb[reqip]) bruteForceDb[reqip] = {
+ invalidAttempts: 0
+ };
+ }
}
+ modExecute(mods, vres(req, res, serverconsole, responseEnd, href, ext, uobject, search, "index.html", users, page404, head, foot, fd, callServerError, getCustomHeaders, origHref, redirect, parsePostData));
}
- modExecute(mods, vres(req, res, serverconsole, responseEnd, href, ext, uobject, search, "index.html", users, page404, head, foot, fd, callServerError, getCustomHeaders, origHref, redirect, parsePostData));
- }
+ });
}
if (authcode.disableBruteProtection) {
authorizedCallback(false);
@@ -4482,69 +4560,78 @@ if (!cluster.isMaster) {
}
//Listen port to server
server.on("error", function (err) {
- if (err.code == "EADDRINUSE" || err.code == "EADDRNOTAVAIL" || err.code == "EACCES") {
- attmts--;
- if (cluster.isMaster === undefined) {
- if (err.code == "EADDRINUSE") {
- serverconsole.locerrmessage("Address is already in use by another process.");
- } else if (err.code == "EADDRNOTAVAIL") {
- serverconsole.locerrmessage("Address is not available on this machine.");
- } else if (err.code == "EACCES") {
- serverconsole.locerrmessage("Permission denied. You may not have sufficient privileges to access the requested address.");
- } else if (err.code == "EAFNOSUPPORT") {
- serverconsole.locerrmessage("Address family not supported. The address family (IPv4 or IPv6) of the requested address is not supported.");
- } else if (err.code == "EALREADY") {
- serverconsole.locerrmessage("Operation already in progress. The server is already in the process of establishing a connection on the requested address.");
- } else if (err.code == "ECONNABORTED") {
- serverconsole.locerrmessage("Connection aborted. The connection to the server was terminated abruptly.");
- } else if (err.code == "ECONNREFUSED") {
- serverconsole.locerrmessage("Connection refused. The server refused the connection attempt.");
- } else if (err.code == "ECONNRESET") {
- serverconsole.locerrmessage("Connection reset by peer. The connection to the server was reset by the remote host.");
- } else if (err.code == "EDESTADDRREQ") {
- serverconsole.locerrmessage("Destination address required. The destination address must be specified.");
- } else if (err.code == "ENETDOWN") {
- serverconsole.locerrmessage("Network is down. The network interface used for the connection is not available.");
- } else if (err.code == "ENETUNREACH") {
- serverconsole.locerrmessage("Network is unreachable. The network destination is not reachable from this host.");
- } else if (err.code == "ENOBUFS") {
- serverconsole.locerrmessage("No buffer space available. Insufficient buffer space is available for the server to process the request.");
- } else if (err.code == "ENOTSOCK") {
- serverconsole.locerrmessage("Not a socket. The file descriptor provided is not a valid socket.");
- } else if (err.code == "EPROTO") {
- serverconsole.locerrmessage("Protocol error. An unspecified protocol error occurred.");
- } else if (err.code == "EPROTONOSUPPORT") {
- serverconsole.locerrmessage("Protocol not supported. The requested network protocol is not supported.");
- } else if (err.code == "ETIMEDOUT") {
- serverconsole.locerrmessage("Connection timed out. The server did not respond within the specified timeout period.");
- } else {
- serverconsole.locerrmessage("There was an unknown error with the server.");
- }
- serverconsole.locmessage(attmts + " attempts left.");
+ attmts--;
+ if (cluster.isPrimary === undefined && attmts >= 0) {
+ if (err.code == "EADDRINUSE") {
+ serverconsole.locerrmessage("Address is already in use by another process.");
+ } else if (err.code == "EADDRNOTAVAIL") {
+ serverconsole.locerrmessage("Address is not available on this machine.");
+ } else if (err.code == "EACCES") {
+ serverconsole.locerrmessage("Permission denied. You may not have sufficient privileges to access the requested address.");
+ } else if (err.code == "EAFNOSUPPORT") {
+ serverconsole.locerrmessage("Address family not supported. The address family (IPv4 or IPv6) of the requested address is not supported.");
+ } else if (err.code == "EALREADY") {
+ serverconsole.locerrmessage("Operation already in progress. The server is already in the process of establishing a connection on the requested address.");
+ } else if (err.code == "ECONNABORTED") {
+ serverconsole.locerrmessage("Connection aborted. The connection to the server was terminated abruptly.");
+ } else if (err.code == "ECONNREFUSED") {
+ serverconsole.locerrmessage("Connection refused. The server refused the connection attempt.");
+ } else if (err.code == "ECONNRESET") {
+ serverconsole.locerrmessage("Connection reset by peer. The connection to the server was reset by the remote host.");
+ } else if (err.code == "EDESTADDRREQ") {
+ serverconsole.locerrmessage("Destination address required. The destination address must be specified.");
+ } else if (err.code == "ENETDOWN") {
+ serverconsole.locerrmessage("Network is down. The network interface used for the connection is not available.");
+ } else if (err.code == "ENETUNREACH") {
+ serverconsole.locerrmessage("Network is unreachable. The network destination is not reachable from this host.");
+ } else if (err.code == "ENOBUFS") {
+ serverconsole.locerrmessage("No buffer space available. Insufficient buffer space is available for the server to process the request.");
+ } else if (err.code == "ENOTSOCK") {
+ serverconsole.locerrmessage("Not a socket. The file descriptor provided is not a valid socket.");
+ } else if (err.code == "EPROTO") {
+ serverconsole.locerrmessage("Protocol error. An unspecified protocol error occurred.");
+ } else if (err.code == "EPROTONOSUPPORT") {
+ serverconsole.locerrmessage("Protocol not supported. The requested network protocol is not supported.");
+ } else if (err.code == "ETIMEDOUT") {
+ serverconsole.locerrmessage("Connection timed out. The server did not respond within the specified timeout period.");
} else {
- process.send("\x12ERRLIST" + attmts + err.code);
- }
- if (attmts > 0) {
- server2.close();
- setTimeout(start, 900);
- } else {
- if (cluster.isMaster !== undefined) process.send("\x12" + err.code);
- process.exit(errors[err.code]);
+ serverconsole.locerrmessage("There was an unknown error with the server.");
}
+ serverconsole.locmessage(attmts + " attempts left.");
} else {
- serverconsole.locerrmessage("There was a problem starting SVR.JS!!!");
- serverconsole.locerrmessage("Stack:");
- serverconsole.locerrmessage(generateErrorStack(err));
- if (cluster.isMaster !== undefined) process.send("\x12CRASH");
- process.exit(err.code ? errors[err.code] : 1);
+ try {
+ process.send("\x12ERRLIST" + attmts + err.code);
+ } catch(ex) {
+ // Probably main process exited
+ }
+ }
+ if (attmts > 0) {
+ server2.close();
+ setTimeout(start, 900);
+ } else {
+ try {
+ if (cluster.isPrimary !== undefined) process.send("\x12ERRCRASH" + err.code);
+ } catch(ex) {
+ // Probably main process exited
+ }
+ setTimeout(function () {
+ var errno = errors[err.code];
+ if(errno) {
+ process.exit(errno);
+ } else {
+ process.exit(1);
+ }
+ }, 50);
}
});
- server.once("listening", function () {
+ server.on("listening", function () {
listeningMessage();
});
}
+var closedMaster = true;
+
function listenConnListener(msg) {
if (msg == "\x12LISTEN") {
listeningMessage();
@@ -4582,6 +4669,8 @@ function bruteForceListenerWrapper(worker) {
};
}
+var isWorkerHungUpBuff = true;
+
function msgListener(msg) {
for (var i = 0; i < Object.keys(cluster.workers).length; i++) {
if (msg == "\x12END") {
@@ -4594,15 +4683,17 @@ function msgListener(msg) {
closedMaster = true;
} else if (msg == "\x12LISTEN" || msg.substr(0, 4) == "\x12AUTH") {
//Do nothing!
+ } else if (msg == "\x12KILLOK") {
+ if(typeof isWorkerHungUpBuff != "undefined") isWorkerHungUpBuff = false;
+ } else if (msg == "\x12KILLTERMMSG") {
+ serverconsole.locmessage("Terminating unused worker process...");
} else if (msg == "\x12SAVEGOOD") {
serverconsole.locmessage("Configuration saved.");
} else if (msg.indexOf("\x12SAVEERR") == 0) {
serverconsole.locwarnmessage("There was a problem, while saving configuration file. Reason: " + msg.substr(8));
- } else if (msg == "\x12OPEN") {
- closedMaster = false;
} else if (msg == "\x12END") {
cluster.workers[Object.keys(cluster.workers)[0]].on("message", function (msg) {
- if (msg.length > 9 && msg.indexOf("\x12ERRLIST") == 0) {
+ if (msg.length >= 8 && msg.indexOf("\x12ERRLIST") == 0) {
var tries = parseInt(msg.substr(8, 1));
var errCode = msg.substr(9);
if (errCode == "EADDRINUSE") {
@@ -4642,8 +4733,14 @@ function msgListener(msg) {
}
serverconsole.locmessage(tries + " attempts left.");
}
- if (msg == "\x12CRASH") process.exit(1);
- if (msg == "\x12EADDRINUSE" || msg == "\x12EADDRNOTAVAIL" || msg == "\x12EACCES") process.exit(errors[msg.substr(1)]);
+ if (msg.length >= 9 && msg.indexOf("\x12ERRCRASH") == 0) {
+ var errno = errors[msg.substr(9)];
+ if(errno) {
+ process.exit(errno);
+ } else {
+ process.exit(1);
+ }
+ }
});
} else {
serverconsole.climessage(msg);
@@ -4653,12 +4750,13 @@ function msgListener(msg) {
var messageTransmitted = false;
function listeningMessage() {
- if (messageTransmitted) return;
- messageTransmitted = true;
- if (!cluster.isMaster && cluster.isMaster !== undefined) {
+ if(typeof closedMaster !== "undefined") closedMaster = false;
+ if (!cluster.isPrimary && cluster.isPrimary !== undefined) {
process.send("\x12LISTEN");
return;
}
+ if (messageTransmitted) return;
+ messageTransmitted = true;
serverconsole.locmessage("Started server at: ");
if (secure) {
if (typeof sport === "number") {
@@ -4691,11 +4789,9 @@ function listeningMessage() {
});
}
-var closedMaster = false;
-
function start(init) {
init = Boolean(init);
- if (cluster.isMaster || cluster.isMaster === undefined) {
+ if (cluster.isPrimary || cluster.isPrimary === undefined) {
if (init) {
for (i = 0; i < logo.length; i++) console.log(logo[i]); //Print logo
console.log();
@@ -4704,9 +4800,14 @@ function start(init) {
if (version.indexOf("Nightly-") === 0) serverconsole.locwarnmessage("This version is only for test purposes and may be unstable.");
if (http2.__disabled__ !== undefined) serverconsole.locwarnmessage("HTTP/2 isn't supported by your Node.JS version! You may not be able to use HTTP/2 with SVR.JS");
if (configJSON.enableHTTP2 && !secure) serverconsole.locwarnmessage("HTTP/2 without HTTPS may not work in web browsers. Web browsers only support HTTP/2 with HTTPS!");
- if (process.isBun) serverconsole.locwarnmessage("Bun support is experimental. Some features of SVR.JS, SVR.JS mods and SVR.JS server-side JavaScript may not work as expected.");
- if (cluster.isMaster === undefined) serverconsole.locwarnmessage("You're running SVR.JS on single thread. Reliability may suffer, as the server is stopped after crash.");
- if (crypto.__disabled__ !== undefined) serverconsole.locwarnmessage("Your Node.JS version doesn't have crypto support! The 'crypto' module is essential for providing cryptographic functionality in Node.js. Without crypto support, certain security features may be unavailable, and some functionality may not work as expected. It's recommended to use a Node.JS version that includes crypto support to ensure the security and proper functioning of your server.");
+ if (process.isBun) {
+ serverconsole.locwarnmessage("Bun support is experimental. Some features of SVR.JS, SVR.JS mods and SVR.JS server-side JavaScript may not work as expected.");
+ if(users.some(function(entry) {return entry.pbkdf2;})) serverconsole.locwarnmessage("PBKDF2 password hashing function in Bun blocks the event loop, which may result in denial of service.");
+ if(users.some(function(entry) {return entry.scrypt;})) serverconsole.locwarnmessage("scrypt password hashing function in Bun blocks the event loop, which may result in denial of service.");
+ }
+ if (cluster.isPrimary === undefined) serverconsole.locwarnmessage("You're running SVR.JS on single thread. Reliability may suffer, as the server is stopped after crash.");
+ if (crypto.__disabled__ !== undefined) serverconsole.locwarnmessage("Your Node.JS version doesn't have crypto support! The 'crypto' module is essential for providing cryptographic functionality in Node.JS. Without crypto support, certain security features may be unavailable, and some functionality may not work as expected. It's recommended to use a Node.JS version that includes crypto support to ensure the security and proper functioning of your server.");
+ if (crypto.__disabled__ === undefined && !crypto.scrypt) serverconsole.locwarnmessage("Your JavaScript runtime doesn't have native scrypt support. HTTP authentication involving scrypt hashes will not work.");
if (process.getuid && process.getuid() == 0) serverconsole.locwarnmessage("You're running SVR.JS as root. It's recommended to run SVR.JS as an non-root user. Running SVR.JS as root may increase the risks of OS command execution vulnerabilities.");
if (secure && process.versions && process.versions.openssl && process.versions.openssl.substr(0, 2) == "1.") {
if (new Date() > new Date("11 September 2023")) {
@@ -4738,7 +4839,7 @@ function start(init) {
}
- if (!cluster.isMaster) {
+ if (!cluster.isPrimary) {
if (secure) {
server.listen(sport);
if (!disableNonEncryptedServer) server2.listen(port);
@@ -4755,13 +4856,13 @@ function start(init) {
if (secure && !disableNonEncryptedServer) {
server2.close();
}
- if (cluster.isMaster === undefined) serverconsole.climessage("Server closed.");
+ if (cluster.isPrimary === undefined) serverconsole.climessage("Server closed.");
else {
process.send("Server closed.");
process.send("\x12CLOSE");
}
} catch (err) {
- if (cluster.isMaster === undefined) serverconsole.climessage("Cannot close server! Reason: " + err.message);
+ if (cluster.isPrimary === undefined) serverconsole.climessage("Cannot close server! Reason: " + err.message);
else process.send("Cannot close server! Reason: " + err.message);
}
},
@@ -4773,38 +4874,81 @@ function start(init) {
} else {
server.listen(port); // Reopen Server
}
- if (cluster.isMaster === undefined) serverconsole.climessage("Server opened.");
+ if (cluster.isPrimary === undefined) serverconsole.climessage("Server opened.");
else {
process.send("Server opened.");
- process.send("\x12OPEN");
}
} catch (err) {
- if (cluster.isMaster === undefined) serverconsole.climessage("Cannot open server! Reason: " + err.message);
+ if (cluster.isPrimary === undefined) serverconsole.climessage("Cannot open server! Reason: " + err.message);
else process.send("Cannot open server! Reason: " + err.message);
}
},
help: function () {
- if (cluster.isMaster === undefined) serverconsole.climessage("Server commands:\n" + Object.keys(commands).join(" "));
+ if (cluster.isPrimary === undefined) serverconsole.climessage("Server commands:\n" + Object.keys(commands).join(" "));
else process.send("Server commands:\n" + Object.keys(commands).join(" "));
},
mods: function () {
- if (cluster.isMaster === undefined) serverconsole.climessage("Mods:");
+ if (cluster.isPrimary === undefined) serverconsole.climessage("Mods:");
else process.send("Mods:");
for (var i = 0; i < modInfos.length; i++) {
- if (cluster.isMaster === undefined) serverconsole.climessage((i + 1).toString() + ". " + modInfos[i].name + " " + modInfos[i].version);
+ if (cluster.isPrimary === undefined) serverconsole.climessage((i + 1).toString() + ". " + modInfos[i].name + " " + modInfos[i].version);
else process.send((i + 1).toString() + ". " + modInfos[i].name + " " + modInfos[i].version);
}
if (modInfos.length == 0) {
- if (cluster.isMaster === undefined) serverconsole.climessage("No mods installed.");
+ if (cluster.isPrimary === undefined) serverconsole.climessage("No mods installed.");
else process.send("No mods installed.");
}
},
stop: function (retcode) {
reallyExiting = true;
- if (typeof retcode == "number") {
- process.exit(retcode);
+ clearInterval(pbkdf2CacheIntervalId);
+ if((!cluster.isPrimary && cluster.isPrimary !== undefined) && server.listening) {
+ try {
+ server.close(function() {
+ if(server2.listening) {
+ try {
+ server2.close(function() {
+ if(!process.removeFakeIPC) {
+ if (typeof retcode == "number") {
+ process.exit(retcode);
+ } else {
+ process.exit(0);
+ }
+ }
+ });
+ } catch(err) {
+ if(!process.removeFakeIPC) {
+ if (typeof retcode == "number") {
+ process.exit(retcode);
+ } else {
+ process.exit(0);
+ }
+ }
+ }
+ } else {
+ if(!process.removeFakeIPC) {
+ if (typeof retcode == "number") {
+ process.exit(retcode);
+ } else {
+ process.exit(0);
+ }
+ }
+ }
+ });
+ } catch(err) {
+ if (typeof retcode == "number") {
+ process.exit(retcode);
+ } else {
+ process.exit(0);
+ }
+ }
+ if(process.removeFakeIPC) process.removeFakeIPC();
} else {
- process.exit(0);
+ if (typeof retcode == "number") {
+ process.exit(retcode);
+ } else {
+ process.exit(0);
+ }
}
},
clear: function () {
@@ -4812,8 +4956,8 @@ function start(init) {
},
block: function (ip) {
if (ip == undefined || JSON.stringify(ip) == "[]") {
- if (cluster.isMaster === undefined) serverconsole.climessage("Cannot block non-existent IP.");
- else if (!cluster.isMaster) process.send("Cannot block non-existent IP.");
+ if (cluster.isPrimary === undefined) serverconsole.climessage("Cannot block non-existent IP.");
+ else if (!cluster.isPrimary) process.send("Cannot block non-existent IP.");
} else {
for (var i = 0; i < ip.length; i++) {
if (ip[i].indexOf(":") == -1) {
@@ -4823,14 +4967,14 @@ function start(init) {
blacklist.add(ip[i]);
}
}
- if (cluster.isMaster === undefined) serverconsole.climessage("IPs successfully blocked.");
- else if (!cluster.isMaster) process.send("IPs successfully blocked.");
+ if (cluster.isPrimary === undefined) serverconsole.climessage("IPs successfully blocked.");
+ else if (!cluster.isPrimary) process.send("IPs successfully blocked.");
}
},
unblock: function (ip) {
if (ip == undefined || JSON.stringify(ip) == "[]") {
- if (cluster.isMaster === undefined) serverconsole.climessage("Cannot unblock non-existent IP.");
- else if (!cluster.isMaster) process.send("Cannot unblock non-existent IP.");
+ if (cluster.isPrimary === undefined) serverconsole.climessage("Cannot unblock non-existent IP.");
+ else if (!cluster.isPrimary) process.send("Cannot unblock non-existent IP.");
} else {
for (var i = 0; i < ip.length; i++) {
if (ip[i].indexOf(":") == -1) {
@@ -4838,19 +4982,19 @@ function start(init) {
}
blacklist.remove(ip[i]);
}
- if (cluster.isMaster === undefined) serverconsole.climessage("IPs successfully unblocked.");
- else if (!cluster.isMaster) process.send("IPs successfully unblocked.");
+ if (cluster.isPrimary === undefined) serverconsole.climessage("IPs successfully unblocked.");
+ else if (!cluster.isPrimary) process.send("IPs successfully unblocked.");
}
},
restart: function () {
- if (cluster.isMaster === undefined) serverconsole.climessage("This command is not supported on single-threaded SVR.JS.");
+ if (cluster.isPrimary === undefined) serverconsole.climessage("This command is not supported on single-threaded SVR.JS.");
else process.send("This command need to be run in SVR.JS master.");
}
};
if (init) {
- if (cluster.isMaster === undefined) {
+ if (cluster.isPrimary === undefined) {
setInterval(function () {
try {
saveConfig();
@@ -4859,7 +5003,7 @@ function start(init) {
throw new Error(err);
}
}, 300000);
- } else if (cluster.isMaster) {
+ } else if (cluster.isPrimary) {
setInterval(function () {
var allClusters = Object.keys(cluster.workers);
for (var i = 0; i < allClusters.length; i++) {
@@ -4879,7 +5023,17 @@ function start(init) {
}
}, 300000);
}
- if (!cluster.isMaster && cluster.isMaster !== undefined) {
+ if (!cluster.isPrimary) {
+ pbkdf2CacheIntervalId = setInterval(function () {
+ pbkdf2Cache = pbkdf2Cache.filter(function(entry) {
+ return entry.addDate > (new Date() - 3600000);
+ });
+ scryptCache = scryptCache.filter(function(entry) {
+ return entry.addDate > (new Date() - 3600000);
+ });
+ }, 10000);
+ }
+ if (!cluster.isPrimary && cluster.isPrimary !== undefined) {
process.on("message", function (line) {
try {
if (line == "") {
@@ -4894,6 +5048,19 @@ function start(init) {
process.send("\x12SAVEERR" + err.message);
}
process.send("\x12END");
+ } else if (line == "\x14KILLPING") {
+ if(!reallyExiting) {
+ process.send("\x12KILLOK");
+ process.send("\x12END");
+ }
+ // Refuse to send, when it's really exiting. Main process will treat the worker as hung up anyway...
+ } else if (line == "\x14KILLREQ") {
+ if(reqcounter - reqcounterKillReq < 2) {
+ process.send("\x12KILLTERMMSG");
+ process.nextTick(commands.stop);
+ } else {
+ reqcounterKillReq = reqcounter;
+ }
} else if (commands[line.split(" ")[0]] !== undefined && commands[line.split(" ")[0]] !== null) {
var argss = line.split(" ");
var command = argss.shift();
@@ -4922,7 +5089,7 @@ function start(init) {
var argss = line.split(" ");
var command = argss.shift();
if (line != "") {
- if (cluster.isMaster !== undefined) {
+ if (cluster.isPrimary !== undefined) {
var allClusters = Object.keys(cluster.workers);
if (command == "block") commands.block(argss);
if (command == "unblock") commands.unblock(argss);
@@ -4940,6 +5107,7 @@ function start(init) {
}
if (stopError) serverconsole.climessage("Some SVR.JS workers might not be stopped.");
SVRJSInitialized = false;
+ closedMaster = true;
var cpus = os.cpus().length;
if (cpus > 16) cpus = 16;
try {
@@ -4971,21 +5139,21 @@ function start(init) {
exiting = true;
allClusters = Object.keys(cluster.workers);
}
- for (var i = 0; i < allClusters.length; i++) {
+ allClusters.forEach(function (clusterID) {
try {
- if (cluster.workers[allClusters[i]]) {
- cluster.workers[allClusters[i]].on("message", msgListener);
- cluster.workers[allClusters[i]].send(line);
+ if (cluster.workers[clusterID]) {
+ cluster.workers[clusterID].on("message", msgListener);
+ cluster.workers[clusterID].send(line);
}
} catch (err) {
- if (cluster.workers[allClusters[i]]) {
- cluster.workers[allClusters[i]].removeAllListeners("message");
- cluster.workers[allClusters[i]].on("message", bruteForceListenerWrapper(cluster.workers[allClusters[i]]));
- cluster.workers[allClusters[i]].on("message", listenConnListener);
+ if (cluster.workers[clusterID]) {
+ cluster.workers[clusterID].removeAllListeners("message");
+ cluster.workers[clusterID].on("message", bruteForceListenerWrapper(cluster.workers[clusterID]));
+ cluster.workers[clusterID].on("message", listenConnListener);
}
serverconsole.climessage("Can't run command \"" + command + "\".");
}
- }
+ });
if (command == "stop") {
setTimeout(function () {
reallyExiting = true;
@@ -5008,9 +5176,9 @@ function start(init) {
});
}
- if (cluster.isMaster || cluster.isMaster === undefined) {
+ if (cluster.isPrimary || cluster.isPrimary === undefined) {
//Cluster forking code
- if (cluster.isMaster !== undefined && init) {
+ if (cluster.isPrimary !== undefined && init) {
var cpus = os.cpus().length;
if (cpus > 16) cpus = 16;
try {
@@ -5033,7 +5201,7 @@ function start(init) {
}
}
cluster.workers[Object.keys(cluster.workers)[0]].on("message", function (msg) {
- if (msg.length > 9 && msg.indexOf("\x12ERRLIST") == 0) {
+ if (msg.length >= 8 && msg.indexOf("\x12ERRLIST") == 0) {
var tries = parseInt(msg.substr(8, 1));
var errCode = msg.substr(9);
if (errCode == "EADDRINUSE") {
@@ -5073,10 +5241,17 @@ function start(init) {
}
serverconsole.locmessage(tries + " attempts left.");
}
- if (msg == "\x12CRASH") process.exit(1);
- if (msg == "\x12EADDRINUSE" || msg == "\x12EADDRNOTAVAIL" || msg == "\x12EACCES") process.exit(errors[msg.substr(1)]);
+ if (msg.length >= 9 && msg.indexOf("\x12ERRCRASH") == 0) {
+ var errno = errors[msg.substr(9)];
+ if(errno) {
+ process.exit(errno);
+ } else {
+ process.exit(1);
+ }
+ }
});
+ // Hangup check and restart
setInterval(function () {
if (!closedMaster && !exiting) {
var chksocket = {};
@@ -5088,7 +5263,7 @@ function start(init) {
"X-SVR-JS-From-Main-Thread": "true",
"User-Agent": (exposeServerVersion ? "SVR.JS/" + version + " (" + getOS() + "; " + (process.isBun ? ("Bun/v" + process.versions.bun + "; like Node.JS/" + process.version) : ("Node.JS/" + process.version)) + ")" : "SVR.JS")
},
- timeout: 2000,
+ timeout: 1620,
rejectUnauthorized: false
}, function (res) {
chksocket.removeAllListeners("timeout");
@@ -5114,7 +5289,7 @@ function start(init) {
else crashed = false;
}
});
- connection.setTimeout(2000, function () {
+ connection.setTimeout(1620, function () {
if (!exiting) SVRJSFork();
crashed = true;
});
@@ -5141,7 +5316,7 @@ function start(init) {
"X-SVR-JS-From-Main-Thread": "true",
"User-Agent": (exposeServerVersion ? "SVR.JS/" + version + " (" + getOS() + "; " + (process.isBun ? ("Bun/v" + process.versions.bun + "; like Node.JS/" + process.version) : ("Node.JS/" + process.version)) + ")" : "SVR.JS")
},
- timeout: 2000
+ timeout: 1620
}, function (res) {
chksocket.removeAllListeners("timeout");
res.destroy();
@@ -5159,7 +5334,73 @@ function start(init) {
});
}
}
- }, 5000);
+ }, 4550);
+
+ // Termination of unused good workers
+ if(!disableUnusedWorkerTermination && cluster.isPrimary !== undefined) {
+ setTimeout(function () {
+ setInterval(function () {
+ if (!closedMaster && !exiting) {
+ var allClusters = Object.keys(cluster.workers);
+ var minClusters = 0;
+ minClusters = Math.ceil(cpus * 0.625);
+ if(minClusters < 2) minClusters = 2;
+ var goodWorkers = [];
+ function checkWorker(callback, _id) {
+ if(typeof _id === "undefined") _id = 0;
+ if(_id >= allClusters.length) {
+ callback();
+ return;
+ }
+ try {
+ if (cluster.workers[allClusters[_id]]) {
+ isWorkerHungUpBuff = true;
+ cluster.workers[allClusters[_id]].on("message", msgListener);
+ cluster.workers[allClusters[_id]].send("\x14KILLPING");
+ setTimeout(function() {
+ if (isWorkerHungUpBuff) {
+ checkWorker(callback, _id+1);
+ } else {
+ goodWorkers.push(allClusters[_id]);
+ checkWorker(callback, _id+1);
+ }
+ }, 250);
+ } else {
+ checkWorker(callback, _id+1);
+ }
+ } catch (err) {
+ if (cluster.workers[allClusters[_id]]) {
+ cluster.workers[allClusters[_id]].removeAllListeners("message");
+ cluster.workers[allClusters[_id]].on("message", bruteForceListenerWrapper(cluster.workers[allClusters[_id]]));
+ cluster.workers[allClusters[_id]].on("message", listenConnListener);
+ }
+ checkWorker(callback, _id+1);
+ }
+ }
+ checkWorker(function() {
+ if (goodWorkers.length > minClusters) {
+ var wN = Math.floor(Math.random() * goodWorkers.length);
+ if (wN == goodWorkers.length) return;
+ try {
+ if (cluster.workers[goodWorkers[wN]]) {
+ isWorkerHungUpBuff = true;
+ cluster.workers[goodWorkers[wN]].on("message", msgListener);
+ cluster.workers[goodWorkers[wN]].send("\x14KILLREQ");
+ }
+ } catch (err) {
+ if (cluster.workers[goodWorkers[wN]]) {
+ cluster.workers[goodWorkers[wN]].removeAllListeners("message");
+ cluster.workers[goodWorkers[wN]].on("message", bruteForceListenerWrapper(cluster.workers[goodWorkers[wN]]));
+ cluster.workers[goodWorkers[wN]].on("message", listenConnListener);
+ }
+ serverconsole.locwarnmessage("There was a problem, while terminating unused worker process. Reason: " + err.message);
+ }
+ }
+ });
+ }
+ }, 300000);
+ }, 2000);
+ }
}
}
}
@@ -5207,7 +5448,9 @@ function saveConfig() {
if (configJSONobj.disableNonEncryptedServer === undefined) configJSONobj.disableNonEncryptedServer = false;
if (configJSONobj.disableToHTTPSRedirect === undefined) configJSONobj.disableToHTTPSRedirect = false;
if (configJSONobj.enableETag === undefined) configJSONobj.enableETag = true;
-
+ if (configJSONobj.disableUnusedWorkerTermination === undefined) configJSONobj.disableUnusedWorkerTermination = false;
+ if (configJSONobj.rewriteDirtyURLs === undefined) configJSONobj.rewriteDirtyURLs = false;
+
var configString = JSON.stringify(configJSONobj, null, 2);
fs.writeFileSync(__dirname + "/config.json", configString);
break;
@@ -5220,7 +5463,7 @@ function saveConfig() {
}
//Process event listeners
-if (cluster.isMaster || cluster.isMaster === undefined) {
+if (cluster.isPrimary || cluster.isPrimary === undefined) {
process.on("uncaughtException", function (err) {
//CRASH HANDLER
serverconsole.locerrmessage("SVR.JS master process just crashed!!!");
@@ -5269,7 +5512,7 @@ if (cluster.isMaster || cluster.isMaster === undefined) {
});
process.on("SIGINT", function () {
reallyExiting = true;
- if (cluster.isMaster !== undefined) {
+ if (cluster.isPrimary !== undefined) {
exiting = true;
var allClusters = Object.keys(cluster.workers);
for (var i = 0; i < allClusters.length; i++) {
diff --git a/svrpasswd.js b/svrpasswd.js
index 0942229..9a428b6 100644
--- a/svrpasswd.js
+++ b/svrpasswd.js
@@ -7,15 +7,15 @@ try {
} catch (ex) {
var crypto = {};
crypto.__disabled__ = null;
- crypto.createHash = function(type) {
+ crypto.createHash = function (type) {
if (type != "SHA256") throw new Error("Hash type not supported!");
return {
msg: "",
- update: function(a) {
+ update: function (a) {
this.msg = a;
return this;
},
- digest: function(ty) {
+ digest: function (ty) {
var chrsz = 8;
var hexcase = 0;
@@ -163,7 +163,7 @@ try {
}
if (!crypto.randomInt) {
- crypto.randomInt = function(min, max) {
+ crypto.randomInt = function (min, max) {
return Math.round(Math.random() * (max - min)) + min;
}
}
@@ -196,42 +196,58 @@ function saveConfig() {
var args = process.argv;
var user = "";
var action = "change";
+var forcechange = false;
if (process.argv.length <= (process.argv[0].indexOf("node") > -1 || process.argv[0].indexOf("bun") > -1 ? 2 : 1)) args.push("-h");
for (var i = (process.argv[0].indexOf("node") > -1 || process.argv[0].indexOf("bun") > -1 ? 2 : 1); i < args.length; i++) {
if (args[i] == "-h" || args[i] == "--help" || args[i] == "-?" || args[i] == "/h" || args[i] == "/?") {
console.log("SVR.JS user tool usage:");
- console.log("node svrpasswd.js [-h] [--help] [-?] [/h] [/?] [-a|--add|-d|--delete] ");
+ console.log("node svrpasswd.js [-h] [--help] [-?] [/h] [/?] [-x] [-a|--add|-d|--delete] ");
console.log("-h -? /h /? --help -- Displays help");
console.log("-a --add -- Add an user");
console.log("-d --delete -- Deletes an user");
+ console.log("-x -- Changes hash algorithm");
process.exit(0);
} else if (args[i] == "-a" || args[i] == "--add") {
if (action != "change") {
console.log("Multiple actions specified.");
- console.log("node svrpasswd.js [-h] [--help] [-?] [/h] [/?] [-a|--add|-d|--delete] ");
+ console.log("node svrpasswd.js [-h] [--help] [-?] [/h] [/?] [-x] [-a|--add|-d|--delete] ");
console.log("-h -? /h /? --help -- Displays help");
console.log("-a --add -- Add an user");
console.log("-d --delete -- Deletes an user");
+ console.log("-x -- Changes hash algorithm");
process.exit(1);
}
action = "add";
} else if (args[i] == "-d" || args[i] == "--delete") {
if (action != "change") {
console.log("Multiple actions specified.");
- console.log("node svrpasswd.js [-h] [--help] [-?] [/h] [/?] [-a|--add|-d|--delete] ");
+ console.log("node svrpasswd.js [-h] [--help] [-?] [/h] [/?] [-x] [-a|--add|-d|--delete] ");
console.log("-h -? /h /? --help -- Displays help");
console.log("-a --add -- Add an user");
console.log("-d --delete -- Deletes an user");
+ console.log("-x -- Changes hash algorithm");
process.exit(1);
}
action = "delete";
- } else {
- if (user != "") {
- console.log("Multiple users specified.");
- console.log("node svrpasswd.js [-h] [--help] [-?] [/h] [/?] [-a|--add|-d|--delete] ");
+ } else if (args[i] == "-x") {
+ if (forcechange) {
+ console.log("Multiple -x options specified.");
+ console.log("node svrpasswd.js [-h] [--help] [-?] [/h] [/?] [-x] [-a|--add|-d|--delete] ");
console.log("-h -? /h /? --help -- Displays help");
console.log("-a --add -- Add an user");
console.log("-d --delete -- Deletes an user");
+ console.log("-x -- Changes hash algorithm");
+ process.exit(1);
+ }
+ forcechange = true;
+ } else {
+ if (user != "") {
+ console.log("Multiple users specified.");
+ console.log("node svrpasswd.js [-h] [--help] [-?] [/h] [/?] [-x] [-a|--add|-d|--delete] ");
+ console.log("-h -? /h /? --help -- Displays help");
+ console.log("-a --add -- Add an user");
+ console.log("-d --delete -- Deletes an user");
+ console.log("-x -- Changes hash algorithm");
process.exit(1);
}
user = args[i];
@@ -240,10 +256,11 @@ for (var i = (process.argv[0].indexOf("node") > -1 || process.argv[0].indexOf("b
if (user == "") {
console.log("No user specified.");
- console.log("node svrpasswd.js [-h] [--help] [-?] [/h] [/?] [-a|--add|-d|--delete] ");
+ console.log("node svrpasswd.js [-h] [--help] [-?] [/h] [/?] [-x] [-a|--add|-d|--delete] ");
console.log("-h -? /h /? --help -- Displays help");
console.log("-a --add -- Add an user");
console.log("-d --delete -- Deletes an user");
+ console.log("-x -- Changes hash algorithm");
process.exit(1);
}
@@ -277,28 +294,72 @@ function password(callback) {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
- prompt: 'Password: ',
- terminal: false
+ prompt: 'Password: '
});
rl.prompt();
- rl.once('line', (line) => {
- //rl.close();
+ process.stdout.writeold = process.stdout.write;
+ process.stdout.write = function (s) {
+ process.stdout.writeold(s.replace(/[^\r\n]/g, ""));
+ };
+ rl.once('line', function (line) {
+ process.stdout.write = process.stdout.writeold;
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: 'Confirm password: ',
- terminal: false
});
rl.prompt();
- rl.on('line', (line2) => {
+ process.stdout.writeold = process.stdout.write;
+ process.stdout.write = function (s) {
+ process.stdout.writeold(s.replace(/[^\r\n]/g, ""));
+ };
+ rl.on('line', function (line2) {
+ process.stdout.write = process.stdout.writeold;
rl.close();
if (line != line2) callback(false);
else callback(line);
-
});
});
}
+function promptAlgorithms(callback, bypass, pbkdf2, scrypt) {
+ if (bypass) {
+ if (scrypt) {
+ callback("scrypt");
+ } else if(pbkdf2) {
+ callback("pbkdf2");
+ } else {
+ callback("sha256");
+ }
+ return;
+ }
+ var algorithms = {
+ sha256: "Salted SHA256 (1 iteration) - fastest and uses least memory, but less secure",
+ pbkdf2: "PBKDF2 (PBKDF2-HMAC-SHA512, 36250 iterations) - more secure and uses less memory, but slower",
+ scrypt: "scrypt (N=2^14, r=8, p=1) - faster and more secure, but uses more memory"
+ }
+ if (!crypto.scrypt || process.isBun) delete algorithms.scrypt;
+ if (!crypto.pbkdf2 || process.isBun) delete algorithms.pbkdf2;
+ var algorithmNames = Object.keys(algorithms);
+ if (algorithmNames.length < 2) callback(algorithmNames[0]);
+ console.log("Select password hashing algorithm. Available algorithms:");
+ for (var i = 0; i < algorithmNames.length; i++) {
+ console.log(algorithmNames[i] + " - " + algorithms[algorithmNames[i]]);
+ }
+ var rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout,
+ prompt: 'Algorithm: '
+ });
+ rl.prompt();
+ rl.on('line', function (line) {
+ rl.close();
+ line = line.trim();
+ if (!algorithms[line]) callback(false);
+ else callback(line);
+ });
+}
+
var userindex = getUserIndex(user);
if (action == "add" && userindex != -1) {
console.log("User alerady exists.");
@@ -312,35 +373,71 @@ if (action == "delete") {
saveConfig();
console.log("User deleted successfully");
} else if (action == "add") {
- password(function(password) {
- if (!password) {
- console.log("Passwords don't match!");
+ promptAlgorithms(function (algorithm) {
+ if (!algorithm) {
+ console.log("Invalid algorithm!");
process.exit(1);
} else {
- var salt = generateSalt()
- users.push({
- name: user,
- pass: sha256(password + salt),
- salt: salt
+ password(function (password) {
+ if (!password) {
+ console.log("Passwords don't match!");
+ process.exit(1);
+ } else {
+ var salt = generateSalt();
+ var hash = "";
+ if (algorithm == "scrypt") {
+ hash = crypto.scryptSync(password, salt, 64).toString("hex");
+ } else if (algorithm == "pbkdf2") {
+ hash = crypto.pbkdf2Sync(password, salt, 36250, 64, "sha512").toString("hex");
+ } else {
+ hash = sha256(password + salt);
+ }
+ users.push({
+ name: user,
+ pass: hash,
+ salt: salt,
+ pbkdf2: (algorithm == "pbkdf2" ? true : undefined),
+ scrypt: (algorithm == "scrypt" ? true : undefined),
+ __svrpasswd_l2: true
+ });
+ saveConfig();
+ console.log("User added successfully");
+ }
});
- saveConfig();
- console.log("User added successfully");
}
});
} else {
- password(function(password) {
- if (!password) {
- console.log("Passwords don't match!");
+ promptAlgorithms(function (algorithm) {
+ if (!algorithm) {
+ console.log("Invalid algorithm!");
process.exit(1);
} else {
- var salt = generateSalt()
- users[userindex] = {
- name: user,
- pass: sha256(password + salt),
- salt: salt
- };
- saveConfig();
- console.log("Password changed successfully");
+ password(function (password) {
+ if (!password) {
+ console.log("Passwords don't match!");
+ process.exit(1);
+ } else {
+ var salt = generateSalt();
+ var hash = "";
+ if (algorithm == "scrypt") {
+ hash = crypto.scryptSync(password, salt, 64).toString("hex");
+ } else if (algorithm == "pbkdf2") {
+ hash = crypto.pbkdf2Sync(password, salt, 36250, 64, "sha512").toString("hex");
+ } else {
+ hash = sha256(password + salt);
+ }
+ users[userindex] = {
+ name: user,
+ pass: hash,
+ salt: salt,
+ pbkdf2: (algorithm == "pbkdf2" ? true : undefined),
+ scrypt: (algorithm == "scrypt" ? true : undefined),
+ __svrpasswd_l2: true
+ };
+ saveConfig();
+ console.log("Password changed successfully");
+ }
+ });
}
- });
+ }, (users[userindex].__svrpasswd_l2 && !forcechange), users[userindex].pbkdf2, users[userindex].scrypt);
}
diff --git a/tests.html b/tests.html
index 0351e6b..9a40d27 100644
--- a/tests.html
+++ b/tests.html
@@ -1,7 +1,7 @@
- SVR.JS 3.6.4 Tests
+ SVR.JS 3.7.0 Tests
-
SVR.JS 3.6.4 Tests
+
SVR.JS 3.7.0 Tests
Directory
Directory (with query)
diff --git a/views.txt b/views.txt
index 573541a..56a6051 100644
--- a/views.txt
+++ b/views.txt
@@ -1 +1 @@
-0
+1
\ No newline at end of file