1
0
Fork 0
forked from svrjs/svrjs

Lint out the codebase.

This commit is contained in:
Dorian Niemiec 2024-08-24 08:07:31 +02:00
parent 1929641ba7
commit a49dba73fe
8 changed files with 374 additions and 276 deletions

View file

@ -1,9 +1,11 @@
const http = require("http"); const http = require("http");
const fs = require("fs"); const fs = require("fs");
const net = require("net");
const generateErrorStack = require("../utils/generateErrorStack.js"); const generateErrorStack = require("../utils/generateErrorStack.js");
const serverHTTPErrorDescs = require("../res/httpErrorDescriptions.js"); const serverHTTPErrorDescs = require("../res/httpErrorDescriptions.js");
const fixNodeMojibakeURL = require("../utils/urlMojibakeFixer.js"); const fixNodeMojibakeURL = require("../utils/urlMojibakeFixer.js");
const getOS = require("../utils/getOS.js"); const getOS = require("../utils/getOS.js");
const ipMatch = require("../utils/ipMatch.js");
const svrjsInfo = require("../../svrjs.json"); const svrjsInfo = require("../../svrjs.json");
const version = svrjsInfo.version; const version = svrjsInfo.version;
@ -295,15 +297,15 @@ module.exports = (req, res, logFacilities, config, next) => {
"Host name rewritten: " + oldHostHeader + " => " + req.headers.host, "Host name rewritten: " + oldHostHeader + " => " + req.headers.host,
); );
// Header and footer placeholders // Header and footer placeholders
res.head = ""; res.head = "";
res.foot = ""; res.foot = "";
res.responseEnd = (body) => { res.responseEnd = (body) => {
// If body is Buffer, then it is converted to String anyway. // If body is Buffer, then it is converted to String anyway.
res.write(head + body + foot); res.write(res.head + body + res.foot);
res.end(); res.end();
} };
// Server error calling method // Server error calling method
res.error = (errorCode, extName, stack, ch) => { res.error = (errorCode, extName, stack, ch) => {
@ -670,8 +672,16 @@ module.exports = (req, res, logFacilities, config, next) => {
}; };
try { try {
res.head = fs.existsSync("./.head") ? fs.readFileSync("./.head").toString() : (fs.existsSync("./head.html") ? fs.readFileSync("./head.html").toString() : ""); // header res.head = fs.existsSync("./.head")
res.foot = fs.existsSync("./.foot") ? fs.readFileSync("./.foot").toString() : (fs.existsSync("./foot.html") ? fs.readFileSync("./foot.html").toString() : ""); // footer ? fs.readFileSync("./.head").toString()
: fs.existsSync("./head.html")
? fs.readFileSync("./head.html").toString()
: ""; // header
res.foot = fs.existsSync("./.foot")
? fs.readFileSync("./.foot").toString()
: fs.existsSync("./foot.html")
? fs.readFileSync("./foot.html").toString()
: ""; // footer
} catch (err) { } catch (err) {
res.error(500, err); res.error(500, err);
} }

View file

@ -3,7 +3,12 @@ module.exports = (req, res, logFacilities, config, next) => {
let fromMain = !(config.secure && !req.socket.encrypted); let fromMain = !(config.secure && !req.socket.encrypted);
// Handle redirects to HTTPS // Handle redirects to HTTPS
if (config.secure && !fromMain && !config.disableNonEncryptedServer && !config.disableToHTTPSRedirect) { if (
config.secure &&
!fromMain &&
!config.disableNonEncryptedServer &&
!config.disableToHTTPSRedirect
) {
var hostx = req.headers.host; var hostx = req.headers.host;
if (hostx === undefined) { if (hostx === undefined) {
logFacilities.errmessage("Host header is missing."); logFacilities.errmessage("Host header is missing.");
@ -17,7 +22,13 @@ module.exports = (req, res, logFacilities, config, next) => {
return; return;
} }
var isPublicServer = !(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); var isPublicServer = !(
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,
);
var destinationPort = 0; var destinationPort = 0;
@ -26,13 +37,21 @@ module.exports = (req, res, logFacilities, config, next) => {
var hostPort = parsedHostx[2] ? parseInt(parsedHostx[2]) : 80; var hostPort = parsedHostx[2] ? parseInt(parsedHostx[2]) : 80;
if (isNaN(hostPort)) hostPort = 80; if (isNaN(hostPort)) hostPort = 80;
if (hostPort == config.port || (config.port == config.pubport && !isPublicServer)) { if (
hostPort == config.port ||
(config.port == config.pubport && !isPublicServer)
) {
destinationPort = config.sport; destinationPort = config.sport;
} else { } else {
destinationPort = config.spubport; destinationPort = config.spubport;
} }
redirect("https://" + hostname + (destinationPort == 443 ? "" : (":" + destinationPort)) + req.url); res.redirect(
"https://" +
hostname +
(destinationPort == 443 ? "" : ":" + destinationPort) +
req.url,
);
return; return;
} }
@ -40,13 +59,23 @@ module.exports = (req, res, logFacilities, config, next) => {
if (config.wwwredirect) { if (config.wwwredirect) {
let hostname = req.headers.host.split(":"); let hostname = req.headers.host.split(":");
let hostport = null; let hostport = null;
if (hostname.length > 1 && (hostname[0] != "[" || hostname[hostname.length - 1] != "]")) hostport = hostname.pop(); if (
hostname.length > 1 &&
(hostname[0] != "[" || hostname[hostname.length - 1] != "]")
)
hostport = hostname.pop();
hostname = hostname.join(":"); hostname = hostname.join(":");
if (hostname == domain && hostname.indexOf("www.") != 0) { if (hostname == config.domain && hostname.indexOf("www.") != 0) {
res.redirect((req.socket.encrypted ? "https" : "http") + "://www." + hostname + (hostport ? ":" + hostport : "") + req.url.replace(/\/+/g, "/")); res.redirect(
(req.socket.encrypted ? "https" : "http") +
"://www." +
hostname +
(hostport ? ":" + hostport : "") +
req.url.replace(/\/+/g, "/"),
);
return; return;
} }
} }
next(); next();
} };

View file

@ -1,4 +1,3 @@
const { emitWarning } = require("process");
const sanitizeURL = require("../utils/urlSanitizer.js"); const sanitizeURL = require("../utils/urlSanitizer.js");
const url = require("url"); const url = require("url");

View file

@ -1,116 +1,147 @@
const url = require("url");
const createRegex = require("../utils/createRegex.js"); const createRegex = require("../utils/createRegex.js");
const ipMatch = require("../utils/ipMatch.js"); const ipMatch = require("../utils/ipMatch.js");
const sanitizeURL = require("../utils/urlSanitizer.js"); const sanitizeURL = require("../utils/urlSanitizer.js");
module.exports = (req, res, logFacilities, config, next) => { module.exports = (req, res, logFacilities, config, next) => {
const matchHostname = (hostname) => { const matchHostname = (hostname) => {
if (typeof hostname == "undefined" || hostname == "*") { if (typeof hostname == "undefined" || hostname == "*") {
return true; return true;
} else if ( } else if (
req.headers.host && req.headers.host &&
hostname.indexOf("*.") == 0 && hostname.indexOf("*.") == 0 &&
hostname != "*." hostname != "*."
) { ) {
const hostnamesRoot = hostname.substring(2); const hostnamesRoot = hostname.substring(2);
if ( if (
req.headers.host == hostnamesRoot || req.headers.host == hostnamesRoot ||
(req.headers.host.length > hostnamesRoot.length && (req.headers.host.length > hostnamesRoot.length &&
req.headers.host.indexOf("." + hostnamesRoot) == req.headers.host.indexOf("." + hostnamesRoot) ==
req.headers.host.length - hostnamesRoot.length - 1) req.headers.host.length - hostnamesRoot.length - 1)
) { ) {
return true; return true;
} }
} else if (req.headers.host && req.headers.host == hostname) { } else if (req.headers.host && req.headers.host == hostname) {
return true; return true;
} }
return false;
};
// Add web root postfixes
if (!req.isProxy) {
let preparedReqUrl3 = config.allowPostfixDoubleSlashes
? req.parsedURL.pathname.replace(/\/+/, "/") +
req.parsedURL.search +
req.parsedURL.hash
: req.url;
let urlWithPostfix = preparedReqUrl3;
let postfixPrefix = "";
config.wwwrootPostfixPrefixesVHost.every(function (currentPostfixPrefix) {
if (preparedReqUrl3.indexOf(currentPostfixPrefix) == 0) {
if (currentPostfixPrefix.match(/\/+$/))
postfixPrefix = currentPostfixPrefix.replace(/\/+$/, "");
else if (
urlWithPostfix.length == currentPostfixPrefix.length ||
urlWithPostfix[currentPostfixPrefix.length] == "?" ||
urlWithPostfix[currentPostfixPrefix.length] == "/" ||
urlWithPostfix[currentPostfixPrefix.length] == "#"
)
postfixPrefix = currentPostfixPrefix;
else return true;
urlWithPostfix = urlWithPostfix.substring(postfixPrefix.length);
return false; return false;
}; } else {
return true;
// Add web root postfixes }
if (!req.isProxy) { });
let preparedReqUrl3 = (config.allowPostfixDoubleSlashes ? (req.parsedURL.pathname.replace(/\/+/,"/") + req.parsedURL.search + req.parsedURL.hash) : req.url); config.wwwrootPostfixesVHost.every(function (postfixEntry) {
let urlWithPostfix = preparedReqUrl3; if (
let postfixPrefix = ""; matchHostname(postfixEntry.host) &&
config.wwwrootPostfixPrefixesVHost.every(function (currentPostfixPrefix) { ipMatch(
if (preparedReqUrl3.indexOf(currentPostfixPrefix) == 0) { postfixEntry.ip,
if (currentPostfixPrefix.match(/\/+$/)) postfixPrefix = currentPostfixPrefix.replace(/\/+$/, ""); req.socket ? req.socket.localAddress : undefined,
else if (urlWithPostfix.length == currentPostfixPrefix.length || urlWithPostfix[currentPostfixPrefix.length] == "?" || urlWithPostfix[currentPostfixPrefix.length] == "/" || urlWithPostfix[currentPostfixPrefix.length] == "#") postfixPrefix = currentPostfixPrefix; ) &&
else return true; !(
urlWithPostfix = urlWithPostfix.substring(postfixPrefix.length); postfixEntry.skipRegex &&
return false; preparedReqUrl3.match(createRegex(postfixEntry.skipRegex))
} else { )
return true; ) {
} urlWithPostfix =
}); postfixPrefix + "/" + postfixEntry.postfix + urlWithPostfix;
config.wwwrootPostfixesVHost.every(function (postfixEntry) { return false;
if (matchHostname(postfixEntry.host) && ipMatch(postfixEntry.ip, req.socket ? req.socket.localAddress : undefined) && !(postfixEntry.skipRegex && preparedReqUrl3.match(createRegex(postfixEntry.skipRegex)))) { } else {
urlWithPostfix = postfixPrefix + "/" + postfixEntry.postfix + urlWithPostfix; return true;
return false; }
} else { });
return true; if (urlWithPostfix != preparedReqUrl3) {
} logFacilities.resmessage(
}); "Added web root postfix: " + req.url + " => " + urlWithPostfix,
if (urlWithPostfix != preparedReqUrl3) { );
logFacilities.resmessage("Added web root postfix: " + req.url + " => " + urlWithPostfix); req.url = urlWithPostfix;
req.url = urlWithPostfix; try {
try { req.parsedURL = new URL(
req.parsedURL = new URL( req.url,
req.url, "http" +
"http" + (req.socket.encrypted ? "s" : "") +
(req.socket.encrypted ? "s" : "") + "://" +
"://" + (req.headers.host
(req.headers.host ? req.headers.host
? req.headers.host : config.domain
: config.domain ? config.domain
? config.domain : "unknown.invalid"),
: "unknown.invalid"), );
); } catch (err) {
} catch (err) { res.error(400, err);
res.error(400, err); return;
return;
}
let href = req.parsedURL.pathname + req.parsedURL.search;
var sHref = sanitizeURL(href, allowDoubleSlashes);
var preparedReqUrl2 = req.parsedURL.pathname + req.parsedURL.search + req.parsedURL.hash;
if (req.url != preparedReqUrl2 || sHref != href.replace(/\/\.(?=\/|$)/g, "/").replace(/\/+/g, "/")) {
res.error(403);
logFacilities.errmessage("Content blocked.");
return;
} else if (sHref != href) {
var rewrittenAgainURL = new url.Url();
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);
logFacilities.resmessage("URL sanitized: " + req.url + " => " + rewrittenAgainURL);
req.url = rewrittenAgainURL;
try {
req.parsedURL = new URL(
req.url,
"http" +
(req.socket.encrypted ? "s" : "") +
"://" +
(req.headers.host
? req.headers.host
: config.domain
? config.domain
: "unknown.invalid"),
);
} catch (err) {
res.error(400, err);
return;
}
}
}
} }
next(); let href = req.parsedURL.pathname + req.parsedURL.search;
};
var sHref = sanitizeURL(href, config.allowDoubleSlashes);
var preparedReqUrl2 =
req.parsedURL.pathname + req.parsedURL.search + req.parsedURL.hash;
if (
req.url != preparedReqUrl2 ||
sHref != href.replace(/\/\.(?=\/|$)/g, "/").replace(/\/+/g, "/")
) {
res.error(403);
logFacilities.errmessage("Content blocked.");
return;
} else if (sHref != href) {
var rewrittenAgainURL = new url.Url();
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);
logFacilities.resmessage(
"URL sanitized: " + req.url + " => " + rewrittenAgainURL,
);
req.url = rewrittenAgainURL;
try {
req.parsedURL = new URL(
req.url,
"http" +
(req.socket.encrypted ? "s" : "") +
"://" +
(req.headers.host
? req.headers.host
: config.domain
? config.domain
: "unknown.invalid"),
);
} catch (err) {
res.error(400, err);
return;
}
}
}
}
next();
};

View file

@ -1,12 +1,13 @@
const os = require("os"); const os = require("os");
function createRegex(regex, isPath) { function createRegex(regex, isPath) {
var regexStrMatch = regex.match(/^\/((?:\\.|[^\/\\])*)\/([a-zA-Z0-9]*)$/); const regexStrMatch = regex.match(/^\/((?:\\.|[^\/\\])*)\/([a-zA-Z0-9]*)$/);
if (!regexStrMatch) throw new Error("Invalid regular expression: " + regex); if (!regexStrMatch) throw new Error("Invalid regular expression: " + regex);
var searchString = regexStrMatch[1]; const searchString = regexStrMatch[1];
var modifiers = regexStrMatch[2]; let modifiers = regexStrMatch[2];
if (isPath && !modifiers.match(/i/i) && os.platform() == "win32") modifiers += "i"; if (isPath && !modifiers.match(/i/i) && os.platform() == "win32")
return new RegExp(searchString, modifiers); modifiers += "i";
} return new RegExp(searchString, modifiers);
}
module.exports = createRegex; module.exports = createRegex;

View file

@ -1,78 +1,82 @@
// Function to check if IPs are equal // Function to check if IPs are equal
function ipMatch(IP1, IP2) { function ipMatch(IP1, IP2) {
if (!IP1) return true; if (!IP1) return true;
if (!IP2) return false; if (!IP2) return false;
// Function to normalize IPv4 address (remove leading zeros) // Function to normalize IPv4 address (remove leading zeros)
function normalizeIPv4Address(address) { function normalizeIPv4Address(address) {
return address.replace(/(^|\.)(?:0(?!\.|$))+/g, "$1"); return address.replace(/(^|\.)(?:0(?!\.|$))+/g, "$1");
}
// Function to expand IPv6 address to full format
function expandIPv6Address(address) {
var fullAddress = "";
var expandedAddress = "";
var validGroupCount = 8;
var validGroupSize = 4;
var ipv4 = "";
var extractIpv4 = /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/;
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)) {
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);
}
if (address.indexOf("::") == -1) {
fullAddress = address;
} else {
var sides = address.split("::");
var groupsPresent = 0;
sides.forEach(function (side) {
groupsPresent += side.split(":").length;
});
fullAddress += sides[0] + ":";
if (validGroupCount - groupsPresent > 1) {
fullAddress += "0000:".repeat(validGroupCount - groupsPresent);
}
fullAddress += sides[1];
}
var groups = fullAddress.split(":");
for (var i = 0; i < validGroupCount; i++) {
if (groups[i].length < validGroupSize) {
groups[i] = "0".repeat(validGroupSize - groups[i].length) + groups[i];
}
expandedAddress += (i != validGroupCount - 1) ? groups[i] + ":" : groups[i];
}
return expandedAddress;
}
// Normalize or expand IP addresses
IP1 = IP1.toLowerCase();
if (IP1 == "localhost") IP1 = "::1";
if (IP1.indexOf("::ffff:") == 0) IP1 = IP1.substring(7);
if (IP1.indexOf(":") > -1) {
IP1 = expandIPv6Address(IP1);
} else {
IP1 = normalizeIPv4Address(IP1);
}
IP2 = IP2.toLowerCase();
if (IP2 == "localhost") IP2 = "::1";
if (IP2.indexOf("::ffff:") == 0) IP2 = IP2.substring(7);
if (IP2.indexOf(":") > -1) {
IP2 = expandIPv6Address(IP2);
} else {
IP2 = normalizeIPv4Address(IP2);
}
// Check if processed IPs are equal
if (IP1 == IP2) return true;
else return false;
} }
module.exports = ipMatch; // Function to expand IPv6 address to full format
function expandIPv6Address(address) {
let fullAddress = "";
let expandedAddress = "";
let validGroupCount = 8;
let validGroupSize = 4;
let ipv4 = "";
const extractIpv4 =
/([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/;
const 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)) {
const oldGroups = address.match(extractIpv4);
for (let i = 1; i < oldGroups.length; i++) {
ipv4 +=
("00" + parseInt(oldGroups[i], 10).toString(16)).slice(-2) +
(i == 2 ? ":" : "");
}
address = address.replace(extractIpv4, ipv4);
}
if (address.indexOf("::") == -1) {
fullAddress = address;
} else {
const sides = address.split("::");
let groupsPresent = 0;
sides.forEach((side) => {
groupsPresent += side.split(":").length;
});
fullAddress += sides[0] + ":";
if (validGroupCount - groupsPresent > 1) {
fullAddress += "0000:".repeat(validGroupCount - groupsPresent);
}
fullAddress += sides[1];
}
let groups = fullAddress.split(":");
for (let i = 0; i < validGroupCount; i++) {
if (groups[i].length < validGroupSize) {
groups[i] = "0".repeat(validGroupSize - groups[i].length) + groups[i];
}
expandedAddress += i != validGroupCount - 1 ? groups[i] + ":" : groups[i];
}
return expandedAddress;
}
// Normalize or expand IP addresses
IP1 = IP1.toLowerCase();
if (IP1 == "localhost") IP1 = "::1";
if (IP1.indexOf("::ffff:") == 0) IP1 = IP1.substring(7);
if (IP1.indexOf(":") > -1) {
IP1 = expandIPv6Address(IP1);
} else {
IP1 = normalizeIPv4Address(IP1);
}
IP2 = IP2.toLowerCase();
if (IP2 == "localhost") IP2 = "::1";
if (IP2.indexOf("::ffff:") == 0) IP2 = IP2.substring(7);
if (IP2.indexOf(":") > -1) {
IP2 = expandIPv6Address(IP2);
} else {
IP2 = normalizeIPv4Address(IP2);
}
// Check if processed IPs are equal
if (IP1 == IP2) return true;
else return false;
}
module.exports = ipMatch;

View file

@ -1,75 +1,77 @@
const createRegex = require('../../src/utils/createRegex'); const createRegex = require("../../src/utils/createRegex");
const os = require('os'); const os = require("os");
jest.mock('os', () => ({ jest.mock("os", () => ({
platform: jest.fn(), platform: jest.fn(),
})); }));
describe('createRegex', () => { describe("createRegex", () => {
beforeEach(() => { beforeEach(() => {
os.platform.mockReset(); os.platform.mockReset();
}); });
test('should throw an error for invalid regular expression', () => { test("should throw an error for invalid regular expression", () => {
expect(() => createRegex('invalid/regex', false)).toThrow('Invalid regular expression: invalid/regex'); expect(() => createRegex("invalid/regex", false)).toThrow(
"Invalid regular expression: invalid/regex",
);
}); });
test('should create a regular expression without modifiers', () => { test("should create a regular expression without modifiers", () => {
const regex = createRegex('/test/', false); const regex = createRegex("/test/", false);
expect(regex).toBeInstanceOf(RegExp); expect(regex).toBeInstanceOf(RegExp);
expect(regex.source).toBe('test'); expect(regex.source).toBe("test");
expect(regex.flags).toBe(''); expect(regex.flags).toBe("");
}); });
test('should create a regular expression with modifiers', () => { test("should create a regular expression with modifiers", () => {
const regex = createRegex('/test/gi', false); const regex = createRegex("/test/gi", false);
expect(regex).toBeInstanceOf(RegExp); expect(regex).toBeInstanceOf(RegExp);
expect(regex.source).toBe('test'); expect(regex.source).toBe("test");
expect(regex.flags).toBe('gi'); expect(regex.flags).toBe("gi");
}); });
test('should add "i" modifier for paths on Windows', () => { test('should add "i" modifier for paths on Windows', () => {
os.platform.mockReturnValue('win32'); os.platform.mockReturnValue("win32");
const regex = createRegex('/test/', true); const regex = createRegex("/test/", true);
expect(regex).toBeInstanceOf(RegExp); expect(regex).toBeInstanceOf(RegExp);
expect(regex.source).toBe('test'); expect(regex.source).toBe("test");
expect(regex.flags).toBe('i'); expect(regex.flags).toBe("i");
}); });
test('should not add "i" modifier for paths on non-Windows platforms', () => { test('should not add "i" modifier for paths on non-Windows platforms', () => {
os.platform.mockReturnValue('linux'); os.platform.mockReturnValue("linux");
const regex = createRegex('/test/', true); const regex = createRegex("/test/", true);
expect(regex).toBeInstanceOf(RegExp); expect(regex).toBeInstanceOf(RegExp);
expect(regex.source).toBe('test'); expect(regex.source).toBe("test");
expect(regex.flags).toBe(''); expect(regex.flags).toBe("");
}); });
test('should not add "i" modifier if already present', () => { test('should not add "i" modifier if already present', () => {
os.platform.mockReturnValue('win32'); os.platform.mockReturnValue("win32");
const regex = createRegex('/test/i', true); const regex = createRegex("/test/i", true);
expect(regex).toBeInstanceOf(RegExp); expect(regex).toBeInstanceOf(RegExp);
expect(regex.source).toBe('test'); expect(regex.source).toBe("test");
expect(regex.flags).toBe('i'); expect(regex.flags).toBe("i");
}); });
test('should handle escaped characters in the search string', () => { test("should handle escaped characters in the search string", () => {
const regex = createRegex('/test\\/path/', false); const regex = createRegex("/test\\/path/", false);
expect(regex).toBeInstanceOf(RegExp); expect(regex).toBeInstanceOf(RegExp);
expect(regex.source).toBe('test\\/path'); expect(regex.source).toBe("test\\/path");
expect(regex.flags).toBe(''); expect(regex.flags).toBe("");
}); });
test('should handle multiple modifiers', () => { test("should handle multiple modifiers", () => {
const regex = createRegex('/test/gim', false); const regex = createRegex("/test/gim", false);
expect(regex).toBeInstanceOf(RegExp); expect(regex).toBeInstanceOf(RegExp);
expect(regex.source).toBe('test'); expect(regex.source).toBe("test");
expect(regex.flags).toBe('gim'); expect(regex.flags).toBe("gim");
}); });
test('should handle empty search string', () => { test("should handle empty search string", () => {
const regex = createRegex('/^$/', false); const regex = createRegex("/^$/", false);
expect(regex).toBeInstanceOf(RegExp); expect(regex).toBeInstanceOf(RegExp);
expect(regex.source).toBe('^$'); expect(regex.source).toBe("^$");
expect(regex.flags).toBe(''); expect(regex.flags).toBe("");
}); });
}); });

View file

@ -1,60 +1,82 @@
const ipMatch = require('../../src/utils/ipMatch'); const ipMatch = require("../../src/utils/ipMatch");
describe('ipMatch', () => { describe("ipMatch", () => {
test('should return true if IP1 is empty', () => { test("should return true if IP1 is empty", () => {
expect(ipMatch('', '192.168.1.1')).toBe(true); expect(ipMatch("", "192.168.1.1")).toBe(true);
}); });
test('should return false if IP2 is empty', () => { test("should return false if IP2 is empty", () => {
expect(ipMatch('192.168.1.1', '')).toBe(false); expect(ipMatch("192.168.1.1", "")).toBe(false);
}); });
test('should return true if both IPs are empty', () => { test("should return true if both IPs are empty", () => {
expect(ipMatch('', '')).toBe(true); expect(ipMatch("", "")).toBe(true);
}); });
test('should return true if both IPs are the same IPv4 address', () => { test("should return true if both IPs are the same IPv4 address", () => {
expect(ipMatch('192.168.1.1', '192.168.1.1')).toBe(true); expect(ipMatch("192.168.1.1", "192.168.1.1")).toBe(true);
}); });
test('should return false if IPs are different IPv4 addresses', () => { test("should return false if IPs are different IPv4 addresses", () => {
expect(ipMatch('192.168.1.1', '192.168.1.2')).toBe(false); expect(ipMatch("192.168.1.1", "192.168.1.2")).toBe(false);
}); });
test('should normalize IPv4 addresses with leading zeros', () => { test("should normalize IPv4 addresses with leading zeros", () => {
expect(ipMatch('192.168.001.001', '192.168.1.1')).toBe(true); expect(ipMatch("192.168.001.001", "192.168.1.1")).toBe(true);
}); });
test('should return true if both IPs are the same IPv6 address', () => { test("should return true if both IPs are the same IPv6 address", () => {
expect(ipMatch('2001:0db8:85a3:0000:0000:8a2e:0370:7334', '2001:db8:85a3::8a2e:370:7334')).toBe(true); expect(
ipMatch(
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
"2001:db8:85a3::8a2e:370:7334",
),
).toBe(true);
}); });
test('should return false if IPs are different IPv6 addresses', () => { test("should return false if IPs are different IPv6 addresses", () => {
expect(ipMatch('2001:0db8:85a3:0000:0000:8a2e:0370:7334', '2001:db8:85a3::8a2e:370:7335')).toBe(false); expect(
ipMatch(
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
"2001:db8:85a3::8a2e:370:7335",
),
).toBe(false);
}); });
test('should expand IPv6 addresses with "::"', () => { test('should expand IPv6 addresses with "::"', () => {
expect(ipMatch('::1', '0:0:0:0:0:0:0:1')).toBe(true); expect(ipMatch("::1", "0:0:0:0:0:0:0:1")).toBe(true);
}); });
test('should handle IPv6 addresses with embedded IPv4 addresses', () => { test("should handle IPv6 addresses with embedded IPv4 addresses", () => {
expect(ipMatch('::ffff:192.168.1.1', '192.168.1.1')).toBe(true); expect(ipMatch("::ffff:192.168.1.1", "192.168.1.1")).toBe(true);
}); });
test('should handle "localhost" as IPv6 loopback address', () => { test('should handle "localhost" as IPv6 loopback address', () => {
expect(ipMatch('localhost', '::1')).toBe(true); expect(ipMatch("localhost", "::1")).toBe(true);
}); });
test('should handle mixed case IP addresses', () => { test("should handle mixed case IP addresses", () => {
expect(ipMatch('192.168.1.1', '192.168.1.1')).toBe(true); expect(ipMatch("192.168.1.1", "192.168.1.1")).toBe(true);
expect(ipMatch('2001:DB8:85A3::8A2E:370:7334', '2001:db8:85a3::8a2e:370:7334')).toBe(true); expect(
ipMatch("2001:DB8:85A3::8A2E:370:7334", "2001:db8:85a3::8a2e:370:7334"),
).toBe(true);
}); });
test('should handle IPv6 addresses with leading zeros', () => { test("should handle IPv6 addresses with leading zeros", () => {
expect(ipMatch('2001:0db8:85a3:0000:0000:8a2e:0370:7334', '2001:db8:85a3::8a2e:370:7334')).toBe(true); expect(
ipMatch(
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
"2001:db8:85a3::8a2e:370:7334",
),
).toBe(true);
}); });
test('should handle IPv6 addresses with mixed case and leading zeros', () => { test("should handle IPv6 addresses with mixed case and leading zeros", () => {
expect(ipMatch('2001:0DB8:85A3:0000:0000:8A2E:0370:7334', '2001:db8:85a3::8a2e:370:7334')).toBe(true); expect(
ipMatch(
"2001:0DB8:85A3:0000:0000:8A2E:0370:7334",
"2001:db8:85a3::8a2e:370:7334",
),
).toBe(true);
}); });
}); });