[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
This commit is contained in:
TheApadayo 2017-06-19 15:39:48 -04:00
parent 6409b55135
commit 491cf4caf8
3 changed files with 71 additions and 13 deletions

View File

@ -11,12 +11,12 @@ namespace Components
#pragma region Client #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; if (Download::CLDownload.running) return;
@ -29,6 +29,20 @@ namespace Components
Command::Execute("openmenu mod_download_popmenu", false); Command::Execute("openmenu mod_download_popmenu", false);
if (needPassword)
{
std::string pass = Dvar::Var("password").get<std::string>();
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.running = true;
Download::CLDownload.isMap = map; Download::CLDownload.isMap = map;
Download::CLDownload.mod = mod; 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; Download::FileDownload fDownload;
fDownload.file = file; fDownload.file = file;
@ -233,7 +248,9 @@ namespace Components
std::string host = "http://" + download->target.getString(); 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 (list.empty())
{ {
if (download->terminateThread) return; if (download->terminateThread) return;
@ -361,6 +378,33 @@ namespace Components
return nullptr; return nullptr;
} }
bool Download::VerifyPassword(mg_connection *nc, http_message* message)
{
std::string g_password = Dvar::Var("g_password").get<std::string>();
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<char>(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) void Download::Forbid(mg_connection *nc)
{ {
mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n" mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n"
@ -372,11 +416,13 @@ namespace Components
nc->flags |= MG_F_SEND_AND_CLOSE; 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 // Only handle http requests
if (ev != MG_EV_HTTP_REQUEST) return; if (ev != MG_EV_HTTP_REQUEST) return;
if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return;
static std::string mapnamePre; static std::string mapnamePre;
static json11::Json jsonList; static json11::Json jsonList;
@ -423,11 +469,13 @@ namespace Components
nc->flags |= MG_F_SEND_AND_CLOSE; 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 // Only handle http requests
if (ev != MG_EV_HTTP_REQUEST) return; if (ev != MG_EV_HTTP_REQUEST) return;
if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return;
// if (!Download::IsClient(nc)) // if (!Download::IsClient(nc))
// { // {
// Download::Forbid(nc); // Download::Forbid(nc);
@ -487,6 +535,8 @@ namespace Components
http_message* message = reinterpret_cast<http_message*>(ev_data); http_message* message = reinterpret_cast<http_message*>(ev_data);
//if (!Download::VerifyPassword(nc, message)) return;
// if (!Download::IsClient(nc)) // if (!Download::IsClient(nc))
// { // {
// Download::Forbid(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 // Only handle http requests
if (ev != MG_EV_HTTP_REQUEST) return; if (ev != MG_EV_HTTP_REQUEST) return;
//http_message* message = reinterpret_cast<http_message*>(ev_data); //if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return;
Utils::InfoString status = ServerInfo::GetInfo(); Utils::InfoString status = ServerInfo::GetInfo();

View File

@ -11,8 +11,8 @@ namespace Components
void preDestroy() override; void preDestroy() override;
static void InitiateClientDownload(std::string mod, bool map = false); static void InitiateClientDownload(std::string mod, bool needPassword, bool map = false);
static void InitiateMapDownload(std::string map); static void InitiateMapDownload(std::string map, bool needPassword);
private: private:
class ClientDownload class ClientDownload
@ -25,8 +25,10 @@ namespace Components
bool valid; bool valid;
bool terminateThread; bool terminateThread;
bool isMap; bool isMap;
bool isPrivate;
mg_mgr mgr; mg_mgr mgr;
Network::Address target; Network::Address target;
std::string hashedPassword;
std::string mod; std::string mod;
std::thread thread; std::thread thread;
@ -209,6 +211,8 @@ namespace Components
static std::thread ServerThread; static std::thread ServerThread;
static bool Terminate; 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 EventHandler(mg_connection *nc, int ev, void *ev_data);
static void ListHandler(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); static void MapHandler(mg_connection *nc, int ev, void *ev_data);

View File

@ -415,15 +415,19 @@ namespace Components
{ {
Party::ConnectError("Invalid map or gametype."); Party::ConnectError("Invalid map or gametype.");
} }
else if (Party::Container.info.get("isPrivate") == "1"s && !Dvar::Var("password").get<std::string>().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"))) else if (isUsermap && usermapHash != Maps::GetUsermapHash(info.get("mapname")))
{ {
Command::Execute("closemenu popup_reconnectingtoparty"); 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"))) else if (!info.get("fs_game").empty() && Utils::String::ToLower(mod) != Utils::String::ToLower(info.get("fs_game")))
{ {
Command::Execute("closemenu popup_reconnectingtoparty"); 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<std::string>().empty() && info.get("fs_game").empty()) else if (!Dvar::Var("fs_game").get<std::string>().empty() && info.get("fs_game").empty())
{ {