implement SSL POST

This commit is contained in:
Lion Kortlepel 2021-01-14 00:17:47 +01:00
parent c75acbff76
commit f6121704df
5 changed files with 86 additions and 50 deletions

View File

@ -25,13 +25,13 @@ endif ()
file(GLOB source_files "src/*.cpp" "include/*.h" "include/*/*.h" "include/*/*/*.h" "include/*.hpp" "include/*/*.hpp" "src/*/*.cpp") file(GLOB source_files "src/*.cpp" "include/*.h" "include/*/*.h" "include/*/*/*.h" "include/*.hpp" "include/*/*.hpp" "src/*/*.cpp")
add_executable(BeamMP-Server ${source_files}) add_executable(BeamMP-Server ${source_files})
target_include_directories(BeamMP-Server PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> cpp-httplib) target_include_directories(BeamMP-Server PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
find_package(Lua REQUIRED) find_package(Lua REQUIRED)
target_include_directories(BeamMP-Server PUBLIC ${LUA_INCLUDE_DIR}) target_include_directories(BeamMP-Server PUBLIC ${LUA_INCLUDE_DIR})
if (UNIX) 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) elseif (WIN32)
include(FindLua) include(FindLua)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)

View File

@ -7,5 +7,6 @@
/// ///
#pragma once #pragma once
#include <string> #include <string>
#include <unordered_map>
std::string HttpRequest(const std::string& host, int port, const std::string& target); 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<std::string, std::string>& fields, const std::string& body, bool json);

View File

@ -13,6 +13,7 @@
#include <future> #include <future>
#include <sstream> #include <sstream>
#include <thread> #include <thread>
#include <unordered_map>
void WebsocketInit(); void WebsocketInit();
std::string GetPlayers() { std::string GetPlayers() {
@ -24,20 +25,25 @@ std::string GetPlayers() {
} }
return Return; return Return;
} }
std::string GenerateCall() { std::unordered_map<std::string, std::string> GenerateCall() {
std::stringstream Ret; return { { "uuid", Key },
Ret << "uuid=" << Key << "&players=" << CI->Size() { "players", std::to_string(CI->Size()) },
<< "&maxplayers=" << MaxPlayers << "&port=" << Port { "maxplayers", std::to_string(MaxPlayers) },
<< "&map=" << MapName << "&private=" << (Private ? "true" : "false") { "port", std::to_string(Port) },
<< "&version=" << GetSVer() << "&clientversion=" << GetCVer() { "map", MapName },
<< "&name=" << ServerName << "&pps=" << StatReport { "private", (Private ? "true" : "false") },
<< "&modlist=" << FileList << "&modstotalsize=" << MaxModSize { "version", GetSVer() },
<< "&modstotal=" << ModsLoaded << "&playerslist=" << GetPlayers() { "clientversion", GetCVer() },
<< "&desc=" << ServerDesc; { "name", ServerName },
return Ret.str(); { "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::string RunPromise(const std::string& host, const std::string& target, const std::unordered_map<std::string, std::string>& R) {
std::packaged_task<std::string()> task([&] { return PostHTTP(host, 443, target, R, false); }); std::packaged_task<std::string()> task([&] { return PostHTTP(host, target, R, "", false); });
std::future<std::string> f1 = task.get_future(); std::future<std::string> f1 = task.get_future();
std::thread t(std::move(task)); std::thread t(std::move(task));
t.detach(); t.detach();
@ -50,12 +56,13 @@ std::string RunPromise(const std::string& host, const std::string& target, const
[[noreturn]] void Heartbeat() { [[noreturn]] void Heartbeat() {
DebugPrintTID(); DebugPrintTID();
std::string R, T; std::unordered_map<std::string, std::string> R;
std::string T;
bool isAuth = false; bool isAuth = false;
while (true) { while (true) {
R = GenerateCall(); R = GenerateCall();
if (!CustomIP.empty()) if (!CustomIP.empty())
R += "&ip=" + CustomIP; R.insert({ "ip", CustomIP });
T = RunPromise("beammp.com", "/heartbeatv2", R); T = RunPromise("beammp.com", "/heartbeatv2", R);
if (T.substr(0, 2) != "20") { if (T.substr(0, 2) != "20") {
@ -69,8 +76,10 @@ std::string RunPromise(const std::string& host, const std::string& target, const
//Server Authenticated //Server Authenticated
if (!isAuth) { if (!isAuth) {
WebsocketInit(); WebsocketInit();
if (T.length() == 4)info(("Authenticated!")); if (T.length() == 4)
else info(("Resumed authenticated session!")); info(("Authenticated!"));
else
info(("Resumed authenticated session!"));
isAuth = true; isAuth = true;
} }
//std::this_thread::sleep_for(std::chrono::seconds(5)); //std::this_thread::sleep_for(std::chrono::seconds(5));

View File

@ -20,7 +20,7 @@
std::string GetClientInfo(const std::string& PK) { std::string GetClientInfo(const std::string& PK) {
if (!PK.empty()) { 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 ""; return "";
} }

View File

@ -11,17 +11,22 @@
#include <boost/asio/connect.hpp> #include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/beast/core.hpp> #include <boost/beast/core.hpp>
#include <boost/beast/http.hpp> #include <boost/beast/http.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/version.hpp> #include <boost/beast/version.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include <sstream>
#include <string> #include <string>
namespace beast = boost::beast; // from <boost/beast.hpp> namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp> namespace http = beast::http; // from <boost/beast/http.hpp>
namespace net = boost::asio; // from <boost/asio.hpp> namespace net = boost::asio; // from <boost/asio.hpp>
namespace ssl = net::ssl; // from <boost/asio/ssl.hpp>
using tcp = net::ip::tcp; // from <boost/asio/ip/tcp.hpp> using tcp = net::ip::tcp; // from <boost/asio/ip/tcp.hpp>
// UNUSED?! // 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) { std::string PostHTTP(const std::string& host, const std::string& target, const std::unordered_map<std::string, std::string>& fields, const std::string& body, bool json) {
try { //try {
net::io_context io; net::io_context io;
// The SSL context is required, and holds certificates
ssl::context ctx(ssl::context::tlsv13_client);
ctx.set_verify_mode(ssl::verify_none);
tcp::resolver resolver(io); tcp::resolver resolver(io);
beast::tcp_stream stream(io); beast::ssl_stream<beast::tcp_stream> stream(io, ctx);
auto const results = resolver.resolve(host, std::to_string(port)); auto const results = resolver.resolve(host, std::to_string(443));
stream.connect(results); if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) {
boost::system::error_code ec { static_cast<int>(::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<http::string_body> req { http::verb::post, target, 11 /* http 1.1 */ }; http::request<http::string_body> req { http::verb::post, target, 11 /* http 1.1 */ };
req.set(http::field::host, host); req.set(http::field::host, host);
req.set("X-Forwarded-For", HttpRequest("api.ipify.org", 80, "/"));
if (!body.empty()) {
if (json) { if (json) {
req.set(http::field::content_type, "application/json"); req.set(http::field::content_type, "application/json");
} }
req.set(http::field::content_length, boost::lexical_cast<std::string>(Fields.size())); req.set(http::field::content_length, boost::lexical_cast<std::string>(body.size()));
req.set(http::field::body, Fields.c_str()); 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) // tell the server what we are (boost beast)
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
req.prepare_payload(); req.prepare_payload();
stream.expires_after(std::chrono::seconds(5)); std::stringstream oss;
oss << req;
warn(oss.str());
beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(5));
http::write(stream, req); http::write(stream, req);
// used for reading // used for reading
beast::flat_buffer buffer; beast::flat_buffer buffer;
http::response<http::string_body> response; http::response<http::dynamic_body> response;
http::read(stream, buffer, response); http::read(stream, buffer, response);
std::string result(response.body()); std::stringstream result;
result << response;
beast::error_code ec; beast::error_code ec;
stream.socket().shutdown(tcp::socket::shutdown_both, ec); stream.shutdown(ec);
if (ec && ec != beast::errc::not_connected) { // IGNORING ec
throw beast::system_error { ec }; // goes down to `return "-1"` anyways
}
return result; info(result.str());
return result.str();
} catch (const std::exception& e) { /*} catch (const std::exception& e) {
error(e.what()); error(e.what());
return "-1"; return "-1";
} }*/
} }