diff --git a/include/Http.h b/include/Http.h index 55a32a8..456ab8b 100644 --- a/include/Http.h +++ b/include/Http.h @@ -14,7 +14,7 @@ public: static std::string Post(const std::string& IP, const std::string& Fields); static std::string Get(const std::string& IP); static bool ProgressBar(size_t c, size_t t); - + static void StartProxy(); public: static bool isDownload; }; \ No newline at end of file diff --git a/include/Startup.h b/include/Startup.h index 3f52290..17e5bff 100644 --- a/include/Startup.h +++ b/include/Startup.h @@ -14,8 +14,8 @@ void InitLauncher(int argc, char* argv[]); std::string GetEP(char* P = nullptr); std::string GetGamePath(); std::string GetVer(); +std::string GetPatch(); std::string GetEN(); -void StartProxy(); void ConfigInit(); extern bool Dev; diff --git a/include/Utils.h b/include/Utils.h new file mode 100644 index 0000000..0342c11 --- /dev/null +++ b/include/Utils.h @@ -0,0 +1,20 @@ +#pragma once +#include +#include + +namespace Utils { + inline std::vector Split(const std::string& String, const std::string& delimiter) { + std::vector Val; + size_t pos; + std::string token, s = String; + while ((pos = s.find(delimiter)) != std::string::npos) { + token = s.substr(0, pos); + if (!token.empty()) + Val.push_back(token); + s.erase(0, pos + delimiter.length()); + } + if (!s.empty()) + Val.push_back(s); + return Val; + }; +}; \ No newline at end of file diff --git a/src/Network/Http.cpp b/src/Network/Http.cpp index 9a7959a..453d7fe 100644 --- a/src/Network/Http.cpp +++ b/src/Network/Http.cpp @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include void WriteHttpDebug(const httplib::Client& client, const std::string& method, const std::string& target, const httplib::Result& result) try { const std::filesystem::path folder = ".https_debug"; @@ -171,3 +174,127 @@ bool HTTP::Download(const std::string& IP, const std::string& Path) { return true; } + +void set_headers(httplib::Response& res) { + res.set_header("Access-Control-Allow-Origin", "*"); + res.set_header("Access-Control-Request-Method", "POST, OPTIONS, GET"); + res.set_header("Access-Control-Request-Headers", "X-API-Version"); +} + + +void HTTP::StartProxy() { + std::thread proxy([&]() { + httplib::Server HTTPProxy; + httplib::Headers headers = { + { "User-Agent", "BeamMP-Launcher/" + GetVer() + GetPatch() }, + { "Accept", "*/*" } + }; + httplib::Client backend("https://backend.beammp.com"); + httplib::Client forum("https://forum.beammp.com"); + + const std::string pattern = ".*"; + + auto handle_request = [&](const httplib::Request& req, httplib::Response& res) { + set_headers(res); + if (req.has_header("X-BMP-Authentication")) { + headers.emplace("X-BMP-Authentication", PrivateKey); + } + if (req.has_header("X-API-Version")) { + headers.emplace("X-API-Version", req.get_header_value("X-API-Version")); + } + + const std::vector path = Utils::Split(req.path, "/"); + + httplib::Result cli_res; + const std::string method = req.method; + std::string host = ""; + + if (!path.empty()) + host = path[0]; + + if (host == "backend") { + std::string remaining_path = req.path.substr(std::strlen("/backend")); + + if (method == "GET") + cli_res = backend.Get(remaining_path, headers); + else if (method == "POST") + cli_res = backend.Post(remaining_path, headers); + + } else if (host == "avatar") { + bool error = false; + std::string username; + std::string avatar_size = "100"; + + if (path.size() > 1) { + username = path[1]; + } else { + error = true; + } + + if (path.size() > 2) { + try { + if (std::stoi(path[2]) > 0) + avatar_size = path[2]; + + } catch (std::exception&) {} + } + + httplib::Result summary_res; + + if (!error) { + summary_res = forum.Get("/u/" + username + ".json", headers); + + if (!summary_res || summary_res->status != 200) { + error = true; + } + } + + if (!error) { + try { + nlohmann::json d = nlohmann::json::parse(summary_res->body, nullptr, false); // can fail with parse_error + + auto user = d.at("user"); // can fail with out_of_range + auto avatar_link_json = user.at("avatar_template"); // can fail with out_of_range + + auto avatar_link = avatar_link_json.get(); + size_t start_pos = avatar_link.find("{size}"); + if (start_pos != std::string::npos) + avatar_link.replace(start_pos, std::strlen("{size}"), avatar_size); + + cli_res = forum.Get(avatar_link, headers); + + } catch (std::exception&) { + error = true; + } + } + + if (error) { + cli_res = forum.Get("/user_avatar/forum.beammp.com/user/0/0.png", headers); + } + + } else { + res.set_content("Host not found", "text/plain"); + return; + } + + if (cli_res) { + res.set_content(cli_res->body, cli_res->get_header_value("Content-Type")); + } else { + res.set_content(to_string(cli_res.error()), "text/plain"); + } + }; + + HTTPProxy.Get(pattern, [&](const httplib::Request& req, httplib::Response& res) { + handle_request(req, res); + }); + + HTTPProxy.Post(pattern, [&](const httplib::Request& req, httplib::Response& res) { + handle_request(req, res); + }); + + ProxyPort = HTTPProxy.bind_to_any_port("0.0.0.0"); + debug("HTTP Proxy listening on port " + std::to_string(ProxyPort)); + HTTPProxy.listen_after_bind(); + }); + proxy.detach(); +} diff --git a/src/Network/Resources.cpp b/src/Network/Resources.cpp index f32c263..74ae789 100644 --- a/src/Network/Resources.cpp +++ b/src/Network/Resources.cpp @@ -28,26 +28,11 @@ #include #include #include -#include #include -#include +#include namespace fs = std::filesystem; std::string ListOfMods; -std::vector Split(const std::string& String, const std::string& delimiter) { - std::vector Val; - size_t pos; - std::string token, s = String; - while ((pos = s.find(delimiter)) != std::string::npos) { - token = s.substr(0, pos); - if (!token.empty()) - Val.push_back(token); - s.erase(0, pos + delimiter.length()); - } - if (!s.empty()) - Val.push_back(s); - return Val; -} void CheckForDir() { if (!fs::exists("Resources")) { @@ -247,7 +232,7 @@ void SyncResources(SOCKET Sock) { info("Checking Resources..."); CheckForDir(); - std::vector list = Split(Ret, ";"); + std::vector list = Utils::Split(Ret, ";"); std::vector FNames(list.begin(), list.begin() + (list.size() / 2)); std::vector FSizes(list.begin() + (list.size() / 2), list.end()); list.clear(); diff --git a/src/Startup.cpp b/src/Startup.cpp index 7289d88..dff8547 100644 --- a/src/Startup.cpp +++ b/src/Startup.cpp @@ -357,59 +357,3 @@ void PreGame(const std::string& GamePath) { } } } - -void set_headers(httplib::Response& res) { - res.set_header("Access-Control-Allow-Origin", "*"); - res.set_header("Access-Control-Request-Method", "POST, OPTIONS, GET"); - res.set_header("Access-Control-Request-Headers", "X-API-Version"); -} - -void StartProxy() { - std::thread proxy([&]() { - httplib::Server HTTPProxy; - httplib::Headers headers = { - { "User-Agent", "BeamMP-Launcher/" + GetVer() + GetPatch() }, - { "Accept", "*/*" } - }; - std::string pattern = "/:any1"; - for (int i = 2; i <= 4; i++) { - HTTPProxy.Get(pattern, [&](const httplib::Request& req, httplib::Response& res) { - httplib::Client cli("https://backend.beammp.com"); - set_headers(res); - if (req.has_header("X-BMP-Authentication")) { - headers.emplace("X-BMP-Authentication", PrivateKey); - } - if (req.has_header("X-API-Version")) { - headers.emplace("X-API-Version", req.get_header_value("X-API-Version")); - } - if (auto cli_res = cli.Get(req.path, headers); cli_res) { - res.set_content(cli_res->body, cli_res->get_header_value("Content-Type")); - } else { - res.set_content(to_string(cli_res.error()), "text/plain"); - } - }); - - HTTPProxy.Post(pattern, [&](const httplib::Request& req, httplib::Response& res) { - httplib::Client cli("https://backend.beammp.com"); - set_headers(res); - if (req.has_header("X-BMP-Authentication")) { - headers.emplace("X-BMP-Authentication", PrivateKey); - } - if (req.has_header("X-API-Version")) { - headers.emplace("X-API-Version", req.get_header_value("X-API-Version")); - } - if (auto cli_res = cli.Post(req.path, headers, req.body, - req.get_header_value("Content-Type")); - cli_res) { - res.set_content(cli_res->body, cli_res->get_header_value("Content-Type")); - } else { - res.set_content(to_string(cli_res.error()), "text/plain"); - } - }); - pattern += "/:any" + std::to_string(i); - } - ProxyPort = HTTPProxy.bind_to_any_port("0.0.0.0"); - HTTPProxy.listen_after_bind(); - }); - proxy.detach(); -} diff --git a/src/main.cpp b/src/main.cpp index 0859282..b66ac7c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,7 @@ int main(int argc, char* argv[]) { fatal("Main 1 : " + std::string(e.what())); } - StartProxy(); + HTTP::StartProxy(); PreGame(GetGameDir()); InitGame(GetGameDir()); CoreNetwork();