From 491cf4caf8c28459fb7a1ab752c6428ce1f9cdd0 Mon Sep 17 00:00:00 2001 From: TheApadayo Date: Mon, 19 Jun 2017 15:39:48 -0400 Subject: [PATCH] [Download] Don't allow downloading of mod files when the client provides an invalid password -also don't even leave the menu if there is no password set when connecting to a private server --- src/Components/Modules/Download.cpp | 68 +++++++++++++++++++++++++---- src/Components/Modules/Download.hpp | 8 +++- src/Components/Modules/Party.cpp | 8 +++- 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 85e6f59a..27d1439a 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -11,12 +11,12 @@ namespace Components #pragma region Client - void Download::InitiateMapDownload(std::string map) + void Download::InitiateMapDownload(std::string map, bool needPassword) { - Download::InitiateClientDownload(map, true); + Download::InitiateClientDownload(map, needPassword, true); } - void Download::InitiateClientDownload(std::string mod, bool map) + void Download::InitiateClientDownload(std::string mod, bool needPassword, bool map) { if (Download::CLDownload.running) return; @@ -29,6 +29,20 @@ namespace Components Command::Execute("openmenu mod_download_popmenu", false); + if (needPassword) + { + std::string pass = Dvar::Var("password").get(); + if (!pass.length()) + { + // shouldn't ever happen but this is safe + Party::ConnectError("A password is required to connect to this server!"); + return; + } + + Download::CLDownload.isPrivate = needPassword; + Download::CLDownload.hashedPassword = Utils::Cryptography::SHA256::Compute(pass); + } + Download::CLDownload.running = true; Download::CLDownload.isMap = map; Download::CLDownload.mod = mod; @@ -192,7 +206,8 @@ namespace Components } } - std::string url = "http://" + download->target.getString() + "/file/" + (download->isMap ? "map/" : "") + file.name; + std::string url = "http://" + download->target.getString() + "/file/" + (download->isMap ? "map/" : "") + file.name + + (download->isPrivate ? ("?password=" + download->hashedPassword) : ""); Download::FileDownload fDownload; fDownload.file = file; @@ -233,7 +248,9 @@ namespace Components std::string host = "http://" + download->target.getString(); - std::string list = Utils::WebIO("IW4x", host + (download->isMap ? "/map" : "/list")).setTimeout(5000)->get(); + std::string listUrl = host + (download->isMap ? "/map" : "/list") + (download->isPrivate ? ("?password=" + download->hashedPassword) : ""); + + std::string list = Utils::WebIO("IW4x", listUrl).setTimeout(5000)->get(); if (list.empty()) { if (download->terminateThread) return; @@ -361,6 +378,33 @@ namespace Components return nullptr; } + bool Download::VerifyPassword(mg_connection *nc, http_message* message) + { + std::string g_password = Dvar::Var("g_password").get(); + + if (!g_password.size()) return true; + + Utils::Memory::Allocator* alloc = Utils::Memory::GetAllocator(); + + // sha256 hashes are 64 chars long but we're gonna be safe here + char* buffer = alloc->allocateArray(128); + int passLen = mg_get_http_var(&message->query_string, "password", buffer, 128); + + if (passLen <= 0 || std::string(buffer, passLen) != g_password)//Utils::Cryptography::SHA256::Compute(g_password)) + { + mg_printf(nc, ("HTTP/1.1 403 Forbidden\r\n"s + + "Content-Type: text/html\r\n"s + + "Connection: close\r\n"s + + "\r\n"s + + ((passLen == 0) ? "Password Required"s : "Invalid Password"s)).c_str()); + + nc->flags |= MG_F_SEND_AND_CLOSE; + return false; + } + + return true; + } + void Download::Forbid(mg_connection *nc) { mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n" @@ -372,11 +416,13 @@ namespace Components nc->flags |= MG_F_SEND_AND_CLOSE; } - void Download::MapHandler(mg_connection *nc, int ev, void* /*ev_data*/) + void Download::MapHandler(mg_connection *nc, int ev, void* ev_data) { // Only handle http requests if (ev != MG_EV_HTTP_REQUEST) return; + if (!Download::VerifyPassword(nc, reinterpret_cast(ev_data))) return; + static std::string mapnamePre; static json11::Json jsonList; @@ -423,11 +469,13 @@ namespace Components nc->flags |= MG_F_SEND_AND_CLOSE; } - void Download::ListHandler(mg_connection* nc, int ev, void* /*ev_data*/) + void Download::ListHandler(mg_connection* nc, int ev, void* ev_data) { // Only handle http requests if (ev != MG_EV_HTTP_REQUEST) return; + if (!Download::VerifyPassword(nc, reinterpret_cast(ev_data))) return; + // if (!Download::IsClient(nc)) // { // Download::Forbid(nc); @@ -487,6 +535,8 @@ namespace Components http_message* message = reinterpret_cast(ev_data); + //if (!Download::VerifyPassword(nc, message)) return; + // if (!Download::IsClient(nc)) // { // Download::Forbid(nc); @@ -567,12 +617,12 @@ namespace Components } } - void Download::InfoHandler(mg_connection* nc, int ev, void* /*ev_data*/) + void Download::InfoHandler(mg_connection* nc, int ev, void* ev_data) { // Only handle http requests if (ev != MG_EV_HTTP_REQUEST) return; - //http_message* message = reinterpret_cast(ev_data); + //if (!Download::VerifyPassword(nc, reinterpret_cast(ev_data))) return; Utils::InfoString status = ServerInfo::GetInfo(); diff --git a/src/Components/Modules/Download.hpp b/src/Components/Modules/Download.hpp index 186f237e..911e983e 100644 --- a/src/Components/Modules/Download.hpp +++ b/src/Components/Modules/Download.hpp @@ -11,8 +11,8 @@ namespace Components void preDestroy() override; - static void InitiateClientDownload(std::string mod, bool map = false); - static void InitiateMapDownload(std::string map); + static void InitiateClientDownload(std::string mod, bool needPassword, bool map = false); + static void InitiateMapDownload(std::string map, bool needPassword); private: class ClientDownload @@ -25,8 +25,10 @@ namespace Components bool valid; bool terminateThread; bool isMap; + bool isPrivate; mg_mgr mgr; Network::Address target; + std::string hashedPassword; std::string mod; std::thread thread; @@ -209,6 +211,8 @@ namespace Components static std::thread ServerThread; static bool Terminate; + static bool VerifyPassword(mg_connection *nc, http_message* message); + static void EventHandler(mg_connection *nc, int ev, void *ev_data); static void ListHandler(mg_connection *nc, int ev, void *ev_data); static void MapHandler(mg_connection *nc, int ev, void *ev_data); diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index fe00e498..bea7413a 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -415,15 +415,19 @@ namespace Components { Party::ConnectError("Invalid map or gametype."); } + else if (Party::Container.info.get("isPrivate") == "1"s && !Dvar::Var("password").get().length()) + { + Party::ConnectError("A password is required to join this server! Set it at the bottom of the serverlist."); + } else if (isUsermap && usermapHash != Maps::GetUsermapHash(info.get("mapname"))) { Command::Execute("closemenu popup_reconnectingtoparty"); - Download::InitiateMapDownload(info.get("mapname")); + Download::InitiateMapDownload(info.get("mapname"), info.get("isPrivate") == "1"); } else if (!info.get("fs_game").empty() && Utils::String::ToLower(mod) != Utils::String::ToLower(info.get("fs_game"))) { Command::Execute("closemenu popup_reconnectingtoparty"); - Download::InitiateClientDownload(info.get("fs_game")); + Download::InitiateClientDownload(info.get("fs_game"), info.get("isPrivate") == "1"s); } else if (!Dvar::Var("fs_game").get().empty() && info.get("fs_game").empty()) {