From d7277151ccd8c3ca7a88a9df1a2794ed00c1f11c Mon Sep 17 00:00:00 2001 From: SaltySnail Date: Thu, 25 Jun 2026 18:35:42 +0200 Subject: [PATCH] Remove restricted region --- CMakeLists.txt | 2 +- include/Network/RegionHandler.h | 21 +++++++++++++++ include/Utils.h | 10 ------- src/Network/Core.cpp | 8 +++++- src/Network/Http.cpp | 7 ++--- src/Network/RegionHandler.cpp | 23 +++++++++++++++++ src/Security/Login.cpp | 13 ++++++++-- src/Startup.cpp | 46 ++++++++++++++++++++++++++------- 8 files changed, 104 insertions(+), 26 deletions(-) create mode 100644 include/Network/RegionHandler.h create mode 100644 src/Network/RegionHandler.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 67e666e..9d54c03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,4 +37,4 @@ else(WIN32) #MINGW set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -s --static") target_link_libraries(${PROJECT_NAME} ssl crypto ws2_32 ssp crypt32 z CURL::libcurl) endif(WIN32) -target_include_directories(${PROJECT_NAME} PRIVATE "include") +target_include_directories(${PROJECT_NAME} PRIVATE "include" "include/Network") diff --git a/include/Network/RegionHandler.h b/include/Network/RegionHandler.h new file mode 100644 index 0000000..b791f08 --- /dev/null +++ b/include/Network/RegionHandler.h @@ -0,0 +1,21 @@ +/* + Copyright (C) 2024 BeamMP Ltd., BeamMP team and contributors. + Licensed under AGPL-3.0 (or later), see . + SPDX-License-Identifier: AGPL-3.0-or-later +*/ + +#pragma once + +#include +#include +#include + +class RegionHandler final { +public: + RegionHandler() = delete; + static void TopLevelDomainFailed(bool failed); + static std::string RegionToTopLevelDomain(const std::string region); +private: + static inline unsigned int mRegionIndex { 0 }; + const static inline std::array mValidTLDs {"beammp.com", "beammp.ru"}; +}; diff --git a/include/Utils.h b/include/Utils.h index c4e7751..3d0359f 100644 --- a/include/Utils.h +++ b/include/Utils.h @@ -336,14 +336,4 @@ namespace Utils { throw std::runtime_error("Game disconnected"); } } - - inline std::string RegionToTopLevelDomain(const std::string region) { - if (region == "Restricted") { - return "beammp.ru"; - } - else if (region == "Developer") { - return "beammp.dev"; - } - return "beammp.com"; // Global - } }; diff --git a/src/Network/Core.cpp b/src/Network/Core.cpp index 90c7a99..be8eff4 100644 --- a/src/Network/Core.cpp +++ b/src/Network/Core.cpp @@ -5,6 +5,7 @@ */ #include "Http.h" +#include "RegionHandler.h" #include "Network/network.hpp" #include "Security/Init.h" #include "Utils.h" @@ -226,7 +227,12 @@ void Parse(std::string Data, SOCKET CSocket) { TCPTerminate = true; Data.clear(); futures.push_back(std::async(std::launch::async, []() { - CoreSend("B" + HTTP::Get("https://backend." + Utils::RegionToTopLevelDomain(options.region) + "/servers-info")); + std::string resp = HTTP::Get("https://backend." + RegionHandler::RegionToTopLevelDomain(options.region) + "/servers-info"); + if (resp == "") { + RegionHandler::TopLevelDomainFailed(true); + resp = HTTP::Get("https://backend." + RegionHandler::RegionToTopLevelDomain(options.region) + "/servers-info"); + } + CoreSend("B" + resp); })); } break; diff --git a/src/Network/Http.cpp b/src/Network/Http.cpp index 9c2845e..bb238ec 100644 --- a/src/Network/Http.cpp +++ b/src/Network/Http.cpp @@ -6,6 +6,7 @@ #include "Http.h" +#include "RegionHandler.h" #include "Options.h" #include #include @@ -137,8 +138,8 @@ void HTTP::StartProxy() { { "User-Agent", "BeamMP-Launcher/" + GetVer() + GetPatch() }, { "Accept", "*/*" } }; - httplib::Client backend("https://backend." + Utils::RegionToTopLevelDomain(options.region)); - httplib::Client forum("https://forum." + Utils::RegionToTopLevelDomain(options.region)); + httplib::Client backend("https://backend." + RegionHandler::RegionToTopLevelDomain(options.region)); + httplib::Client forum("https://forum." + RegionHandler::RegionToTopLevelDomain(options.region)); const std::string pattern = ".*"; @@ -217,7 +218,7 @@ void HTTP::StartProxy() { } if (error) { - cli_res = forum.Get("/user_avatar/forum." + Utils::RegionToTopLevelDomain(options.region) + "/user/0/0.png", headers); + cli_res = forum.Get("/user_avatar/forum." + RegionHandler::RegionToTopLevelDomain(options.region) + "/user/0/0.png", headers); } } else { diff --git a/src/Network/RegionHandler.cpp b/src/Network/RegionHandler.cpp new file mode 100644 index 0000000..620c0ba --- /dev/null +++ b/src/Network/RegionHandler.cpp @@ -0,0 +1,23 @@ +/* + Copyright (C) 2024 BeamMP Ltd., BeamMP team and contributors. + Licensed under AGPL-3.0 (or later), see . + SPDX-License-Identifier: AGPL-3.0-or-later +*/ + +#include "RegionHandler.h" +#include "Logger.h" + +void RegionHandler::TopLevelDomainFailed(bool failed) +{ + if (!failed) return; + info("Top level domain of " + mValidTLDs[mRegionIndex % mValidTLDs.size()] + " didn't respond correctly , changing domain to " + mValidTLDs[(mRegionIndex + 1) % mValidTLDs.size()]); + mRegionIndex++; +} + +std::string RegionHandler::RegionToTopLevelDomain(const std::string region) +{ + if (region == "Developer") { + return "beammp.dev"; + } + return mValidTLDs[mRegionIndex % mValidTLDs.size()]; // Global +} diff --git a/src/Security/Login.cpp b/src/Security/Login.cpp index e2b0561..4c7843b 100644 --- a/src/Security/Login.cpp +++ b/src/Security/Login.cpp @@ -7,6 +7,7 @@ #include "Http.h" #include "Options.h" +#include "RegionHandler.h" #include "Logger.h" #include #include @@ -56,7 +57,11 @@ std::string Login(const std::string& fields) { } info("Attempting to authenticate..."); try { - std::string Buffer = HTTP::Post("https://auth." + Utils::RegionToTopLevelDomain(options.region) + "/userlogin", fields); + std::string Buffer = HTTP::Post("https://auth." + RegionHandler::RegionToTopLevelDomain(options.region) + "/userlogin", fields); + if (Buffer == "") { + RegionHandler::TopLevelDomainFailed(true); + Buffer = HTTP::Post("https://auth." + RegionHandler::RegionToTopLevelDomain(options.region) + "/userlogin", fields); + } if (Buffer.empty()) { return GetFail("Failed to communicate with the auth system!"); @@ -116,7 +121,11 @@ void CheckLocalKey() { } } - Buffer = HTTP::Post("https://auth." + Utils::RegionToTopLevelDomain(options.region) + "/userlogin", R"({"pk":")" + Buffer + "\"}"); + Buffer = HTTP::Post("https://auth." + RegionHandler::RegionToTopLevelDomain(options.region) + "/userlogin", R"({"pk":")" + Buffer + "\"}"); + if (Buffer == "") { + RegionHandler::TopLevelDomainFailed(true); + Buffer = HTTP::Post("https://auth." + RegionHandler::RegionToTopLevelDomain(options.region) + "/userlogin", R"({"pk":")" + Buffer + "\"}"); + } nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false); diff --git a/src/Startup.cpp b/src/Startup.cpp index c35b47b..bf046e7 100644 --- a/src/Startup.cpp +++ b/src/Startup.cpp @@ -24,6 +24,7 @@ #include "Security/Init.h" #include "Startup.h" #include "Utils.h" +#include "RegionHandler.h" #include "hashpp.h" #include #include @@ -331,9 +332,16 @@ bool VerifySignature(const std::filesystem::path& filePath) #endif void CheckForUpdates(const std::string& CV) { - std::string LatestHash = HTTP::Get("https://backend." + Utils::RegionToTopLevelDomain(options.region) + "/sha/launcher?branch=" + Branch + "&pk=" + PublicKey); - std::string LatestVersion = HTTP::Get( - "https://backend." + Utils::RegionToTopLevelDomain(options.region) + "/version/launcher?branch=" + Branch + "&pk=" + PublicKey); + std::string LatestHash = HTTP::Get("https://backend." + RegionHandler::RegionToTopLevelDomain(options.region) + "/sha/launcher?branch=" + Branch + "&pk=" + PublicKey); + if (LatestHash == "") { + RegionHandler::TopLevelDomainFailed(true); + LatestHash = HTTP::Get("https://backend." + RegionHandler::RegionToTopLevelDomain(options.region) + "/sha/launcher?branch=" + Branch + "&pk=" + PublicKey); + } + std::string LatestVersion = HTTP::Get("https://backend." + RegionHandler::RegionToTopLevelDomain(options.region) + "/version/launcher?branch=" + Branch + "&pk=" + PublicKey); + if (LatestVersion == "") { + RegionHandler::TopLevelDomainFailed(true); + LatestVersion = HTTP::Get("https://backend." + RegionHandler::RegionToTopLevelDomain(options.region) + "/version/launcher?branch=" + Branch + "&pk=" + PublicKey); + } std::regex sha256_pattern(R"(^[a-fA-F0-9]{64}$)"); std::smatch match; @@ -357,11 +365,21 @@ void CheckForUpdates(const std::string& CV) { #else info("Downloading Launcher update " + LatestHash); std::wstring DownloadLocation = GetBP() / (beammp_wide("new_") + GetEN()); - if (HTTP::Download( - "https://backend." + Utils::RegionToTopLevelDomain(options.region) + "/builds/launcher?download=true" + bool downloadSuccess = false; + downloadSuccess = HTTP::Download( + "https://backend." + RegionHandler::RegionToTopLevelDomain(options.region) + "/builds/launcher?download=true" "&pk=" + PublicKey + "&branch=" + Branch, - DownloadLocation, LatestHash)) { + DownloadLocation, LatestHash); + if (!downloadSuccess) { + RegionHandler::TopLevelDomainFailed(true); + downloadSuccess = HTTP::Download( + "https://backend." + RegionHandler::RegionToTopLevelDomain(options.region) + "/builds/launcher?download=true" + "&pk=" + + PublicKey + "&branch=" + Branch, + DownloadLocation, LatestHash); + } + if (downloadSuccess) { if (!VerifySignature(DownloadLocation) || !CheckThumbprint(DownloadLocation)) { std::error_code ec; fs::remove(DownloadLocation, ec); @@ -514,7 +532,11 @@ void PreGame(const beammp_fs_string& GamePath) { info(beammp_wide("Game user path: ") + beammp_fs_string(GetGamePath())); if (!options.no_download) { - std::string LatestHash = HTTP::Get("https://backend." + Utils::RegionToTopLevelDomain(options.region) + "/sha/mod?branch=" + Branch + "&pk=" + PublicKey); + std::string LatestHash = HTTP::Get("https://backend." + RegionHandler::RegionToTopLevelDomain(options.region) + "/sha/mod?branch=" + Branch + "&pk=" + PublicKey); + if (LatestHash == "") { + RegionHandler::TopLevelDomainFailed(true); + LatestHash = HTTP::Get("https://backend." + RegionHandler::RegionToTopLevelDomain(options.region) + "/sha/mod?branch=" + Branch + "&pk=" + PublicKey); + } transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower); LatestHash.erase(std::remove_if(LatestHash.begin(), LatestHash.end(), [](auto const& c) -> bool { return !std::isalnum(c); }), @@ -548,10 +570,16 @@ void PreGame(const beammp_fs_string& GamePath) { if (FileHash != LatestHash) { info("Downloading BeamMP Update " + LatestHash); - HTTP::Download("https://backend." + Utils::RegionToTopLevelDomain(options.region) + "/builds/client?download=true" + if (!HTTP::Download("https://backend." + RegionHandler::RegionToTopLevelDomain(options.region) + "/builds/client?download=true" "&pk=" + PublicKey + "&branch=" + Branch, - ZipPath, LatestHash); + ZipPath, LatestHash)) { + RegionHandler::TopLevelDomainFailed(true); + HTTP::Download("https://backend." + RegionHandler::RegionToTopLevelDomain(options.region) + "/builds/client?download=true" + "&pk=" + + PublicKey + "&branch=" + Branch, + ZipPath, LatestHash); + } } beammp_fs_string Target(GetGamePath() / beammp_wide("mods/unpacked/beammp"));