1
0
Fork 0
forked from svrjs/svrjs

Optimize URL sanitizer

This commit is contained in:
Dorian Niemiec 2024-08-28 16:17:06 +02:00
parent 7fe503c07d
commit 82b0510774

View file

@ -1,43 +1,50 @@
// SVR.JS path sanitizer function // SVR.JS path sanitizer function
function sanitizeURL(resource, allowDoubleSlashes) { function sanitizeURL(resource, allowDoubleSlashes) {
if (resource == "*" || resource == "") return resource; if (resource === "*" || resource === "") return resource;
// Remove null characters // Remove null characters
resource = resource.replace(/%00|\0/g, ""); resource = resource.replace(/%00|\0/g, "");
// Check if URL is malformed (e.g. %c0%af or %u002f or simply %as) // Check if URL is malformed (e.g. %c0%af or %u002f or simply %as)
if (resource.match(/%(?:c[01]|f[ef]|(?![0-9a-f]{2}).{2}|.{0,1}$)/i)) if (resource.match(/%(?:c[01]|f[ef]|(?![0-9a-f]{2}).{2}|.{0,1}$)/i))
throw new URIError("URI malformed"); throw new URIError("URI malformed");
// Decode URL-encoded characters while preserving certain characters // Decode URL-encoded characters while preserving certain characters
resource = resource.replace(/%([0-9a-f]{2})/gi, (match, hex) => { resource = resource.replace(/%([0-9a-f]{2})/gi, (match, hex) => {
const decodedChar = String.fromCharCode(parseInt(hex, 16)); const decodedChar = String.fromCharCode(parseInt(hex, 16));
return /(?!["<>^`{|}?#%])[!-~]/.test(decodedChar) ? decodedChar : "%" + hex; return /[!$&-;=@-\]_a-z~]/.test(decodedChar) ? decodedChar : match;
}); });
// Encode certain characters // Encode certain characters
resource = resource.replace(/[<>^`{|}]]/g, (character) => { resource = resource.replace(/[<>^`{|}]/g, (character) => {
const charCode = character.charCodeAt(0); const charCode = character.charCodeAt(0);
return ( return (
"%" + (charCode < 16 ? "0" : "") + charCode.toString(16).toUpperCase() "%" + (charCode < 16 ? "0" : "") + charCode.toString(16).toUpperCase()
); );
}); });
let sanitizedResource = resource;
// Ensure the resource starts with a slash // Ensure the resource starts with a slash
if (resource[0] != "/") sanitizedResource = "/" + sanitizedResource; if (resource[0] !== "/") resource = "/" + resource;
// Convert backslashes to slashes and handle duplicate slashes // Convert backslashes to slashes and handle duplicate slashes
sanitizedResource = sanitizedResource resource = resource
.replace(/\\/g, "/") .replace(/\\/g, "/")
.replace(allowDoubleSlashes ? /\/{3,}/g : /\/+/g, "/"); .replace(allowDoubleSlashes ? /\/{3,}/g : /\/+/g, "/");
// Handle relative navigation (e.g., "/./", "/../", "../", "./"), also remove trailing dots in paths
sanitizedResource = sanitizedResource // Handle relative navigation (e.g., "/./", "/../", "../", "./") and remove trailing dots in paths
resource = resource
.replace(/\/\.(?:\.{2,})?(?=\/|$)/g, "") .replace(/\/\.(?:\.{2,})?(?=\/|$)/g, "")
.replace(/([^./])\.+(?=\/|$)/g, "$1"); .replace(/([^./])\.+(?=\/|$)/g, "$1");
while (sanitizedResource.match(/\/(?!\.\.\/)[^/]+\/\.\.(?=\/|$)/)) {
sanitizedResource = sanitizedResource.replace( // Remove remaining "../"
/\/(?!\.\.\/)[^/]+\/\.\.(?=\/|$)/g, while (resource.match(/\/(?!\.\.\/)[^/]+\/\.\.(?=\/|$)/)) {
"", resource = resource.replace(/\/(?!\.\.\/)[^/]+\/\.\.(?=\/|$)/g, "");
);
} }
sanitizedResource = sanitizedResource.replace(/\/\.\.(?=\/|$)/g, ""); resource = resource.replace(/\/\.\.(?=\/|$)/g, "");
if (sanitizedResource.length == 0) return "/";
else return sanitizedResource; // If the result has length of 0, return "/", else return the sanitized URL
if (resource.length == 0) return "/";
else return resource;
} }
module.exports = sanitizeURL; module.exports = sanitizeURL;