forked from svrjs/svrjs
Lint out the codebase, add SVRJSFork() function, networking-related code, and ipSubnetUtils.js utility functions file and corresponding unit tests
This commit is contained in:
parent
2c990a6907
commit
0ea53fdf96
3 changed files with 270 additions and 5 deletions
176
src/index.js
176
src/index.js
|
@ -207,6 +207,10 @@ if (!fs.existsSync(process.dirname + "/temp"))
|
||||||
const cluster = require("./utils/clusterBunShim.js"); // Cluster module with shim for Bun
|
const cluster = require("./utils/clusterBunShim.js"); // Cluster module with shim for Bun
|
||||||
const legacyModWrapper = require("./utils/legacyModWrapper.js");
|
const legacyModWrapper = require("./utils/legacyModWrapper.js");
|
||||||
const generateErrorStack = require("./utils/generateErrorStack.js");
|
const generateErrorStack = require("./utils/generateErrorStack.js");
|
||||||
|
const {
|
||||||
|
calculateNetworkIPv4FromCidr,
|
||||||
|
calculateBroadcastIPv4FromCidr,
|
||||||
|
} = require("./utils/ipSubnetUtils.js");
|
||||||
//const serverHTTPErrorDescs = require("../res/httpErrorDescriptions.js");
|
//const serverHTTPErrorDescs = require("../res/httpErrorDescriptions.js");
|
||||||
//const getOS = require("./utils/getOS.js");
|
//const getOS = require("./utils/getOS.js");
|
||||||
//const parseURL = require("./utils/urlParser.js");
|
//const parseURL = require("./utils/urlParser.js");
|
||||||
|
@ -344,7 +348,7 @@ if (typeof process.serverConfig.port === "string") {
|
||||||
if (process.serverConfig.port.match(/^[0-9]+$/)) {
|
if (process.serverConfig.port.match(/^[0-9]+$/)) {
|
||||||
process.serverConfig.port = parseInt(process.serverConfig.port);
|
process.serverConfig.port = parseInt(process.serverConfig.port);
|
||||||
} else {
|
} else {
|
||||||
const portLMatch = port.match(
|
const portLMatch = process.serverConfig.port.match(
|
||||||
/^(\[[^ \]@\/\\]+\]|[^ \]\[:@\/\\]+):([0-9]+)$/,
|
/^(\[[^ \]@\/\\]+\]|[^ \]\[:@\/\\]+):([0-9]+)$/,
|
||||||
);
|
);
|
||||||
if (portLMatch) {
|
if (portLMatch) {
|
||||||
|
@ -357,7 +361,7 @@ if (typeof process.serverConfig.port === "string") {
|
||||||
}
|
}
|
||||||
if (typeof process.serverConfig.sport === "string") {
|
if (typeof process.serverConfig.sport === "string") {
|
||||||
if (process.serverConfig.sport.match(/^[0-9]+$/)) {
|
if (process.serverConfig.sport.match(/^[0-9]+$/)) {
|
||||||
process.serverConfig.sport = parseInt(sport);
|
process.serverConfig.sport = parseInt(process.serverConfig.sport);
|
||||||
} else {
|
} else {
|
||||||
const sportLMatch = process.serverConfig.sport.match(
|
const sportLMatch = process.serverConfig.sport.match(
|
||||||
/^(\[[^ \]@\/\\]+\]|[^ \]\[:@\/\\]+):([0-9]+)$/,
|
/^(\[[^ \]@\/\\]+\]|[^ \]\[:@\/\\]+):([0-9]+)$/,
|
||||||
|
@ -402,6 +406,58 @@ try {
|
||||||
wwwrootError = err;
|
wwwrootError = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IP and network inteface-related
|
||||||
|
let ifaces = {};
|
||||||
|
let ifaceEx = null;
|
||||||
|
try {
|
||||||
|
ifaces = os.networkInterfaces();
|
||||||
|
} catch (err) {
|
||||||
|
ifaceEx = err;
|
||||||
|
}
|
||||||
|
var ips = [];
|
||||||
|
const brdIPs = ["255.255.255.255", "127.255.255.255", "0.255.255.255"];
|
||||||
|
const netIPs = ["127.0.0.0"];
|
||||||
|
|
||||||
|
Object.keys(ifaces).forEach((ifname) => {
|
||||||
|
let alias = 0;
|
||||||
|
ifaces[ifname].forEach((iface) => {
|
||||||
|
if (iface.family !== "IPv4" || iface.internal !== false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (alias >= 1) {
|
||||||
|
ips.push(ifname + ":" + alias, iface.address);
|
||||||
|
} else {
|
||||||
|
ips.push(ifname, iface.address);
|
||||||
|
}
|
||||||
|
brdIPs.push(calculateBroadcastIPv4FromCidr(iface.cidr));
|
||||||
|
netIPs.push(calculateNetworkIPv4FromCidr(iface.cidr));
|
||||||
|
alias++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ips.length == 0) {
|
||||||
|
Object.keys(ifaces).forEach((ifname) => {
|
||||||
|
let alias = 0;
|
||||||
|
ifaces[ifname].forEach((iface) => {
|
||||||
|
if (iface.family !== "IPv6" || iface.internal !== false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (alias >= 1) {
|
||||||
|
ips.push(ifname + ":" + alias, iface.address);
|
||||||
|
} else {
|
||||||
|
ips.push(ifname, iface.address);
|
||||||
|
}
|
||||||
|
alias++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server IP address
|
||||||
|
var host = ips[(ips.length) - 1];
|
||||||
|
if (!host) host = "[offline]";
|
||||||
|
|
||||||
|
// TODO: Public IP address-related
|
||||||
|
|
||||||
// SSL-related
|
// SSL-related
|
||||||
let key = "";
|
let key = "";
|
||||||
let cert = "";
|
let cert = "";
|
||||||
|
@ -931,6 +987,108 @@ middleware.forEach((middlewareO) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// SVR.JS worker spawn-related
|
||||||
|
let SVRJSInitialized = false;
|
||||||
|
let crashed = false;
|
||||||
|
let threadLimitWarned = false;
|
||||||
|
|
||||||
|
// SVR.JS worker forking function
|
||||||
|
function SVRJSFork() {
|
||||||
|
// Log
|
||||||
|
if (SVRJSInitialized)
|
||||||
|
serverconsole.locmessage(
|
||||||
|
"Starting next thread, because previous one hung up/crashed...",
|
||||||
|
);
|
||||||
|
// Fork new worker
|
||||||
|
var newWorker = {};
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
!threadLimitWarned &&
|
||||||
|
cluster.__shimmed__ &&
|
||||||
|
process.isBun &&
|
||||||
|
process.versions.bun &&
|
||||||
|
process.versions.bun[0] != "0"
|
||||||
|
) {
|
||||||
|
threadLimitWarned = true;
|
||||||
|
serverconsole.locwarnmessage(
|
||||||
|
"SVR.JS limited the number of workers to one, because of startup problems in Bun 1.0 and newer with shimmed (not native) clustering module. Reliability may suffer.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
cluster.__shimmed__ &&
|
||||||
|
process.isBun &&
|
||||||
|
process.versions.bun &&
|
||||||
|
process.versions.bun[0] != "0" &&
|
||||||
|
Object.keys(cluster.workers) > 0
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
newWorker = cluster.fork();
|
||||||
|
} else {
|
||||||
|
if (SVRJSInitialized)
|
||||||
|
serverconsole.locwarnmessage(
|
||||||
|
"SVR.JS limited the number of workers to one, because of startup problems in Bun 1.0 and newer with shimmed (not native) clustering module. Reliability may suffer.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (err.name == "NotImplementedError") {
|
||||||
|
// If cluster.fork throws a NotImplementedError, shim cluster module
|
||||||
|
cluster.bunShim();
|
||||||
|
if (
|
||||||
|
!threadLimitWarned &&
|
||||||
|
cluster.__shimmed__ &&
|
||||||
|
process.isBun &&
|
||||||
|
process.versions.bun &&
|
||||||
|
process.versions.bun[0] != "0"
|
||||||
|
) {
|
||||||
|
threadLimitWarned = true;
|
||||||
|
serverconsole.locwarnmessage(
|
||||||
|
"SVR.JS limited the number of workers to one, because of startup problems in Bun 1.0 and newer with shimmed (not native) clustering module. Reliability may suffer.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
cluster.__shimmed__ &&
|
||||||
|
process.isBun &&
|
||||||
|
process.versions.bun &&
|
||||||
|
process.versions.bun[0] != "0" &&
|
||||||
|
Object.keys(cluster.workers) > 0
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
newWorker = cluster.fork();
|
||||||
|
} else {
|
||||||
|
if (SVRJSInitialized)
|
||||||
|
serverconsole.locwarnmessage(
|
||||||
|
"SVR.JS limited the number of workers to one, because of startup problems in Bun 1.0 and newer with shimmed (not native) clustering module. Reliability may suffer.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listeners
|
||||||
|
if (newWorker.on) {
|
||||||
|
newWorker.on("error", function (err) {
|
||||||
|
if (!exiting)
|
||||||
|
serverconsole.locwarnmessage(
|
||||||
|
"There was a problem when handling SVR.JS worker! (from master process side) Reason: " +
|
||||||
|
err.message,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
newWorker.on("exit", function () {
|
||||||
|
if (!exiting && Object.keys(cluster.workers).length == 0) {
|
||||||
|
crashed = true;
|
||||||
|
SVRJSFork();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// TODO: add listeners to workers
|
||||||
|
// newWorker.on("message", bruteForceListenerWrapper(newWorker));
|
||||||
|
// newWorker.on("message", listenConnListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starting function
|
||||||
function start(init) {
|
function start(init) {
|
||||||
init = Boolean(init);
|
init = Boolean(init);
|
||||||
if (cluster.isPrimary || cluster.isPrimary === undefined) {
|
if (cluster.isPrimary || cluster.isPrimary === undefined) {
|
||||||
|
@ -970,7 +1128,7 @@ function start(init) {
|
||||||
/^(?:0\.|1\.0\.|1\.1\.[0-9](?![0-9])|1\.1\.1[0-2](?![0-9]))/,
|
/^(?:0\.|1\.0\.|1\.1\.[0-9](?![0-9])|1\.1\.1[0-2](?![0-9]))/,
|
||||||
)
|
)
|
||||||
) &&
|
) &&
|
||||||
users.some(function (entry) {
|
process.serverConfig.users.some(function (entry) {
|
||||||
return entry.pbkdf2;
|
return entry.pbkdf2;
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -1161,7 +1319,12 @@ function start(init) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print server startup information
|
// Print server startup information
|
||||||
if (!(process.serverConfig.secure && process.serverConfig.disableNonEncryptedServer))
|
if (
|
||||||
|
!(
|
||||||
|
process.serverConfig.secure &&
|
||||||
|
process.serverConfig.disableNonEncryptedServer
|
||||||
|
)
|
||||||
|
)
|
||||||
serverconsole.locmessage(
|
serverconsole.locmessage(
|
||||||
"Starting HTTP server at " +
|
"Starting HTTP server at " +
|
||||||
(typeof process.serverConfig.port == "number"
|
(typeof process.serverConfig.port == "number"
|
||||||
|
@ -1213,7 +1376,10 @@ function start(init) {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.code != "ERR_SERVER_ALREADY_LISTEN") throw err;
|
if (err.code != "ERR_SERVER_ALREADY_LISTEN") throw err;
|
||||||
}
|
}
|
||||||
if (process.serverConfig.secure && !process.serverConfig.disableNonEncryptedServer) {
|
if (
|
||||||
|
process.serverConfig.secure &&
|
||||||
|
!process.serverConfig.disableNonEncryptedServer
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
if (typeof process.serverConfig.port == "number" && listenAddress) {
|
if (typeof process.serverConfig.port == "number" && listenAddress) {
|
||||||
server2.listen(process.serverConfig.port, listenAddress);
|
server2.listen(process.serverConfig.port, listenAddress);
|
||||||
|
|
50
src/utils/ipSubnetUtils.js
Normal file
50
src/utils/ipSubnetUtils.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
function calculateBroadcastIPv4FromCidr(ipWithCidr) {
|
||||||
|
// Check if CIDR notation is valid, if it's not, return null
|
||||||
|
if (!ipWithCidr) return null;
|
||||||
|
const ipCA = ipWithCidr.match(/^((?:(?:25[0-5]|(?:2[0-4]|1\d|[1-9]|)\d)\.?\b){4})\/([0-2][0-9]|3[0-2]|[0-9])$/);
|
||||||
|
if (!ipCA) return null;
|
||||||
|
|
||||||
|
// Extract IP and mask (numeric format)
|
||||||
|
const ip = ipCA[1];
|
||||||
|
const mask = parseInt(ipCA[2]);
|
||||||
|
|
||||||
|
return ip
|
||||||
|
.split(".")
|
||||||
|
.map((num, index) => {
|
||||||
|
// Calculate resulting 8-bit
|
||||||
|
var power = Math.max(Math.min(mask - index * 8, 8), 0);
|
||||||
|
return (
|
||||||
|
(parseInt(num) & ((Math.pow(2, power) - 1) << (8 - power))) |
|
||||||
|
(Math.pow(2, 8 - power) - 1)
|
||||||
|
).toString();
|
||||||
|
})
|
||||||
|
.join(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateNetworkIPv4FromCidr(ipWithCidr) {
|
||||||
|
// Check if CIDR notation is valid, if it's not, return null
|
||||||
|
if (!ipWithCidr) return null;
|
||||||
|
const ipCA = ipWithCidr.match(/^((?:(?:25[0-5]|(?:2[0-4]|1\d|[1-9]|)\d)\.?\b){4})\/([0-2][0-9]|3[0-2]|[0-9])$/);
|
||||||
|
if (!ipCA) return null;
|
||||||
|
|
||||||
|
// Extract IP and mask (numeric format)
|
||||||
|
const ip = ipCA[1];
|
||||||
|
const mask = parseInt(ipCA[2]);
|
||||||
|
|
||||||
|
return ip
|
||||||
|
.split(".")
|
||||||
|
.map((num, index) => {
|
||||||
|
// Calculate resulting 8-bit
|
||||||
|
var power = Math.max(Math.min(mask - index * 8, 8), 0);
|
||||||
|
return (
|
||||||
|
parseInt(num) &
|
||||||
|
((Math.pow(2, power) - 1) << (8 - power))
|
||||||
|
).toString();
|
||||||
|
})
|
||||||
|
.join(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
calculateBroadcastIPv4FromCidr: calculateBroadcastIPv4FromCidr,
|
||||||
|
calculateNetworkIPv4FromCidr: calculateNetworkIPv4FromCidr,
|
||||||
|
};
|
49
tests/utils/ipSubnetUtils.test.js
Normal file
49
tests/utils/ipSubnetUtils.test.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
const {
|
||||||
|
calculateBroadcastIPv4FromCidr,
|
||||||
|
calculateNetworkIPv4FromCidr,
|
||||||
|
} = require('../../src/utils/ipSubnetUtils');
|
||||||
|
|
||||||
|
describe('IPv4 subnet utilties', () => {
|
||||||
|
describe('calculateBroadcastIPv4FromCidr', () => {
|
||||||
|
test('should return the broadcast address for a given CIDR', () => {
|
||||||
|
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/24')).toBe('192.168.1.255');
|
||||||
|
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/25')).toBe('192.168.1.127');
|
||||||
|
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/26')).toBe('192.168.1.63');
|
||||||
|
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/27')).toBe('192.168.1.31');
|
||||||
|
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/28')).toBe('192.168.1.15');
|
||||||
|
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/29')).toBe('192.168.1.7');
|
||||||
|
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/30')).toBe('192.168.1.3');
|
||||||
|
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/31')).toBe('192.168.1.1');
|
||||||
|
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/32')).toBe('192.168.1.0');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return null for invalid CIDR notation', () => {
|
||||||
|
expect(calculateBroadcastIPv4FromCidr(null)).toBe(null);
|
||||||
|
expect(calculateBroadcastIPv4FromCidr('192.168.1.0')).toBe(null);
|
||||||
|
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/')).toBe(null);
|
||||||
|
expect(calculateBroadcastIPv4FromCidr('192.168.1.0/abc')).toBe(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('calculateNetworkIPv4FromCidr', () => {
|
||||||
|
test('should return the network address for a given CIDR', () => {
|
||||||
|
expect(calculateNetworkIPv4FromCidr('192.168.1.0/24')).toBe('192.168.1.0');
|
||||||
|
expect(calculateNetworkIPv4FromCidr('192.168.1.0/25')).toBe('192.168.1.0');
|
||||||
|
expect(calculateNetworkIPv4FromCidr('192.168.1.0/26')).toBe('192.168.1.0');
|
||||||
|
expect(calculateNetworkIPv4FromCidr('192.168.1.0/27')).toBe('192.168.1.0');
|
||||||
|
expect(calculateNetworkIPv4FromCidr('192.168.1.0/28')).toBe('192.168.1.0');
|
||||||
|
expect(calculateNetworkIPv4FromCidr('192.168.1.0/29')).toBe('192.168.1.0');
|
||||||
|
expect(calculateNetworkIPv4FromCidr('192.168.1.0/30')).toBe('192.168.1.0');
|
||||||
|
expect(calculateNetworkIPv4FromCidr('192.168.1.0/31')).toBe('192.168.1.0');
|
||||||
|
expect(calculateNetworkIPv4FromCidr('192.168.1.0/32')).toBe('192.168.1.0');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return null for invalid CIDR notation', () => {
|
||||||
|
expect(calculateNetworkIPv4FromCidr(null)).toBe(null);
|
||||||
|
expect(calculateNetworkIPv4FromCidr('192.168.1.0')).toBe(null);
|
||||||
|
expect(calculateNetworkIPv4FromCidr('192.168.1.0/')).toBe(null);
|
||||||
|
expect(calculateNetworkIPv4FromCidr('192.168.1.0/abc')).toBe(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Reference in a new issue