From 6c145a6dbfaa9887920ae890b2760da0a73fb710 Mon Sep 17 00:00:00 2001 From: rgnter <32541639+rgnter@users.noreply.github.com> Date: Sun, 18 Dec 2022 12:32:45 +0100 Subject: [PATCH 1/7] fix: Bad package name for Ubuntu --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f9a20c7..3134837 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ Ubuntu 22.04 git libz-dev rapidjson-dev -liblua5.3 +liblua5.3-dev libssl-dev libwebsocketpp-dev libcurl4-openssl-dev From 9f59c27b1f37dee9784e0e6acdc9054f57889d38 Mon Sep 17 00:00:00 2001 From: Anonymous275 <36374260+Anonymous-275@users.noreply.github.com> Date: Wed, 21 Dec 2022 22:26:45 +0000 Subject: [PATCH 2/7] - add hash function - add password config - add debug messages for password stages - add pass boolean for heartbeat - adjust network codes --- include/Common.h | 1 + include/TNetwork.h | 1 + src/TConfig.cpp | 4 ++++ src/THeartbeatThread.cpp | 3 ++- src/TNetwork.cpp | 30 +++++++++++++++++++++++++++++- 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/include/Common.h b/include/Common.h index a2bc21f..26d96d7 100644 --- a/include/Common.h +++ b/include/Common.h @@ -49,6 +49,7 @@ public: std::string Resource { "Resources" }; std::string MapName { "/levels/gridmap_v2/info.json" }; std::string Key {}; + std::string Password{}; std::string SSLKeyPath { "./.ssl/HttpServer/key.pem" }; std::string SSLCertPath { "./.ssl/HttpServer/cert.pem" }; bool HTTPServerEnabled { false }; diff --git a/include/TNetwork.h b/include/TNetwork.h index 3b4980e..bf5d12f 100644 --- a/include/TNetwork.h +++ b/include/TNetwork.h @@ -38,6 +38,7 @@ private: std::thread mUDPThread; std::thread mTCPThread; + static std::string Hash(const std::string& str); std::vector UDPRcvFromClient(ip::udp::endpoint& ClientEndpoint); void HandleDownload(TConnection&& TCPSock); void OnConnect(const std::weak_ptr& c); diff --git a/src/TConfig.cpp b/src/TConfig.cpp index 8c93aa4..92316c2 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -18,6 +18,7 @@ static constexpr std::string_view StrDescription = "Description"; static constexpr std::string_view StrResourceFolder = "ResourceFolder"; static constexpr std::string_view StrAuthKey = "AuthKey"; static constexpr std::string_view StrLogChat = "LogChat"; +static constexpr std::string_view StrPassword = "Password"; // Misc static constexpr std::string_view StrSendErrors = "SendErrors"; @@ -106,6 +107,7 @@ void TConfig::FlushToFile() { data["General"][StrMap.data()] = Application::Settings.MapName; data["General"][StrDescription.data()] = Application::Settings.ServerDesc; data["General"][StrResourceFolder.data()] = Application::Settings.Resource; + data["General"][StrPassword.data()] = Application::Settings.Password; // Misc data["Misc"][StrHideUpdateMessages.data()] = Application::Settings.HideUpdateMessages; SetComment(data["Misc"][StrHideUpdateMessages.data()].comments(), " Hides the periodic update message which notifies you of a new server version. You should really keep this on and always update as soon as possible. For more information visit https://wiki.beammp.com/en/home/server-maintenance#updating-the-server. An update message will always appear at startup regardless."); @@ -189,6 +191,7 @@ void TConfig::ParseFromFile(std::string_view name) { TryReadValue(data, "General", StrResourceFolder, Application::Settings.Resource); TryReadValue(data, "General", StrAuthKey, Application::Settings.Key); TryReadValue(data, "General", StrLogChat, Application::Settings.LogChat); + TryReadValue(data, "General", StrPassword, Application::Settings.Password); // Misc TryReadValue(data, "Misc", StrSendErrors, Application::Settings.SendErrors); TryReadValue(data, "Misc", StrHideUpdateMessages, Application::Settings.HideUpdateMessages); @@ -240,6 +243,7 @@ void TConfig::PrintDebug() { beammp_debug(std::string(StrHTTPServerIP) + ": \"" + Application::Settings.HTTPServerIP + "\""); // special! beammp_debug("Key Length: " + std::to_string(Application::Settings.Key.length()) + ""); + beammp_debug("Password Protected: " + std::string(Application::Settings.Password.empty() ? "false" : "true")); } void TConfig::ParseOldFormat() { diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index 873825a..ab0f5a6 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -149,7 +149,8 @@ std::string THeartbeatThread::GenerateCall() { << "&modstotalsize=" << mResourceManager.MaxModSize() << "&modstotal=" << mResourceManager.ModsLoaded() << "&playerslist=" << GetPlayers() - << "&desc=" << Application::Settings.ServerDesc; + << "&desc=" << Application::Settings.ServerDesc + << "&pass=" << (Application::Settings.Password.empty() ? "false" : "true"); return Ret.str(); } THeartbeatThread::THeartbeatThread(TResourceManager& ResourceManager, TServer& Server) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 0b0f024..cf4fec8 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -235,7 +235,8 @@ std::shared_ptr TNetwork::Authentication(TConnection&& RawConnection) { ClientKick(*Client, fmt::format("Invalid version header: '{}' ({})", std::string(reinterpret_cast(Data.data()), Data.size()), Data.size())); return nullptr; } - if (!TCPSend(*Client, StringToVector("S"))) { + + if (!TCPSend(*Client, StringToVector("A"))) { //changed to A for Accepted version // TODO: handle } @@ -322,12 +323,30 @@ std::shared_ptr TNetwork::Authentication(TConnection&& RawConnection) { } if (mServer.ClientCount() < size_t(Application::Settings.MaxPlayers)) { + + if(!Application::Settings.Password.empty()) { // ask password + if(!TCPSend(*Client, StringToVector("S"))) { + // TODO: handle + } + beammp_info("Waiting for password"); + Data = TCPRcv(*Client); + std::string Pass = std::string(reinterpret_cast(Data.data()), Data.size()); + if(Pass != Hash(Application::Settings.Password)) { + beammp_debug(Client->GetName() + " attempted to connect with a wrong password"); + ClientKick(*Client, "Wrong password!"); + return {}; + } else { + beammp_debug(Client->GetName() + " used the correct password"); + } + } + beammp_info("Identification success"); mServer.InsertClient(Client); TCPClient(Client); } else { ClientKick(*Client, "Server full!"); } + return Client; } @@ -943,3 +962,12 @@ std::vector TNetwork::UDPRcvFromClient(ip::udp::endpoint& ClientEndpoin beammp_assert(Rcv <= Ret.size()); return std::vector(Ret.begin(), Ret.begin() + Rcv); } + +std::string TNetwork::Hash(const std::string& str) { + std::stringstream ret; + unsigned char* hash = SHA256(reinterpret_cast(str.c_str()), str.length(), nullptr); + for (int i = 0; i < 32; i++) { + ret << std::hex << (int)hash[i]; + } + return ret.str(); +} From 688e46f524ee64fb10c4fbb8e4a524116f9f674a Mon Sep 17 00:00:00 2001 From: Anonymous275 <36374260+Anonymous-275@users.noreply.github.com> Date: Wed, 21 Dec 2022 22:34:21 +0000 Subject: [PATCH 3/7] - fix linux build --- src/TNetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index cf4fec8..6cbe4ed 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -967,7 +967,7 @@ std::string TNetwork::Hash(const std::string& str) { std::stringstream ret; unsigned char* hash = SHA256(reinterpret_cast(str.c_str()), str.length(), nullptr); for (int i = 0; i < 32; i++) { - ret << std::hex << (int)hash[i]; + ret << std::hex << static_cast(hash[i]); } return ret.str(); } From 4b30918659f0e00f5c02528b53fadf777770d60e Mon Sep 17 00:00:00 2001 From: Anonymous275 <36374260+Anonymous-275@users.noreply.github.com> Date: Fri, 23 Dec 2022 16:24:24 +0000 Subject: [PATCH 4/7] - add 120 seconds timeout --- src/TNetwork.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 6cbe4ed..6c679b5 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -11,6 +11,8 @@ #include #include +typedef boost::asio::detail::socket_option::integer rcv_timeout_option; + std::vector StringToVector(const std::string& Str) { return std::vector(Str.data(), Str.data() + Str.size()); } @@ -151,6 +153,7 @@ void TNetwork::TCPServerMain() { if (ec) { beammp_errorf("failed to accept: {}", ec.message()); } + ClientSocket.set_option(rcv_timeout_option{ 120000 }); //timeout of 120seconds TConnection Conn { std::move(ClientSocket), ClientEp }; std::thread ID(&TNetwork::Identify, this, std::move(Conn)); ID.detach(); // TODO: Add to a queue and attempt to join periodically From d677d8d58d89a79e87cb1f611dbcb68704d7761c Mon Sep 17 00:00:00 2001 From: Anonymous275 <36374260+Anonymous-275@users.noreply.github.com> Date: Thu, 29 Dec 2022 17:06:06 +0000 Subject: [PATCH 5/7] rename Hash function to HashPassword move HashPassword to cpp only move check to line 285 --- include/TNetwork.h | 1 - src/TNetwork.cpp | 51 +++++++++++++++++++++++----------------------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/include/TNetwork.h b/include/TNetwork.h index bf5d12f..3b4980e 100644 --- a/include/TNetwork.h +++ b/include/TNetwork.h @@ -38,7 +38,6 @@ private: std::thread mUDPThread; std::thread mTCPThread; - static std::string Hash(const std::string& str); std::vector UDPRcvFromClient(ip::udp::endpoint& ClientEndpoint); void HandleDownload(TConnection&& TCPSock); void OnConnect(const std::weak_ptr& c); diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 6c679b5..73144a6 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -215,6 +215,15 @@ void TNetwork::HandleDownload(TConnection&& Conn) { }); } +std::string HashPassword(const std::string& str) { + std::stringstream ret; + unsigned char* hash = SHA256(reinterpret_cast(str.c_str()), str.length(), nullptr); + for (int i = 0; i < 32; i++) { + ret << std::hex << static_cast(hash[i]); + } + return ret.str(); +} + std::shared_ptr TNetwork::Authentication(TConnection&& RawConnection) { auto Client = CreateClient(std::move(RawConnection.Socket)); Client->SetIdentifier("ip", RawConnection.SockAddr.address().to_string()); @@ -283,6 +292,22 @@ std::shared_ptr TNetwork::Authentication(TConnection&& RawConnection) { return nullptr; } + if(!Application::Settings.Password.empty()) { // ask password + if(!TCPSend(*Client, StringToVector("S"))) { + // TODO: handle + } + beammp_info("Waiting for password"); + Data = TCPRcv(*Client); + std::string Pass = std::string(reinterpret_cast(Data.data()), Data.size()); + if(Pass != HashPassword(Application::Settings.Password)) { + beammp_debug(Client->GetName() + " attempted to connect with a wrong password"); + ClientKick(*Client, "Wrong password!"); + return {}; + } else { + beammp_debug(Client->GetName() + " used the correct password"); + } + } + beammp_debug("Name -> " + Client->GetName() + ", Guest -> " + std::to_string(Client->IsGuest()) + ", Roles -> " + Client->GetRoles()); mServer.ForEachClient([&](const std::weak_ptr& ClientPtr) -> bool { std::shared_ptr Cl; @@ -326,23 +351,6 @@ std::shared_ptr TNetwork::Authentication(TConnection&& RawConnection) { } if (mServer.ClientCount() < size_t(Application::Settings.MaxPlayers)) { - - if(!Application::Settings.Password.empty()) { // ask password - if(!TCPSend(*Client, StringToVector("S"))) { - // TODO: handle - } - beammp_info("Waiting for password"); - Data = TCPRcv(*Client); - std::string Pass = std::string(reinterpret_cast(Data.data()), Data.size()); - if(Pass != Hash(Application::Settings.Password)) { - beammp_debug(Client->GetName() + " attempted to connect with a wrong password"); - ClientKick(*Client, "Wrong password!"); - return {}; - } else { - beammp_debug(Client->GetName() + " used the correct password"); - } - } - beammp_info("Identification success"); mServer.InsertClient(Client); TCPClient(Client); @@ -965,12 +973,3 @@ std::vector TNetwork::UDPRcvFromClient(ip::udp::endpoint& ClientEndpoin beammp_assert(Rcv <= Ret.size()); return std::vector(Ret.begin(), Ret.begin() + Rcv); } - -std::string TNetwork::Hash(const std::string& str) { - std::stringstream ret; - unsigned char* hash = SHA256(reinterpret_cast(str.c_str()), str.length(), nullptr); - for (int i = 0; i < 32; i++) { - ret << std::hex << static_cast(hash[i]); - } - return ret.str(); -} From c51cf090efccab994b621348a89d534c53683642 Mon Sep 17 00:00:00 2001 From: Anonymous275 <36374260+Anonymous-275@users.noreply.github.com> Date: Thu, 29 Dec 2022 17:20:34 +0000 Subject: [PATCH 6/7] fix linux build --- include/TNetwork.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/TNetwork.h b/include/TNetwork.h index 3b4980e..5e0766c 100644 --- a/include/TNetwork.h +++ b/include/TNetwork.h @@ -52,4 +52,5 @@ private: static const uint8_t* SendSplit(TClient& c, ip::tcp::socket& Socket, const uint8_t* DataPtr, size_t Size); }; +std::string HashPassword(const std::string& str); std::vector StringToVector(const std::string& Str); From 879b9772f5138e8e26b394d2369a1ef8be2a2435 Mon Sep 17 00:00:00 2001 From: Simon <36374260+Anonymous-275@users.noreply.github.com> Date: Sun, 15 Jan 2023 17:11:43 +0000 Subject: [PATCH 7/7] Apply suggestions from code review Co-authored-by: Lion --- src/TConfig.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/TConfig.cpp b/src/TConfig.cpp index 92316c2..7957808 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -108,6 +108,7 @@ void TConfig::FlushToFile() { data["General"][StrDescription.data()] = Application::Settings.ServerDesc; data["General"][StrResourceFolder.data()] = Application::Settings.Resource; data["General"][StrPassword.data()] = Application::Settings.Password; + SetComment(data["General"][StrPassword.data()].comments(), " Sets a password on this server, which restricts people from joining. To join, a player must enter this exact password. Leave empty ("") to disable the password."); // Misc data["Misc"][StrHideUpdateMessages.data()] = Application::Settings.HideUpdateMessages; SetComment(data["Misc"][StrHideUpdateMessages.data()].comments(), " Hides the periodic update message which notifies you of a new server version. You should really keep this on and always update as soon as possible. For more information visit https://wiki.beammp.com/en/home/server-maintenance#updating-the-server. An update message will always appear at startup regardless.");