2024-08-23 19:58:15 +02:00
|
|
|
const http = require("http");
|
|
|
|
const fs = require("fs");
|
2024-08-24 19:41:13 +02:00
|
|
|
const generateServerString = require("./utils/generateServerString.js");
|
2024-08-24 19:47:48 +02:00
|
|
|
const deleteFolderRecursive = require("./utils/deleteFolderRecursive.js");
|
2024-08-24 19:41:13 +02:00
|
|
|
const svrjsInfo = require("../svrjs.json");
|
2024-08-25 13:09:58 +02:00
|
|
|
const { name, version } = svrjsInfo;
|
2024-08-23 19:58:15 +02:00
|
|
|
|
2024-08-23 21:58:26 +02:00
|
|
|
let inspector = undefined;
|
|
|
|
try {
|
|
|
|
inspector = require("inspector");
|
|
|
|
} catch (err) {
|
|
|
|
// Don't use inspector
|
|
|
|
}
|
|
|
|
|
2024-08-25 15:40:53 +02:00
|
|
|
let tar = {};
|
|
|
|
try {
|
|
|
|
tar = require("tar");
|
|
|
|
} catch (err) {
|
|
|
|
tar = {
|
|
|
|
_errored: err,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-08-24 19:29:12 +02:00
|
|
|
process.dirname = __dirname;
|
2024-08-25 07:13:41 +02:00
|
|
|
process.filename = __filename;
|
2024-08-24 19:29:12 +02:00
|
|
|
|
2024-08-25 15:50:56 +02:00
|
|
|
let hexstrbase64 = undefined;
|
|
|
|
try {
|
|
|
|
hexstrbase64 = require(process.dirname + "/hexstrbase64/index.js");
|
|
|
|
} catch (err) {
|
|
|
|
// Don't use hexstrbase64
|
|
|
|
}
|
|
|
|
|
2024-08-24 19:41:13 +02:00
|
|
|
// TODO: after implementing clustering in new SVR.JS
|
|
|
|
//process.singleThreaded = false;
|
|
|
|
process.singleThreaded = true;
|
|
|
|
|
2024-08-25 09:44:53 +02:00
|
|
|
process.err4xxcounter = 0;
|
|
|
|
process.err5xxcounter = 0;
|
|
|
|
process.reqcounter = 0;
|
|
|
|
process.malformedcounter = 0;
|
|
|
|
|
2024-08-24 19:41:13 +02:00
|
|
|
if (process.versions) process.versions.svrjs = version; // Inject SVR.JS into process.versions
|
|
|
|
|
2024-08-25 16:23:16 +02:00
|
|
|
let exiting = false;
|
2024-08-24 19:41:13 +02:00
|
|
|
let forceSecure = false;
|
|
|
|
let disableMods = false;
|
|
|
|
|
2024-08-24 19:47:48 +02:00
|
|
|
// Handle command line arguments
|
2024-08-24 19:41:13 +02:00
|
|
|
const args = process.argv;
|
2024-08-25 11:32:03 +02:00
|
|
|
for (
|
|
|
|
let 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] == "/?"
|
|
|
|
) {
|
2024-08-25 13:09:58 +02:00
|
|
|
console.log(name + " usage:");
|
2024-08-25 11:32:03 +02:00
|
|
|
console.log(
|
|
|
|
"node svr.js [-h] [--help] [-?] [/h] [/?] [--secure] [--reset] [--clean] [--disable-mods] [--single-threaded] [-v] [--version]",
|
|
|
|
);
|
2024-08-24 19:41:13 +02:00
|
|
|
console.log("-h -? /h /? --help -- Displays help");
|
2024-08-25 13:09:58 +02:00
|
|
|
console.log("--clean -- Cleans up files created by " + name);
|
2024-08-25 11:32:03 +02:00
|
|
|
console.log(
|
2024-08-25 13:10:28 +02:00
|
|
|
"--reset -- Resets " +
|
|
|
|
name +
|
|
|
|
" to default settings (WARNING: DANGEROUS)",
|
2024-08-25 11:32:03 +02:00
|
|
|
);
|
2024-08-24 19:41:13 +02:00
|
|
|
console.log("--secure -- Runs HTTPS server");
|
|
|
|
console.log("--disable-mods -- Disables mods (safe mode)");
|
|
|
|
console.log("--single-threaded -- Run single-threaded");
|
|
|
|
console.log("-v --version -- Display server version");
|
|
|
|
process.exit(0);
|
|
|
|
} else if (args[i] == "--secure") {
|
|
|
|
forceSecure = true;
|
|
|
|
} else if (args[i] == "-v" || args[i] == "--version") {
|
|
|
|
console.log(generateServerString(true));
|
|
|
|
process.exit(0);
|
|
|
|
} else if (args[i] == "--clean") {
|
|
|
|
console.log("Removing logs...");
|
|
|
|
deleteFolderRecursive(process.dirname + "/log");
|
|
|
|
fs.mkdirSync(process.dirname + "/log");
|
|
|
|
console.log("Removing temp folder...");
|
|
|
|
deleteFolderRecursive(process.dirname + "/temp");
|
|
|
|
fs.mkdirSync(process.dirname + "/temp");
|
|
|
|
console.log("Done!");
|
|
|
|
process.exit(0);
|
|
|
|
} else if (args[i] == "--reset") {
|
|
|
|
console.log("Removing logs...");
|
|
|
|
deleteFolderRecursive(process.dirname + "/log");
|
|
|
|
fs.mkdirSync(process.dirname + "/log");
|
|
|
|
console.log("Removing temp folder...");
|
|
|
|
deleteFolderRecursive(process.dirname + "/temp");
|
|
|
|
fs.mkdirSync(process.dirname + "/temp");
|
|
|
|
console.log("Removing configuration file...");
|
2024-08-24 19:49:36 +02:00
|
|
|
fs.unlinkSync(process.dirname + "/config.json");
|
2024-08-24 19:41:13 +02:00
|
|
|
console.log("Done!");
|
|
|
|
process.exit(0);
|
|
|
|
} else if (args[i] == "--disable-mods") {
|
|
|
|
disableMods = true;
|
|
|
|
} else if (args[i] == "--single-threaded") {
|
|
|
|
process.singlethreaded = true;
|
|
|
|
} else {
|
|
|
|
console.log("Unrecognized argument: " + args[i]);
|
2024-08-25 13:09:58 +02:00
|
|
|
console.log(name + " usage:");
|
2024-08-25 11:32:03 +02:00
|
|
|
console.log(
|
|
|
|
"node svr.js [-h] [--help] [-?] [/h] [/?] [--secure] [--reset] [--clean] [--disable-mods] [--single-threaded] [-v] [--version]",
|
|
|
|
);
|
2024-08-24 19:41:13 +02:00
|
|
|
console.log("-h -? /h /? --help -- Displays help");
|
2024-08-25 13:09:58 +02:00
|
|
|
console.log("--clean -- Cleans up files created by " + name);
|
2024-08-25 11:32:03 +02:00
|
|
|
console.log(
|
2024-08-25 13:10:28 +02:00
|
|
|
"--reset -- Resets " +
|
|
|
|
name +
|
|
|
|
" to default settings (WARNING: DANGEROUS)",
|
2024-08-25 11:32:03 +02:00
|
|
|
);
|
2024-08-24 19:41:13 +02:00
|
|
|
console.log("--secure -- Runs HTTPS server");
|
|
|
|
console.log("--disable-mods -- Disables mods (safe mode)");
|
|
|
|
console.log("--single-threaded -- Run single-threaded");
|
|
|
|
console.log("-v --version -- Display server version");
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-23 19:58:15 +02:00
|
|
|
// Create log, mods and temp directories, if they don't exist.
|
2024-08-25 11:32:03 +02:00
|
|
|
if (!fs.existsSync(process.dirname + "/log"))
|
|
|
|
fs.mkdirSync(process.dirname + "/log");
|
|
|
|
if (!fs.existsSync(process.dirname + "/mods"))
|
|
|
|
fs.mkdirSync(process.dirname + "/mods");
|
|
|
|
if (!fs.existsSync(process.dirname + "/temp"))
|
|
|
|
fs.mkdirSync(process.dirname + "/temp");
|
2024-08-23 19:58:15 +02:00
|
|
|
|
2024-08-24 16:54:28 +02:00
|
|
|
const cluster = require("./utils/clusterBunShim.js"); // Cluster module with shim for Bun
|
2024-08-25 15:40:53 +02:00
|
|
|
const legacyModWrapper = require("./utils/legacyModWrapper.js");
|
2024-08-25 16:23:16 +02:00
|
|
|
const generateErrorStack = require("./utils/generateErrorStack.js");
|
2024-08-25 11:47:43 +02:00
|
|
|
//const serverHTTPErrorDescs = require("../res/httpErrorDescriptions.js");
|
|
|
|
//const getOS = require("./utils/getOS.js");
|
2024-08-24 19:30:25 +02:00
|
|
|
//const parseURL = require("./utils/urlParser.js");
|
|
|
|
//const fixNodeMojibakeURL = require("./utils/urlMojibakeFixer.js");
|
2024-08-24 16:54:28 +02:00
|
|
|
|
2024-08-24 16:55:44 +02:00
|
|
|
process.serverConfig = {};
|
2024-08-25 09:12:39 +02:00
|
|
|
let configJSONRErr = undefined;
|
|
|
|
let configJSONPErr = undefined;
|
|
|
|
if (fs.existsSync(__dirname + "/config.json")) {
|
|
|
|
let configJSONf = "";
|
|
|
|
try {
|
|
|
|
configJSONf = fs.readFileSync(__dirname + "/config.json"); // Read JSON File
|
|
|
|
try {
|
|
|
|
process.serverConfig = JSON.parse(configJSONf); // Parse JSON
|
|
|
|
} catch (err2) {
|
|
|
|
configJSONPErr = err2;
|
|
|
|
}
|
|
|
|
} catch (err) {
|
2024-08-25 11:57:45 +02:00
|
|
|
configJSONRErr = err;
|
2024-08-25 09:12:39 +02:00
|
|
|
}
|
|
|
|
}
|
2024-08-24 16:55:44 +02:00
|
|
|
|
|
|
|
// TODO: configuration from config.json
|
|
|
|
if (process.serverConfig.users === undefined) process.serverConfig.users = [];
|
2024-08-25 11:32:03 +02:00
|
|
|
if (process.serverConfig.secure === undefined)
|
|
|
|
process.serverConfig.secure = false;
|
2024-08-24 19:41:13 +02:00
|
|
|
if (forceSecure) process.serverConfig.secure = true;
|
2024-08-24 16:55:44 +02:00
|
|
|
if (process.serverConfig.secure) {
|
2024-08-25 11:32:03 +02:00
|
|
|
if (process.serverConfig.key === undefined)
|
|
|
|
process.serverConfig.key = "cert/key.key";
|
|
|
|
if (process.serverConfig.cert === undefined)
|
|
|
|
process.serverConfig.cert = "cert/cert.crt";
|
|
|
|
if (process.serverConfig.sport === undefined)
|
|
|
|
process.serverConfig.sport = 443;
|
|
|
|
if (process.serverConfig.spubport === undefined)
|
|
|
|
process.serverConfig.spubport = 443;
|
2024-08-24 16:55:44 +02:00
|
|
|
if (process.serverConfig.sni === undefined) process.serverConfig.sni = {};
|
2024-08-25 11:32:03 +02:00
|
|
|
if (process.serverConfig.enableOCSPStapling === undefined)
|
|
|
|
process.serverConfig.enableOCSPStapling = false;
|
2024-08-24 16:55:44 +02:00
|
|
|
}
|
|
|
|
if (process.serverConfig.port === undefined) process.serverConfig.port = 80;
|
2024-08-25 11:32:03 +02:00
|
|
|
if (process.serverConfig.pubport === undefined)
|
|
|
|
process.serverConfig.pubport = 80;
|
|
|
|
if (
|
|
|
|
process.serverConfig.domain === undefined &&
|
|
|
|
process.serverConfig.domian !== undefined
|
|
|
|
)
|
|
|
|
process.serverConfig.domain = process.serverConfig.domian;
|
2024-08-24 16:55:44 +02:00
|
|
|
delete process.serverConfig.domian;
|
2024-08-25 11:32:03 +02:00
|
|
|
if (process.serverConfig.page404 === undefined)
|
|
|
|
process.serverConfig.page404 = "404.html";
|
2024-08-25 08:32:49 +02:00
|
|
|
process.serverConfig.timestamp = new Date().getTime();
|
2024-08-25 11:32:03 +02:00
|
|
|
if (process.serverConfig.blacklist === undefined)
|
|
|
|
process.serverConfig.blacklist = [];
|
|
|
|
if (process.serverConfig.nonStandardCodes === undefined)
|
|
|
|
process.serverConfig.nonStandardCodes = [];
|
|
|
|
if (process.serverConfig.enableCompression === undefined)
|
|
|
|
process.serverConfig.enableCompression = true;
|
|
|
|
if (process.serverConfig.customHeaders === undefined)
|
|
|
|
process.serverConfig.customHeaders = {};
|
|
|
|
if (process.serverConfig.enableHTTP2 === undefined)
|
|
|
|
process.serverConfig.enableHTTP2 = false;
|
|
|
|
if (process.serverConfig.enableLogging === undefined)
|
|
|
|
process.serverConfig.enableLogging = true;
|
|
|
|
if (process.serverConfig.enableDirectoryListing === undefined)
|
|
|
|
process.serverConfig.enableDirectoryListing = true;
|
|
|
|
if (process.serverConfig.enableDirectoryListingWithDefaultHead === undefined)
|
|
|
|
process.serverConfig.enableDirectoryListingWithDefaultHead = false;
|
|
|
|
if (process.serverConfig.serverAdministratorEmail === undefined)
|
|
|
|
process.serverConfig.serverAdministratorEmail = "[no contact information]";
|
|
|
|
if (process.serverConfig.stackHidden === undefined)
|
|
|
|
process.serverConfig.stackHidden = false;
|
|
|
|
if (process.serverConfig.enableRemoteLogBrowsing === undefined)
|
|
|
|
process.serverConfig.enableRemoteLogBrowsing = false;
|
|
|
|
if (process.serverConfig.exposeServerVersion === undefined)
|
|
|
|
process.serverConfig.exposeServerVersion = true;
|
|
|
|
if (process.serverConfig.disableServerSideScriptExpose === undefined)
|
|
|
|
process.serverConfig.disableServerSideScriptExpose = true;
|
|
|
|
if (process.serverConfig.allowStatus === undefined)
|
|
|
|
process.serverConfig.allowStatus = true;
|
|
|
|
if (process.serverConfig.rewriteMap === undefined)
|
|
|
|
process.serverConfig.rewriteMap = [];
|
|
|
|
if (process.serverConfig.dontCompress === undefined)
|
|
|
|
process.serverConfig.dontCompress = [
|
|
|
|
"/.*\\.ipxe$/",
|
|
|
|
"/.*\\.(?:jpe?g|png|bmp|tiff|jfif|gif|webp)$/",
|
|
|
|
"/.*\\.(?:[id]mg|iso|flp)$/",
|
|
|
|
"/.*\\.(?:zip|rar|bz2|[gb7x]z|lzma|tar)$/",
|
|
|
|
"/.*\\.(?:mp[34]|mov|wm[av]|avi|webm|og[gv]|mk[va])$/",
|
|
|
|
];
|
|
|
|
if (process.serverConfig.enableIPSpoofing === undefined)
|
|
|
|
process.serverConfig.enableIPSpoofing = false;
|
|
|
|
if (process.serverConfig.disableNonEncryptedServer === undefined)
|
|
|
|
process.serverConfig.disableNonEncryptedServer = false;
|
|
|
|
if (process.serverConfig.disableToHTTPSRedirect === undefined)
|
|
|
|
process.serverConfig.disableToHTTPSRedirect = false;
|
|
|
|
if (process.serverConfig.enableETag === undefined)
|
|
|
|
process.serverConfig.enableETag = true;
|
|
|
|
if (process.serverConfig.disableUnusedWorkerTermination === undefined)
|
|
|
|
process.serverConfig.disableUnusedWorkerTermination = false;
|
|
|
|
if (process.serverConfig.rewriteDirtyURLs === undefined)
|
|
|
|
process.serverConfig.rewriteDirtyURLs = false;
|
|
|
|
if (process.serverConfig.errorPages === undefined)
|
|
|
|
process.serverConfig.errorPages = [];
|
|
|
|
if (process.serverConfig.useWebRootServerSideScript === undefined)
|
|
|
|
process.serverConfig.useWebRootServerSideScript = true;
|
|
|
|
if (process.serverConfig.exposeModsInErrorPages === undefined)
|
|
|
|
process.serverConfig.exposeModsInErrorPages = true;
|
|
|
|
if (process.serverConfig.disableTrailingSlashRedirects === undefined)
|
|
|
|
process.serverConfig.disableTrailingSlashRedirects = false;
|
|
|
|
if (process.serverConfig.environmentVariables === undefined)
|
|
|
|
process.serverConfig.environmentVariables = {};
|
|
|
|
if (process.serverConfig.customHeadersVHost === undefined)
|
|
|
|
process.serverConfig.customHeadersVHost = [];
|
|
|
|
if (process.serverConfig.enableDirectoryListingVHost === undefined)
|
|
|
|
process.serverConfig.enableDirectoryListingVHost = [];
|
|
|
|
if (process.serverConfig.wwwrootPostfixesVHost === undefined)
|
|
|
|
process.serverConfig.wwwrootPostfixesVHost = [];
|
|
|
|
if (process.serverConfig.wwwrootPostfixPrefixesVHost === undefined)
|
|
|
|
process.serverConfig.wwwrootPostfixPrefixesVHost = [];
|
|
|
|
if (process.serverConfig.allowDoubleSlashes === undefined)
|
|
|
|
process.serverConfig.allowDoubleSlashes = false;
|
|
|
|
if (process.serverConfig.allowPostfixDoubleSlashes === undefined)
|
|
|
|
process.serverConfig.allowPostfixDoubleSlashes = false;
|
|
|
|
if (process.serverConfig.optOutOfStatisticsServer === undefined)
|
|
|
|
process.serverConfig.optOutOfStatisticsServer = false;
|
2024-08-24 16:55:44 +02:00
|
|
|
|
|
|
|
process.serverConfig.version = version; // Compatiblity for very old SVR.JS mods
|
|
|
|
|
2024-08-24 16:58:27 +02:00
|
|
|
const serverconsole = require("./utils/serverconsole.js");
|
2024-08-23 19:58:15 +02:00
|
|
|
|
2024-08-23 21:58:26 +02:00
|
|
|
let inspectorURL = undefined;
|
|
|
|
try {
|
|
|
|
if (inspector) {
|
|
|
|
inspectorURL = inspector.url();
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
// Failed to get inspector URL
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!process.stdout.isTTY && !inspectorURL) {
|
|
|
|
// When stdout is not a terminal and not attached to an Node.JS inspector, disable it to improve performance of SVR.JS
|
|
|
|
console.log = function () {};
|
|
|
|
process.stdout.write = function () {};
|
|
|
|
process.stdout._write = function () {};
|
|
|
|
process.stdout._writev = function () {};
|
|
|
|
}
|
|
|
|
|
2024-08-25 11:32:03 +02:00
|
|
|
let wwwrootError = null;
|
2024-08-23 21:33:26 +02:00
|
|
|
try {
|
2024-08-25 11:32:03 +02:00
|
|
|
if (cluster.isPrimary || cluster.isPrimary === undefined)
|
|
|
|
process.chdir(
|
|
|
|
process.serverConfig.wwwroot != undefined
|
|
|
|
? process.serverConfig.wwwroot
|
|
|
|
: process.dirname,
|
|
|
|
);
|
2024-08-23 21:33:26 +02:00
|
|
|
} catch (err) {
|
|
|
|
wwwrootError = err;
|
|
|
|
}
|
2024-08-23 20:43:09 +02:00
|
|
|
|
2024-08-25 14:02:45 +02:00
|
|
|
let mods = [];
|
|
|
|
const modFiles = fs.readdirSync(__dirname + "/mods").sort();
|
|
|
|
let modInfos = [];
|
|
|
|
let modLoadingErrors = [];
|
2024-08-25 15:47:12 +02:00
|
|
|
let SSJSError = undefined;
|
2024-08-25 14:02:45 +02:00
|
|
|
|
|
|
|
if (!disableMods) {
|
|
|
|
// Iterate through the list of mod files
|
|
|
|
modFiles.forEach((modFileRaw) => {
|
|
|
|
// Build the path to the current mod file
|
|
|
|
const modFile = process.dirname + "/mods/" + modFileRaw;
|
|
|
|
|
|
|
|
// Check if the current mod file is a regular file
|
|
|
|
if (fs.statSync(modFile).isFile()) {
|
|
|
|
if (modFile.indexOf(".js") == modFile.length - 3) {
|
|
|
|
try {
|
|
|
|
const mod = require(modFile);
|
|
|
|
mods.push(mod);
|
|
|
|
if (mod.modInfo) modInfos.push(mod.modInfo);
|
|
|
|
else {
|
|
|
|
modInfos.push({
|
|
|
|
name:
|
|
|
|
"Unknown mod (" +
|
|
|
|
modFileRaw +
|
|
|
|
"; module.exports.modInfo not set)",
|
|
|
|
version: "ERROR",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
modLoadingErrors.push({
|
|
|
|
error: err,
|
|
|
|
modName: modFileRaw,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
2024-08-25 15:40:53 +02:00
|
|
|
try {
|
|
|
|
// Define the modloader folder name
|
|
|
|
let modloaderFolderName = "modloader";
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine if the mod file is a ".tar.gz" file or not
|
|
|
|
if (modFile.indexOf(".tar.gz") == modFile.length - 7) {
|
|
|
|
// If it's a ".tar.gz" file, extract its contents using `tar`
|
|
|
|
if (tar._errored) throw tar._errored;
|
|
|
|
tar.x({
|
|
|
|
file: modFile,
|
|
|
|
sync: true,
|
|
|
|
C:
|
|
|
|
process.dirname +
|
|
|
|
"/temp/" +
|
|
|
|
modloaderFolderName +
|
|
|
|
"/" +
|
|
|
|
modFileRaw,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// If it's not a ".tar.gz" file, throw an error about `svrmodpack` support being dropped
|
|
|
|
throw new Error(
|
|
|
|
"This version of " +
|
|
|
|
name +
|
|
|
|
' no longer supports "svrmodpack" library for SVR.JS mods. Please consider using newer mods with .tar.gz format.',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the mod to the mods list
|
|
|
|
mods.push(
|
|
|
|
legacyModWrapper(
|
|
|
|
require(
|
|
|
|
process.dirname +
|
|
|
|
"/temp/" +
|
|
|
|
modloaderFolderName +
|
|
|
|
"/" +
|
|
|
|
modFileRaw +
|
|
|
|
"/index.js",
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Read the mod's info file
|
|
|
|
try {
|
|
|
|
modInfos.push(
|
|
|
|
JSON.parse(
|
|
|
|
fs.readFileSync(
|
|
|
|
process.dirname +
|
|
|
|
"/temp/" +
|
|
|
|
modloaderFolderName +
|
|
|
|
"/" +
|
|
|
|
modFileRaw +
|
|
|
|
"/mod.info",
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
} catch (err) {
|
|
|
|
// If failed to read info file, add a placeholder entry to modInfos with an error message
|
|
|
|
modInfos.push({
|
|
|
|
name: "Unknown mod (" + modFileRaw + ";" + err.message + ")",
|
|
|
|
version: "ERROR",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
modLoadingErrors.push({
|
|
|
|
error: err,
|
|
|
|
modName: modFileRaw,
|
|
|
|
});
|
|
|
|
}
|
2024-08-25 14:02:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2024-08-25 15:47:12 +02:00
|
|
|
|
|
|
|
// Define the temporary server-side JavaScript file name
|
|
|
|
let tempServerSideScriptName = "serverSideScript.js";
|
2024-08-25 15:50:56 +02:00
|
|
|
if (
|
|
|
|
!(
|
|
|
|
process.isBun &&
|
|
|
|
process.versions.bun &&
|
|
|
|
process.versions.bun[0] == "0"
|
|
|
|
) &&
|
|
|
|
cluster.isPrimary === false
|
|
|
|
) {
|
2024-08-25 15:47:12 +02:00
|
|
|
// If not the master process and it's not Bun, create a unique temporary server-side JavaScript file name for each worker
|
2024-08-25 15:50:56 +02:00
|
|
|
tempServerSideScriptName =
|
|
|
|
".serverSideScript_w" + Math.floor(Math.random() * 65536) + ".js";
|
2024-08-25 15:47:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Determine path of server-side script file
|
|
|
|
let SSJSPath = "./serverSideScript.js";
|
2024-08-25 15:50:56 +02:00
|
|
|
if (!process.serverConfig.useWebRootServerSideScript)
|
|
|
|
SSJSPath = process.dirname + "/serverSideScript.js";
|
2024-08-25 15:47:12 +02:00
|
|
|
|
|
|
|
// Check if a custom server side script file exists
|
|
|
|
if (fs.existsSync(SSJSPath) && fs.statSync(SSJSPath).isFile()) {
|
|
|
|
try {
|
|
|
|
// Prepend necessary modules and variables to the custom server side script
|
2024-08-25 15:50:56 +02:00
|
|
|
const modhead =
|
|
|
|
"var readline = require('readline');\r\nvar os = require('os');\r\nvar http = require('http');\r\nvar url = require('url');\r\nvar fs = require('fs');\r\nvar path = require('path');\r\n" +
|
|
|
|
(hexstrbase64 === undefined
|
|
|
|
? ""
|
|
|
|
: "var hexstrbase64 = require('../hexstrbase64/index.js');\r\n") +
|
|
|
|
(crypto.__disabled__ === undefined
|
|
|
|
? "var crypto = require('crypto');\r\nvar https = require('https');\r\n"
|
|
|
|
: "") +
|
|
|
|
'var stream = require(\'stream\');\r\nvar customvar1;\r\nvar customvar2;\r\nvar customvar3;\r\nvar customvar4;\r\n\r\nfunction Mod() {}\r\nMod.prototype.callback = function callback(req, res, serverconsole, responseEnd, href, ext, uobject, search, defaultpage, users, page404, head, foot, fd, elseCallback, configJSON, callServerError, getCustomHeaders, origHref, redirect, parsePostData, authUser) {\r\nreturn function () {\r\nvar disableEndElseCallbackExecute = false;\r\nfunction filterHeaders(e){var r={};return Object.keys(e).forEach((function(t){null!==e[t]&&void 0!==e[t]&&("object"==typeof e[t]?r[t]=JSON.parse(JSON.stringify(e[t])):r[t]=e[t])})),r}\r\nfunction checkHostname(e){if(void 0===e||"*"==e)return!0;if(req.headers.host&&0==e.indexOf("*.")&&"*."!=e){var r=e.substring(2);if(req.headers.host==r||req.headers.host.indexOf("."+r)==req.headers.host.length-r.length-1)return!0}else if(req.headers.host&&req.headers.host==e)return!0;return!1}\r\nfunction checkHref(e){return href==e||"win32"==os.platform()&&href.toLowerCase()==e.toLowerCase()}\r\n';
|
|
|
|
const modfoot =
|
|
|
|
"\r\nif(!disableEndElseCallbackExecute) {\r\ntry{\r\nelseCallback();\r\n} catch(err) {\r\n}\r\n}\r\n}\r\n}\r\nmodule.exports = Mod;";
|
2024-08-25 15:47:12 +02:00
|
|
|
// Write the modified server side script to the temp folder
|
2024-08-25 15:50:56 +02:00
|
|
|
fs.writeFileSync(
|
|
|
|
process.dirname + "/temp/" + tempServerSideScriptName,
|
|
|
|
modhead + fs.readFileSync(SSJSPath) + modfoot,
|
|
|
|
);
|
2024-08-25 15:47:12 +02:00
|
|
|
|
|
|
|
// Add the server side script to the mods list
|
2024-08-25 15:50:56 +02:00
|
|
|
mods.push(
|
|
|
|
legacyModWrapper(
|
|
|
|
require(process.dirname + "/temp/" + tempServerSideScriptName),
|
|
|
|
),
|
|
|
|
);
|
2024-08-25 15:47:12 +02:00
|
|
|
} catch (err) {
|
|
|
|
SSJSError = err;
|
|
|
|
}
|
|
|
|
}
|
2024-08-25 14:02:45 +02:00
|
|
|
}
|
|
|
|
|
2024-08-25 16:47:26 +02:00
|
|
|
// Middleware
|
2024-08-23 20:43:09 +02:00
|
|
|
let middleware = [
|
2024-08-23 22:13:58 +02:00
|
|
|
require("./middleware/urlSanitizer.js"),
|
2024-08-24 08:02:11 +02:00
|
|
|
require("./middleware/redirects.js"),
|
2024-08-25 09:12:39 +02:00
|
|
|
require("./middleware/blocklist.js"),
|
2024-08-24 08:22:49 +02:00
|
|
|
require("./middleware/webRootPostfixes.js"),
|
2024-08-24 17:32:27 +02:00
|
|
|
require("./middleware/rewriteURL.js"),
|
2024-08-24 17:44:25 +02:00
|
|
|
require("./middleware/responseHeaders.js"),
|
2024-08-24 20:32:06 +02:00
|
|
|
require("./middleware/checkForbiddenPaths.js"),
|
2024-08-24 20:40:28 +02:00
|
|
|
require("./middleware/nonStandardCodesAndHttpAuthentication.js"),
|
2024-08-25 09:44:53 +02:00
|
|
|
require("./middleware/redirectTrailingSlashes.js"),
|
2024-08-25 14:24:18 +02:00
|
|
|
...mods, // Load SVR.JS mods as middleware
|
2024-08-25 09:44:53 +02:00
|
|
|
require("./middleware/defaultHandlerChecks.js"),
|
2024-08-25 10:23:37 +02:00
|
|
|
require("./middleware/status.js"),
|
2024-08-25 11:32:03 +02:00
|
|
|
require("./middleware/staticFileServingAndDirectoryListings.js"),
|
2024-08-23 20:43:09 +02:00
|
|
|
];
|
|
|
|
|
2024-08-25 16:51:25 +02:00
|
|
|
// HTTP server handlers
|
|
|
|
const requestHandler = require("./handlers/requestHandler.js")(
|
|
|
|
serverconsole,
|
|
|
|
middleware,
|
|
|
|
);
|
|
|
|
|
|
|
|
const proxyHandler = require("./handlers/proxyHandler.js")(
|
|
|
|
serverconsole,
|
|
|
|
middleware,
|
|
|
|
);
|
|
|
|
|
|
|
|
const clientErrorHandler = require("./handlers/clientErrorHandler.js")(
|
|
|
|
serverconsole,
|
|
|
|
);
|
|
|
|
|
|
|
|
// Create HTTP server
|
|
|
|
const server = http
|
|
|
|
.createServer(requestHandler)
|
|
|
|
.on("connect", proxyHandler)
|
|
|
|
.on("clientError", clientErrorHandler);
|
|
|
|
|
2024-08-25 16:47:26 +02:00
|
|
|
// TODO: close, open, stop, restart commands
|
|
|
|
// Base commands
|
|
|
|
let commands = {
|
|
|
|
help: (args, log) => {
|
|
|
|
log("Server commands:\n" + Object.keys(commands).join(" "));
|
|
|
|
},
|
|
|
|
mods: function (args, log) {
|
|
|
|
log("Mods:");
|
|
|
|
for (let i = 0; i < modInfos.length; i++) {
|
|
|
|
log(
|
|
|
|
(i + 1).toString() +
|
|
|
|
". " +
|
|
|
|
modInfos[i].name +
|
|
|
|
" " +
|
|
|
|
modInfos[i].version,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (modInfos.length == 0) {
|
|
|
|
log("No mods installed.");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
clear: function (args, log) {
|
|
|
|
console.clear();
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
// Load commands from middleware
|
|
|
|
middleware.forEach((middlewareO) => {
|
|
|
|
if (middlewareO.commands) {
|
|
|
|
Object.keys(middlewareO.commands).forEach((command) => {
|
|
|
|
if (commands[command]) {
|
|
|
|
commands[command] = (args, log) => {
|
|
|
|
middlewareO.commands(args, log, commands[command]);
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
commands[command] = (args, log) => {
|
|
|
|
middlewareO.commands(args, log, () => {});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-08-25 16:51:25 +02:00
|
|
|
// TODO: HTTP ports
|
|
|
|
// Listen HTTP server to port 3000
|
|
|
|
server.listen(3000);
|
2024-08-23 21:34:58 +02:00
|
|
|
|
2024-08-25 14:02:45 +02:00
|
|
|
// TODO: error logging
|
2024-08-25 11:32:03 +02:00
|
|
|
if (wwwrootError) throw wwwrootError;
|
|
|
|
if (configJSONRErr) throw configJSONRErr;
|
|
|
|
if (configJSONPErr) throw configJSONPErr;
|
2024-08-25 14:02:45 +02:00
|
|
|
modLoadingErrors.forEach((modLoadingError) => {
|
2024-08-25 14:24:18 +02:00
|
|
|
console.log('Error while loading "' + modLoadingError.modName + '" mod:');
|
2024-08-25 14:02:45 +02:00
|
|
|
console.log(modLoadingError.error);
|
2024-08-25 14:24:18 +02:00
|
|
|
});
|
2024-08-25 15:47:12 +02:00
|
|
|
if (SSJSError) {
|
|
|
|
console.log("Error while loading server-side JavaScript:");
|
|
|
|
console.log(SSJSError);
|
2024-08-25 15:50:56 +02:00
|
|
|
}
|
2024-08-25 16:23:16 +02:00
|
|
|
|
|
|
|
// Process event listeners
|
|
|
|
if (cluster.isPrimary || cluster.isPrimary === undefined) {
|
|
|
|
// Crash handler
|
|
|
|
function crashHandlerMaster(err) {
|
|
|
|
serverconsole.locerrmessage("SVR.JS worker just crashed!!!");
|
|
|
|
serverconsole.locerrmessage("Stack:");
|
2024-08-25 16:25:25 +02:00
|
|
|
serverconsole.locerrmessage(
|
|
|
|
err.stack ? generateErrorStack(err) : String(err),
|
|
|
|
);
|
2024-08-25 16:35:19 +02:00
|
|
|
process.exit(err.errno !== undefined ? err.errno : 1);
|
2024-08-25 16:23:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
process.on("uncaughtException", crashHandlerMaster);
|
|
|
|
process.on("unhandledRejection", crashHandlerMaster);
|
|
|
|
|
|
|
|
process.on("exit", function (code) {
|
|
|
|
try {
|
|
|
|
// TODO: saveConfig function
|
|
|
|
/*if (!configJSONRErr && !configJSONPErr) {
|
|
|
|
saveConfig();
|
|
|
|
}*/
|
|
|
|
} catch (err) {
|
2024-08-25 16:25:25 +02:00
|
|
|
serverconsole.locwarnmessage(
|
|
|
|
"There was a problem while saving configuration file. Reason: " +
|
|
|
|
err.message,
|
|
|
|
);
|
2024-08-25 16:23:16 +02:00
|
|
|
}
|
|
|
|
try {
|
|
|
|
deleteFolderRecursive(process.dirname + "/temp");
|
|
|
|
} catch (err) {
|
|
|
|
// Error!
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
fs.mkdirSync(process.dirname + "/temp");
|
|
|
|
} catch (err) {
|
|
|
|
// Error!
|
|
|
|
}
|
2024-08-25 16:25:25 +02:00
|
|
|
if (
|
|
|
|
process.isBun &&
|
|
|
|
process.versions.bun &&
|
|
|
|
process.versions.bun[0] == "0"
|
|
|
|
) {
|
2024-08-25 16:23:16 +02:00
|
|
|
try {
|
2024-08-25 16:25:25 +02:00
|
|
|
fs.writeFileSync(
|
|
|
|
process.dirname + "/temp/serverSideScript.js",
|
|
|
|
"// Placeholder server-side JavaScript to workaround Bun bug.\r\n",
|
|
|
|
);
|
2024-08-25 16:23:16 +02:00
|
|
|
} catch (err) {
|
|
|
|
// Error!
|
|
|
|
}
|
|
|
|
}
|
|
|
|
serverconsole.locmessage("Server closed with exit code: " + code);
|
|
|
|
});
|
|
|
|
process.on("warning", function (warning) {
|
|
|
|
serverconsole.locwarnmessage(warning.message);
|
|
|
|
if (generateErrorStack(warning)) {
|
|
|
|
serverconsole.locwarnmessage("Stack:");
|
|
|
|
serverconsole.locwarnmessage(generateErrorStack(warning));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
process.on("SIGINT", function () {
|
|
|
|
if (cluster.isPrimary !== undefined) {
|
|
|
|
exiting = true;
|
|
|
|
// TODO: commands
|
|
|
|
//const allWorkers = Object.keys(cluster.workers);
|
|
|
|
/*for (var i = 0; i < allWorkers.length; i++) {
|
|
|
|
try {
|
|
|
|
if (cluster.workers[allWorkers[i]]) {
|
|
|
|
cluster.workers[allWorkers[i]].send("stop");
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
// Worker will crash with EPIPE anyway.
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
serverconsole.locmessage("Server terminated using SIGINT");
|
|
|
|
process.exit();
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// Crash handler
|
|
|
|
function crashHandler(err) {
|
|
|
|
serverconsole.locerrmessage("SVR.JS worker just crashed!!!");
|
|
|
|
serverconsole.locerrmessage("Stack:");
|
2024-08-25 16:25:25 +02:00
|
|
|
serverconsole.locerrmessage(
|
|
|
|
err.stack ? generateErrorStack(err) : String(err),
|
|
|
|
);
|
2024-08-25 16:35:19 +02:00
|
|
|
process.exit(err.errno !== undefined ? err.errno : 1);
|
2024-08-25 16:23:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
process.on("uncaughtException", crashHandler);
|
|
|
|
process.on("unhandledRejection", crashHandler);
|
|
|
|
|
|
|
|
// Warning handler
|
|
|
|
process.on("warning", function (warning) {
|
|
|
|
serverconsole.locwarnmessage(warning.message);
|
|
|
|
if (warning.stack) {
|
|
|
|
serverconsole.locwarnmessage("Stack:");
|
|
|
|
serverconsole.locwarnmessage(generateErrorStack(warning));
|
|
|
|
}
|
|
|
|
});
|
2024-08-25 16:25:25 +02:00
|
|
|
}
|