From f48125f4f2b32e7cfc9b0d1ce47b05dabb3a85e6 Mon Sep 17 00:00:00 2001 From: Dorian Niemiec Date: Sat, 24 Aug 2024 17:21:09 +0200 Subject: [PATCH] Move matchHostname function to separate source file, and add unit tests for the function. --- src/middleware/core.js | 28 ++--------------- src/middleware/rewriteURL.js | 26 ++-------------- src/utils/matchHostname.js | 24 +++++++++++++++ tests/utils/matchHostname.test.js | 51 +++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 49 deletions(-) create mode 100644 src/utils/matchHostname.js create mode 100644 tests/utils/matchHostname.test.js diff --git a/src/middleware/core.js b/src/middleware/core.js index 9957929..3dc8718 100644 --- a/src/middleware/core.js +++ b/src/middleware/core.js @@ -6,6 +6,7 @@ const generateServerString = require("../utils/generateServerString.js"); const serverHTTPErrorDescs = require("../res/httpErrorDescriptions.js"); const fixNodeMojibakeURL = require("../utils/urlMojibakeFixer.js"); const ipMatch = require("../utils/ipMatch.js"); +const matchHostname = require("../utils/matchHostname.js"); const svrjsInfo = require("../../svrjs.json"); const version = svrjsInfo.version; @@ -14,29 +15,6 @@ if (!process.err5xxcounter) process.err5xxcounter = 0; if (!process.reqcounter) process.reqcounter = 0; module.exports = (req, res, logFacilities, config, next) => { - const matchHostname = (hostname) => { - if (typeof hostname == "undefined" || hostname == "*") { - return true; - } else if ( - req.headers.host && - hostname.indexOf("*.") == 0 && - hostname != "*." - ) { - const hostnamesRoot = hostname.substring(2); - if ( - req.headers.host == hostnamesRoot || - (req.headers.host.length > hostnamesRoot.length && - req.headers.host.indexOf("." + hostnamesRoot) == - req.headers.host.length - hostnamesRoot.length - 1) - ) { - return true; - } - } else if (req.headers.host && req.headers.host == hostname) { - return true; - } - return false; - }; - config.generateServerString = () => { return generateServerString(config.exposeServerVersion); }; @@ -48,7 +26,7 @@ module.exports = (req, res, logFacilities, config, next) => { let vhostP = null; config.customHeadersVHost.every(function (vhost) { if ( - matchHostname(vhost.host) && + matchHostname(vhost.host, req.headers.host) && ipMatch(vhost.ip, req.socket ? req.socket.localAddress : undefined) ) { vhostP = vhost; @@ -398,7 +376,7 @@ module.exports = (req, res, logFacilities, config, next) => { if ( list[_i].scode != errorCode || !( - matchHostname(list[_i].host) && + matchHostname(list[_i].host, req.headers.host) && ipMatch(list[_i].ip, req.socket ? req.socket.localAddress : undefined) ) ) { diff --git a/src/middleware/rewriteURL.js b/src/middleware/rewriteURL.js index 2402d74..edf236c 100644 --- a/src/middleware/rewriteURL.js +++ b/src/middleware/rewriteURL.js @@ -3,6 +3,7 @@ const url = require("url"); const createRegex = require("../utils/createRegex.js"); const ipMatch = require("../utils/ipMatch.js"); const sanitizeURL = require("../utils/urlSanitizer.js"); +const matchHostname = require("../utils/matchHostname.js"); module.exports = (req, res, logFacilities, config, next) => { try { @@ -11,29 +12,6 @@ module.exports = (req, res, logFacilities, config, next) => { res.error(400); } - const matchHostname = (hostname) => { - if (typeof hostname == "undefined" || hostname == "*") { - return true; - } else if ( - req.headers.host && - hostname.indexOf("*.") == 0 && - hostname != "*." - ) { - const hostnamesRoot = hostname.substring(2); - if ( - req.headers.host == hostnamesRoot || - (req.headers.host.length > hostnamesRoot.length && - req.headers.host.indexOf("." + hostnamesRoot) == - req.headers.host.length - hostnamesRoot.length - 1) - ) { - return true; - } - } else if (req.headers.host && req.headers.host == hostname) { - return true; - } - return false; - }; - // Handle URL rewriting const rewriteURL = (address, map, callback, _fileState, _mapBegIndex) => { let rewrittenURL = address; @@ -71,7 +49,7 @@ module.exports = (req, res, logFacilities, config, next) => { tempRewrittenURL = address; } if ( - matchHostname(mapEntry.host) && + matchHostname(mapEntry.host, req.headers.host) && ipMatch( mapEntry.ip, req.socket ? req.socket.localAddress : undefined, diff --git a/src/utils/matchHostname.js b/src/utils/matchHostname.js new file mode 100644 index 0000000..5638c07 --- /dev/null +++ b/src/utils/matchHostname.js @@ -0,0 +1,24 @@ +function matchHostname(hostname, reqHostname) { + if (typeof hostname == "undefined" || hostname == "*") { + return true; + } else if ( + reqHostname && + hostname.indexOf("*.") == 0 && + hostname != "*." + ) { + const hostnamesRoot = hostname.substring(2); + if ( + reqHostname == hostnamesRoot || + (reqHostname.length > hostnamesRoot.length && + reqHostname.indexOf("." + hostnamesRoot) == + reqHostname.length - hostnamesRoot.length - 1) + ) { + return true; + } + } else if (reqHostname && reqHostname == hostname) { + return true; + } + return false; +}; + +module.exports = matchHostname; \ No newline at end of file diff --git a/tests/utils/matchHostname.test.js b/tests/utils/matchHostname.test.js new file mode 100644 index 0000000..a57537c --- /dev/null +++ b/tests/utils/matchHostname.test.js @@ -0,0 +1,51 @@ +const matchHostname = require('../../src/utils/matchHostname'); + +describe('matchHostname', () => { + test('should return true if hostname is undefined', () => { + expect(matchHostname(undefined, 'example.com')).toBe(true); + }); + + test('should return true if hostname is "*"', () => { + expect(matchHostname('*', 'example.com')).toBe(true); + }); + + test('should return true if reqHostname matches hostname exactly', () => { + expect(matchHostname('example.com', 'example.com')).toBe(true); + }); + + test('should return false if reqHostname does not match hostname exactly', () => { + expect(matchHostname('example.com', 'example.org')).toBe(false); + }); + + test('should return true if hostname starts with "*." and reqHostname matches the root', () => { + expect(matchHostname('*.example.com', 'sub.example.com')).toBe(true); + }); + + test('should return false if hostname starts with "*." and reqHostname does not match the root', () => { + expect(matchHostname('*.example.com', 'example.org')).toBe(false); + }); + + test('should return true if hostname starts with "*." and reqHostname is the root', () => { + expect(matchHostname('*.example.com', 'example.com')).toBe(true); + }); + + test('should return false if hostname is "*."', () => { + expect(matchHostname('*.', 'example.com')).toBe(false); + }); + + test('should return false if reqHostname is undefined', () => { + expect(matchHostname('example.com', undefined)).toBe(false); + }); + + test('should return false if hostname does not start with "*." and reqHostname does not match', () => { + expect(matchHostname('sub.example.com', 'example.com')).toBe(false); + }); + + test('should return true if hostname starts with "*." and reqHostname matches the root with additional subdomains', () => { + expect(matchHostname('*.example.com', 'sub.sub.example.com')).toBe(true); + }); + + test('should return false if hostname starts with "*." and reqHostname does not match the root with additional subdomains', () => { + expect(matchHostname('*.example.com', 'sub.sub.example.org')).toBe(false); + }); +});