1
0
Fork 0
forked from svrjs/svrjs

Prepare for double slash URL support

This commit is contained in:
Dorian Niemiec 2024-03-02 21:54:07 +01:00
parent bd5ab63954
commit 28d633884e

31
svr.js
View file

@ -3328,17 +3328,19 @@ if (!cluster.isPrimary) {
// Function to parse a URL string into a URL object // Function to parse a URL string into a URL object
function parseURL(uri) { function parseURL(uri) {
// Prepare the path (remove multiple slashes)
var preparedURI = uri.replace(/^\/{2,}/,"/");
// Check if the URL API is available (Node.js version >= 10) // Check if the URL API is available (Node.js version >= 10)
if (typeof URL !== "undefined" && url.Url) { if (typeof URL !== "undefined" && url.Url) {
try { try {
// Create a new URL object using the provided URI and base URL // Create a new URL object using the provided URI and base URL
var uobject = new URL(uri.replace(/^\/{2,}/,"/"), "http" + (req.socket.encrypted ? "s" : "") + "://" + (req.headers.host ? req.headers.host : (domain ? domain : "unknown.invalid"))); var uobject = new URL(preparedURI, "http" + (req.socket.encrypted ? "s" : "") + "://" + (req.headers.host ? req.headers.host : (domain ? domain : "unknown.invalid")));
// Create a new URL object (similar to deprecated url.Url) // Create a new URL object (similar to deprecated url.Url)
var nuobject = new url.Url(); var nuobject = new url.Url();
// Set properties of the new URL object from the provided URL // Set properties of the new URL object from the provided URL
if (uri.indexOf("/") != -1) nuobject.slashes = true; if (preparedURI.indexOf("/") != -1) nuobject.slashes = true;
if (uobject.protocol != "") nuobject.protocol = uobject.protocol; if (uobject.protocol != "") nuobject.protocol = uobject.protocol;
if (uobject.username != "" && uobject.password != "") nuobject.auth = uobject.username + ":" + uobject.password; if (uobject.username != "" && uobject.password != "") nuobject.auth = uobject.username + ":" + uobject.password;
if (uobject.host != "") nuobject.host = uobject.host; if (uobject.host != "") nuobject.host = uobject.host;
@ -3350,7 +3352,7 @@ if (!cluster.isPrimary) {
if (uobject.href != "") nuobject.href = uobject.href; if (uobject.href != "") nuobject.href = uobject.href;
// Adjust the pathname and href properties if the URI doesn't start with "/" // Adjust the pathname and href properties if the URI doesn't start with "/"
if (uri.indexOf("/") != 0) { if (preparedURI.indexOf("/") != 0) {
if (nuobject.pathname) { if (nuobject.pathname) {
nuobject.pathname = nuobject.pathname.substr(1); nuobject.pathname = nuobject.pathname.substr(1);
nuobject.href = nuobject.pathname + (nuobject.search ? nuobject.search : ""); nuobject.href = nuobject.pathname + (nuobject.search ? nuobject.search : "");
@ -3372,11 +3374,11 @@ if (!cluster.isPrimary) {
return nuobject; return nuobject;
} catch (err) { } catch (err) {
// If there was an error using the URL API, fall back to deprecated url.parse // If there was an error using the URL API, fall back to deprecated url.parse
return url.parse(uri, true); return url.parse(preparedURI, true);
} }
} else { } else {
// If the URL API is not available, fall back to deprecated url.parse // If the URL API is not available, fall back to deprecated url.parse
return url.parse(uri, true); return url.parse(preparedURI, true);
} }
} }
@ -4313,6 +4315,7 @@ if (!cluster.isPrimary) {
doCallback = false; doCallback = false;
break; break;
} }
if (!mapEntry.allowDoubleSlashes) address = address.replace(/\/+/g,"/");
if (matchHostname(mapEntry.host) && ipMatch(mapEntry.ip, req.socket ? req.socket.localAddress : undefined) && address.match(createRegex(mapEntry.definingRegex)) && !(mapEntry.isNotDirectory && _fileState == 2) && !(mapEntry.isNotFile && _fileState == 1)) { if (matchHostname(mapEntry.host) && ipMatch(mapEntry.ip, req.socket ? req.socket.localAddress : undefined) && address.match(createRegex(mapEntry.definingRegex)) && !(mapEntry.isNotDirectory && _fileState == 2) && !(mapEntry.isNotFile && _fileState == 1)) {
try { try {
mapEntry.replacements.forEach(function (replacement) { mapEntry.replacements.forEach(function (replacement) {
@ -4510,24 +4513,27 @@ if (!cluster.isPrimary) {
}); });
} }
// Prepare the path (remove multiple slashes)
var decodedHrefWithoutDuplicateSlashes = decodedHref.replace(/\/+/g,"/");
// Check if path is forbidden // Check if path is forbidden
if ((isForbiddenPath(decodedHref, "config") || isForbiddenPath(decodedHref, "certificates")) && !isProxy) { if ((isForbiddenPath(decodedHrefWithoutDuplicateSlashes, "config") || isForbiddenPath(decodedHrefWithoutDuplicateSlashes, "certificates")) && !isProxy) {
callServerError(403); callServerError(403);
serverconsole.errmessage("Access to configuration file/certificates is denied."); serverconsole.errmessage("Access to configuration file/certificates is denied.");
return; return;
} else if (isIndexOfForbiddenPath(decodedHref, "temp") && !isProxy) { } else if (isIndexOfForbiddenPath(decodedHrefWithoutDuplicateSlashes, "temp") && !isProxy) {
callServerError(403); callServerError(403);
serverconsole.errmessage("Access to temporary folder is denied."); serverconsole.errmessage("Access to temporary folder is denied.");
return; return;
} else if (isIndexOfForbiddenPath(decodedHref, "log") && !isProxy && (configJSON.enableLogging || configJSON.enableLogging == undefined) && !configJSON.enableRemoteLogBrowsing) { } else if (isIndexOfForbiddenPath(decodedHrefWithoutDuplicateSlashes, "log") && !isProxy && (configJSON.enableLogging || configJSON.enableLogging == undefined) && !configJSON.enableRemoteLogBrowsing) {
callServerError(403); callServerError(403);
serverconsole.errmessage("Access to log files is denied."); serverconsole.errmessage("Access to log files is denied.");
return; return;
} else if (isForbiddenPath(decodedHref, "svrjs") && !isProxy && !exposeServerVersion) { } else if (isForbiddenPath(decodedHrefWithoutDuplicateSlashes, "svrjs") && !isProxy && !exposeServerVersion) {
callServerError(403); callServerError(403);
serverconsole.errmessage("Access to SVR.JS script is denied."); serverconsole.errmessage("Access to SVR.JS script is denied.");
return; return;
} else if ((isForbiddenPath(decodedHref, "svrjs") || isForbiddenPath(decodedHref, "serverSideScripts") || isIndexOfForbiddenPath(decodedHref, "serverSideScriptDirectories")) && !isProxy && (configJSON.disableServerSideScriptExpose || configJSON.disableServerSideScriptExpose === undefined)) { } else if ((isForbiddenPath(decodedHrefWithoutDuplicateSlashes, "svrjs") || isForbiddenPath(decodedHrefWithoutDuplicateSlashes, "serverSideScripts") || isIndexOfForbiddenPath(decodedHrefWithoutDuplicateSlashes, "serverSideScriptDirectories")) && !isProxy && (configJSON.disableServerSideScriptExpose || configJSON.disableServerSideScriptExpose === undefined)) {
callServerError(403); callServerError(403);
serverconsole.errmessage("Access to sources is denied."); serverconsole.errmessage("Access to sources is denied.");
return; return;
@ -4541,14 +4547,15 @@ if (!cluster.isPrimary) {
for (var i = 0; i < nonStandardCodes.length; i++) { for (var i = 0; i < nonStandardCodes.length; i++) {
if (matchHostname(nonStandardCodes[i].host) && ipMatch(nonStandardCodes[i].ip, req.socket ? req.socket.localAddress : undefined)) { if (matchHostname(nonStandardCodes[i].host) && ipMatch(nonStandardCodes[i].ip, req.socket ? req.socket.localAddress : undefined)) {
var isMatch = false; var isMatch = false;
var hrefWithoutDuplicateSlashes = href.replace(/\/+/g,"/");
if (nonStandardCodes[i].regex) { if (nonStandardCodes[i].regex) {
// Regex match // Regex match
var createdRegex = createRegex(nonStandardCodes[i].regex, true); var createdRegex = createRegex(nonStandardCodes[i].regex, true);
isMatch = req.url.match(createdRegex) || href.match(createdRegex); isMatch = req.url.match(createdRegex) || hrefWithoutDuplicateSlashes.match(createdRegex);
regexI[i] = createdRegex; regexI[i] = createdRegex;
} else { } else {
// Non-regex match // Non-regex match
isMatch = nonStandardCodes[i].url == href || (os.platform() == "win32" && nonStandardCodes[i].url.toLowerCase() == href.toLowerCase()); isMatch = nonStandardCodes[i].url == hrefWithoutDuplicateSlashes || (os.platform() == "win32" && nonStandardCodes[i].url.toLowerCase() == hrefWithoutDuplicateSlashes.toLowerCase());
} }
if (isMatch) { if (isMatch) {
if (nonStandardCodes[i].scode == 401) { if (nonStandardCodes[i].scode == 401) {