From d1dd4af6af1f81fb7ffde7cd0938b68ebd6fae23 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sat, 13 Jan 2024 13:15:16 +0100 Subject: [PATCH 1/5] fix(download): restore password verification --- src/Components/Modules/Download.cpp | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 43433425..927f4946 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -462,6 +462,40 @@ namespace Components mg_http_reply(connection, 200, formatted.c_str(), "%s", data.c_str()); } + bool VerifyPassword([[maybe_unused]] mg_connection* c, [[maybe_unused]] const mg_http_message* hm) + { + const std::string g_password = *Game::g_password ? (*Game::g_password)->current.string : ""; + if (g_password.empty()) return true; + + // SHA256 hashes are 64 characters long but we're gonna be safe here + char buffer[128]{}; + const auto len = mg_http_get_var(&hm->query, "password", buffer, sizeof(buffer)); + + const auto reply = [&c](const char* s) -> void + { + mg_printf(c, "%s", "HTTP/1.1 403 Forbidden\r\n"); + mg_printf(c, "%s", "Content-Type: text/plain\r\n"); + mg_printf(c, "Connection: close\r\n"); + mg_printf(c, "%s", "\r\n"); + mg_printf(c, "%s", s); + }; + + if (len <= 0) + { + reply("Password Required"); + return false; + } + + const auto password = std::string(buffer, len); + if (password != Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(g_password), "")) + { + reply("Invalid Password"); + return false; + } + + return true; + } + std::optional Download::InfoHandler([[maybe_unused]] mg_connection* c, [[maybe_unused]] const mg_http_message* hm) { if (!(*Game::com_sv_running)->current.enabled) @@ -524,6 +558,12 @@ namespace Components static nlohmann::json jsonList; static std::filesystem::path fsGamePre; + if (!VerifyPassword(c, hm)) + { + // Custom reply done in VerifyPassword + return {}; + } + const std::filesystem::path fsGame = (*Game::fs_gameDirVar)->current.string; if (!fsGame.empty() && (fsGamePre != fsGame)) @@ -572,6 +612,12 @@ namespace Components static std::string mapNamePre; static nlohmann::json jsonList; + if (!VerifyPassword(c, hm)) + { + // Custom reply done in VerifyPassword + return {}; + } + const std::string mapName = Party::IsInUserMapLobby() ? (*Game::ui_mapname)->current.string : Maps::GetUserMap()->getName(); if (!Maps::GetUserMap()->isValid() && !Party::IsInUserMapLobby()) { From c6762826dcf3a6205fc2742046515db0a853bd6c Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sat, 20 Jan 2024 13:57:59 +0100 Subject: [PATCH 2/5] address review --- src/Components/Modules/Download.cpp | 20 ++++++++------------ src/Components/Modules/Download.hpp | 2 +- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 927f4946..f70f53fa 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -435,7 +435,7 @@ namespace Components MongooseLogBuffer.push_back(c); } - void Download::ReplyError(mg_connection* connection, int code) + void Download::ReplyError(mg_connection* connection, int code, std::string messageOverride) { std::string msg{}; switch(code) @@ -453,6 +453,11 @@ namespace Components break; } + if (!messageOverride.empty()) + { + msg = message; + } + mg_http_reply(connection, code, "Content-Type: text/plain\r\n", "%s", msg.c_str()); } @@ -471,25 +476,16 @@ namespace Components char buffer[128]{}; const auto len = mg_http_get_var(&hm->query, "password", buffer, sizeof(buffer)); - const auto reply = [&c](const char* s) -> void - { - mg_printf(c, "%s", "HTTP/1.1 403 Forbidden\r\n"); - mg_printf(c, "%s", "Content-Type: text/plain\r\n"); - mg_printf(c, "Connection: close\r\n"); - mg_printf(c, "%s", "\r\n"); - mg_printf(c, "%s", s); - }; - if (len <= 0) { - reply("Password Required"); + ReplyError(connection, 403, "Password Required"); return false; } const auto password = std::string(buffer, len); if (password != Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(g_password), "")) { - reply("Invalid Password"); + ReplyError(connection, 403, "Invalid Password"); return false; } diff --git a/src/Components/Modules/Download.hpp b/src/Components/Modules/Download.hpp index b4e4dde1..d93ac94f 100644 --- a/src/Components/Modules/Download.hpp +++ b/src/Components/Modules/Download.hpp @@ -105,7 +105,7 @@ namespace Components static bool DownloadFile(ClientDownload* download, unsigned int index); static void LogFn(char c, void* param); - static void ReplyError(mg_connection* connection, int code); + static void ReplyError(mg_connection* connection, int code, std::string messageOverride = {}); static void Reply(mg_connection* connection, const std::string& contentType, const std::string& data); static std::optional FileHandler(mg_connection* c, const mg_http_message* hm); From 8ed849bf53925329a9b50ff2fd7bb89b0cc3d991 Mon Sep 17 00:00:00 2001 From: Edo Date: Sat, 20 Jan 2024 14:10:58 +0100 Subject: [PATCH 3/5] Update Download.cpp --- src/Components/Modules/Download.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index f70f53fa..6910e4c5 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -455,7 +455,7 @@ namespace Components if (!messageOverride.empty()) { - msg = message; + msg = messageOverride; } mg_http_reply(connection, code, "Content-Type: text/plain\r\n", "%s", msg.c_str()); @@ -478,14 +478,14 @@ namespace Components if (len <= 0) { - ReplyError(connection, 403, "Password Required"); + ReplyError(c, 403, "Password Required"); return false; } const auto password = std::string(buffer, len); if (password != Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(g_password), "")) { - ReplyError(connection, 403, "Invalid Password"); + ReplyError(c, 403, "Invalid Password"); return false; } From 45cfea133bb160df672efd5fbfc236e909b479de Mon Sep 17 00:00:00 2001 From: Edo Date: Sat, 20 Jan 2024 14:15:12 +0100 Subject: [PATCH 4/5] Update Download.cpp --- src/Components/Modules/Download.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 6910e4c5..237c3ef9 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -478,14 +478,14 @@ namespace Components if (len <= 0) { - ReplyError(c, 403, "Password Required"); + Download::ReplyError(c, 403, "Password Required"); return false; } const auto password = std::string(buffer, len); if (password != Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(g_password), "")) { - ReplyError(c, 403, "Invalid Password"); + Download::ReplyError(c, 403, "Invalid Password"); return false; } From b81c1b4e0685d52636d0f1225507c653abef9758 Mon Sep 17 00:00:00 2001 From: Edo Date: Sat, 20 Jan 2024 14:20:44 +0100 Subject: [PATCH 5/5] Update Download.hpp --- src/Components/Modules/Download.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/Download.hpp b/src/Components/Modules/Download.hpp index d93ac94f..09b5702e 100644 --- a/src/Components/Modules/Download.hpp +++ b/src/Components/Modules/Download.hpp @@ -17,6 +17,8 @@ namespace Components static void InitiateClientDownload(const std::string& mod, bool needPassword, bool map = false); static void InitiateMapDownload(const std::string& map, bool needPassword); + static void ReplyError(mg_connection* connection, int code, std::string messageOverride = {}); + static Dvar::Var SV_wwwDownload; static Dvar::Var SV_wwwBaseUrl; @@ -105,7 +107,6 @@ namespace Components static bool DownloadFile(ClientDownload* download, unsigned int index); static void LogFn(char c, void* param); - static void ReplyError(mg_connection* connection, int code, std::string messageOverride = {}); static void Reply(mg_connection* connection, const std::string& contentType, const std::string& data); static std::optional FileHandler(mg_connection* c, const mg_http_message* hm);