From f6121704dfb3bed0c40e883a305d66229b422f4d Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 14 Jan 2021 00:17:47 +0100 Subject: [PATCH] implement SSL POST --- CMakeLists.txt | 4 +- include/Curl/Http.h | 3 +- src/Init/Heartbeat.cpp | 43 ++++++++++++--------- src/Network/Auth.cpp | 2 +- src/Network/Http.cpp | 84 +++++++++++++++++++++++++++--------------- 5 files changed, 86 insertions(+), 50 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 70ecc49..98d287f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,13 +25,13 @@ endif () file(GLOB source_files "src/*.cpp" "include/*.h" "include/*/*.h" "include/*/*/*.h" "include/*.hpp" "include/*/*.hpp" "src/*/*.cpp") add_executable(BeamMP-Server ${source_files}) -target_include_directories(BeamMP-Server PUBLIC $ cpp-httplib) +target_include_directories(BeamMP-Server PUBLIC $) find_package(Lua REQUIRED) target_include_directories(BeamMP-Server PUBLIC ${LUA_INCLUDE_DIR}) if (UNIX) - target_link_libraries(BeamMP-Server z pthread stdc++fs ${Boost_LINK_DIRS} ${LUA_LIBRARIES} curl dl) + target_link_libraries(BeamMP-Server z pthread stdc++fs ${Boost_LINK_DIRS} ${LUA_LIBRARIES} curl dl crypto ssl) elseif (WIN32) include(FindLua) find_package(ZLIB REQUIRED) diff --git a/include/Curl/Http.h b/include/Curl/Http.h index 46744b7..714543d 100644 --- a/include/Curl/Http.h +++ b/include/Curl/Http.h @@ -7,5 +7,6 @@ /// #pragma once #include +#include std::string HttpRequest(const std::string& host, int port, const std::string& target); -std::string PostHTTP(const std::string& host, int port, const std::string& target, const std::string& Fields, bool json); +std::string PostHTTP(const std::string& host, const std::string& target, const std::unordered_map& fields, const std::string& body, bool json); diff --git a/src/Init/Heartbeat.cpp b/src/Init/Heartbeat.cpp index fb38486..080b7c8 100644 --- a/src/Init/Heartbeat.cpp +++ b/src/Init/Heartbeat.cpp @@ -13,6 +13,7 @@ #include #include #include +#include void WebsocketInit(); std::string GetPlayers() { @@ -24,20 +25,25 @@ std::string GetPlayers() { } return Return; } -std::string GenerateCall() { - std::stringstream Ret; - Ret << "uuid=" << Key << "&players=" << CI->Size() - << "&maxplayers=" << MaxPlayers << "&port=" << Port - << "&map=" << MapName << "&private=" << (Private ? "true" : "false") - << "&version=" << GetSVer() << "&clientversion=" << GetCVer() - << "&name=" << ServerName << "&pps=" << StatReport - << "&modlist=" << FileList << "&modstotalsize=" << MaxModSize - << "&modstotal=" << ModsLoaded << "&playerslist=" << GetPlayers() - << "&desc=" << ServerDesc; - return Ret.str(); +std::unordered_map GenerateCall() { + return { { "uuid", Key }, + { "players", std::to_string(CI->Size()) }, + { "maxplayers", std::to_string(MaxPlayers) }, + { "port", std::to_string(Port) }, + { "map", MapName }, + { "private", (Private ? "true" : "false") }, + { "version", GetSVer() }, + { "clientversion", GetCVer() }, + { "name", ServerName }, + { "pps", StatReport }, + { "modlist", FileList }, + { "modstotalsize", std::to_string(MaxModSize) }, + { "modstotal", std::to_string(ModsLoaded) }, + { "playerslist", GetPlayers() }, + { "desc", ServerDesc } }; } -std::string RunPromise(const std::string& host, const std::string& target, const std::string& R) { - std::packaged_task task([&] { return PostHTTP(host, 443, target, R, false); }); +std::string RunPromise(const std::string& host, const std::string& target, const std::unordered_map& R) { + std::packaged_task task([&] { return PostHTTP(host, target, R, "", false); }); std::future f1 = task.get_future(); std::thread t(std::move(task)); t.detach(); @@ -50,12 +56,13 @@ std::string RunPromise(const std::string& host, const std::string& target, const [[noreturn]] void Heartbeat() { DebugPrintTID(); - std::string R, T; + std::unordered_map R; + std::string T; bool isAuth = false; while (true) { R = GenerateCall(); if (!CustomIP.empty()) - R += "&ip=" + CustomIP; + R.insert({ "ip", CustomIP }); T = RunPromise("beammp.com", "/heartbeatv2", R); if (T.substr(0, 2) != "20") { @@ -69,8 +76,10 @@ std::string RunPromise(const std::string& host, const std::string& target, const //Server Authenticated if (!isAuth) { WebsocketInit(); - if (T.length() == 4)info(("Authenticated!")); - else info(("Resumed authenticated session!")); + if (T.length() == 4) + info(("Authenticated!")); + else + info(("Resumed authenticated session!")); isAuth = true; } //std::this_thread::sleep_for(std::chrono::seconds(5)); diff --git a/src/Network/Auth.cpp b/src/Network/Auth.cpp index 8c5b18c..570e774 100644 --- a/src/Network/Auth.cpp +++ b/src/Network/Auth.cpp @@ -20,7 +20,7 @@ std::string GetClientInfo(const std::string& PK) { if (!PK.empty()) { - return PostHTTP("auth.beammp.com", 443, "/pkToUser", R"({"key":")" + PK + "\"}", true); + return PostHTTP("auth.beammp.com", "/pkToUser", {}, R"({"key":")" + PK + "\"}", true); } return ""; } diff --git a/src/Network/Http.cpp b/src/Network/Http.cpp index 0296346..6fea3b1 100644 --- a/src/Network/Http.cpp +++ b/src/Network/Http.cpp @@ -11,17 +11,22 @@ #include #include +#include +#include #include #include +#include #include #include #include #include +#include #include namespace beast = boost::beast; // from namespace http = beast::http; // from namespace net = boost::asio; // from +namespace ssl = net::ssl; // from using tcp = net::ip::tcp; // from // UNUSED?! @@ -63,48 +68,69 @@ std::string HttpRequest(const std::string& host, int port, const std::string& ta } } -std::string PostHTTP(const std::string& host, int port, const std::string& target, const std::string& Fields, bool json) { - try { - net::io_context io; - tcp::resolver resolver(io); - beast::tcp_stream stream(io); - auto const results = resolver.resolve(host, std::to_string(port)); - stream.connect(results); +std::string PostHTTP(const std::string& host, const std::string& target, const std::unordered_map& fields, const std::string& body, bool json) { + //try { + net::io_context io; - http::request req { http::verb::post, target, 11 /* http 1.1 */ }; + // The SSL context is required, and holds certificates + ssl::context ctx(ssl::context::tlsv13_client); - req.set(http::field::host, host); + ctx.set_verify_mode(ssl::verify_none); + + tcp::resolver resolver(io); + beast::ssl_stream stream(io, ctx); + auto const results = resolver.resolve(host, std::to_string(443)); + if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) { + boost::system::error_code ec { static_cast(::ERR_get_error()), boost::asio::error::get_ssl_category() }; + throw boost::system::system_error { ec }; + } + beast::get_lowest_layer(stream).connect(results); + stream.handshake(ssl::stream_base::client); + + http::request req { http::verb::post, target, 11 /* http 1.1 */ }; + + req.set(http::field::host, host); + req.set("X-Forwarded-For", HttpRequest("api.ipify.org", 80, "/")); + if (!body.empty()) { if (json) { req.set(http::field::content_type, "application/json"); } - req.set(http::field::content_length, boost::lexical_cast(Fields.size())); - req.set(http::field::body, Fields.c_str()); - // tell the server what we are (boost beast) - req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); - req.prepare_payload(); + req.set(http::field::content_length, boost::lexical_cast(body.size())); + req.set(http::field::body, body); + } + for (const auto& pair : fields) { + info("setting " + pair.first + " to " + pair.second); + req.set(pair.first, pair.second); + } + // tell the server what we are (boost beast) + req.prepare_payload(); - stream.expires_after(std::chrono::seconds(5)); + std::stringstream oss; + oss << req; + warn(oss.str()); - http::write(stream, req); + beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(5)); - // used for reading - beast::flat_buffer buffer; - http::response response; + http::write(stream, req); - http::read(stream, buffer, response); + // used for reading + beast::flat_buffer buffer; + http::response response; - std::string result(response.body()); + http::read(stream, buffer, response); - beast::error_code ec; - stream.socket().shutdown(tcp::socket::shutdown_both, ec); - if (ec && ec != beast::errc::not_connected) { - throw beast::system_error { ec }; // goes down to `return "-1"` anyways - } + std::stringstream result; + result << response; - return result; + beast::error_code ec; + stream.shutdown(ec); + // IGNORING ec - } catch (const std::exception& e) { + info(result.str()); + return result.str(); + + /*} catch (const std::exception& e) { error(e.what()); return "-1"; - } + }*/ }