diff --git a/include/crow/http_response.h b/include/crow/http_response.h index 3ff27ff22..505c7c3f1 100644 --- a/include/crow/http_response.h +++ b/include/crow/http_response.h @@ -217,6 +217,7 @@ namespace crow ///Return a static file as the response body void set_static_file_info(std::string path) { + utility::sanitize_filename(path); file_info.path = path; file_info.statResult = stat(file_info.path.c_str(), &file_info.statbuf); #ifdef CROW_ENABLE_COMPRESSION diff --git a/include/crow/mustache.h b/include/crow/mustache.h index d5d0cb751..79a677481 100644 --- a/include/crow/mustache.h +++ b/include/crow/mustache.h @@ -6,6 +6,8 @@ #include #include "crow/json.h" #include "crow/logging.h" +#include "crow/utility.h" + namespace crow { namespace mustache @@ -144,6 +146,8 @@ namespace crow case '"': out += """; break; case '\'': out += "'"; break; case '/': out += "/"; break; + case '`': out += "`"; break; + case '=': out += "="; break; default: out += *it; break; } } @@ -633,7 +637,9 @@ namespace crow inline template_t load(const std::string& filename) { - return compile(detail::get_loader_ref()(filename)); + std::string filename_sanitized(filename); + utility::sanitize_filename(filename_sanitized); + return compile(detail::get_loader_ref()(filename_sanitized)); } } // namespace mustache } // namespace crow diff --git a/include/crow/utility.h b/include/crow/utility.h index f4f5c66f8..40eaefcf0 100644 --- a/include/crow/utility.h +++ b/include/crow/utility.h @@ -9,6 +9,8 @@ #include #include +#include + #include "crow/settings.h" namespace crow @@ -16,10 +18,12 @@ namespace crow namespace black_magic { #ifndef CROW_MSVC_WORKAROUND + /// Out of Range Exception for const_str struct OutOfRange { OutOfRange(unsigned /*pos*/, unsigned /*length*/) {} }; + /// Helper function to throw an exception if i is larger than len constexpr unsigned requires_in_range(unsigned i, unsigned len) { return i >= len ? throw OutOfRange(i, len) : i; @@ -62,6 +66,7 @@ namespace crow return s[p] == '>' ? p : find_closing_tag(s, p + 1); } + /// Check that the CROW_ROUTE string is valid constexpr bool is_valid(const_str s, unsigned i = 0, int f = 0) { return i == s.size() ? f == 0 : @@ -613,5 +618,128 @@ namespace crow return base64decode(data.c_str(), size, urlsafe); } + inline static void sanitize_filename(std::string& data, char replacement = '_') + { + unsigned char i = 0, length_limit; + + length_limit = data.length() < 255 ? data.length() : 255; + data = data.substr(0, length_limit); + + for (; i < length_limit; i++) + { + switch ((unsigned char)data[i]) + { + // WARNING While I can't see how using '\' or '/' would cause a problem, it still warrants an investigation + //case '/': + case '?': + case '<': + case '>': + //case '\\': + case ':': + case '*': + case '|': + case '\"': + + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9a: + case 0x9b: + case 0x9c: + case 0x9d: + case 0x9e: + case 0x9f: + + data[i] = replacement; + break; + + default: + break; + } + } + std::string str_replacement(1, replacement); + + boost::ireplace_all(data, "..", str_replacement); + + boost::ireplace_all(data, "CON", str_replacement); + boost::ireplace_all(data, "PRN", str_replacement); + boost::ireplace_all(data, "AUX", str_replacement); + boost::ireplace_all(data, "NUL", str_replacement); + boost::ireplace_all(data, "COM1", str_replacement); + boost::ireplace_all(data, "COM2", str_replacement); + boost::ireplace_all(data, "COM3", str_replacement); + boost::ireplace_all(data, "COM4", str_replacement); + boost::ireplace_all(data, "COM5", str_replacement); + boost::ireplace_all(data, "COM6", str_replacement); + boost::ireplace_all(data, "COM7", str_replacement); + boost::ireplace_all(data, "COM8", str_replacement); + boost::ireplace_all(data, "COM9", str_replacement); + boost::ireplace_all(data, "LPT1", str_replacement); + boost::ireplace_all(data, "LPT2", str_replacement); + boost::ireplace_all(data, "LPT3", str_replacement); + boost::ireplace_all(data, "LPT4", str_replacement); + boost::ireplace_all(data, "LPT5", str_replacement); + boost::ireplace_all(data, "LPT6", str_replacement); + boost::ireplace_all(data, "LPT7", str_replacement); + boost::ireplace_all(data, "LPT8", str_replacement); + boost::ireplace_all(data, "LPT9", str_replacement); + } + } // namespace utility } // namespace crow