Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
6 changes: 3 additions & 3 deletions include/Http.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
#include <string>
class HTTP {
public:
static bool Download(const std::string& IP, const beammp_fs_string& Path, const std::string& Hash);
static std::string Post(const std::string& IP, const std::string& Fields);
static std::string Get(const std::string& IP);
static bool Download(const std::string& IP, const beammp_fs_string& Path, const std::string& Hash, const bool& redirect = true);
static std::string Post(std::string IP, const std::string& Fields, const bool& redirect = true);
static std::string Get(std::string IP, const bool& redirect = true);
static bool ProgressBar(size_t c, size_t t);
static void StartProxy();
public:
Expand Down
22 changes: 22 additions & 0 deletions include/Network/RegionHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
Copyright (C) 2024 BeamMP Ltd., BeamMP team and contributors.
Licensed under AGPL-3.0 (or later), see <https://www.gnu.org/licenses/>.
SPDX-License-Identifier: AGPL-3.0-or-later
*/

#pragma once

#include <vector>
#include <string>
#include <array>

class RegionHandler final {
public:
RegionHandler() = delete;
static void TopLevelDomainFailed();
static std::string RegionToTopLevelDomain();
static std::string RedirectURL(const std::string& URL);
private:
static inline unsigned int mRegionIndex { 0 };
const static inline std::array<std::string, 2> mValidTLDs {"beammp.com", "beammp.net"};
};
1 change: 1 addition & 0 deletions include/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct Options {
bool no_update = false;
bool no_launch = false;
const char* user_path = nullptr;
std::string region;
const char **game_arguments = nullptr;
int game_arguments_length = 0;
const char** argv = nullptr;
Expand Down
3 changes: 3 additions & 0 deletions src/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ void ParseConfig(const nlohmann::json& d) {
deleteDuplicateMods = d["DeleteDuplicateMods"].get<bool>();
}

if (d.contains("Region") && d["Region"].is_string()) {
options.region = d["Region"].get<std::string>();
}
}

void ConfigInit() {
Expand Down
4 changes: 3 additions & 1 deletion src/Network/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

#include "Http.h"
#include "RegionHandler.h"
#include "Network/network.hpp"
#include "Security/Init.h"
#include "Utils.h"
Expand Down Expand Up @@ -226,7 +227,8 @@ 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.beammp.com/servers-info"));
std::string resp = HTTP::Get("https://backend.beammp.com/servers-info", true);
CoreSend("B" + resp);
}));
}
break;
Expand Down
42 changes: 36 additions & 6 deletions src/Network/Http.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@


#include "Http.h"
#include "RegionHandler.h"
#include "Options.h"
#include <Logger.h>
#include <Network/network.hpp>
#include <Startup.h>
Expand All @@ -29,9 +31,12 @@ static size_t CurlWriteCallback(void* contents, size_t size, size_t nmemb, void*
}

bool HTTP::isDownload = false;
std::string HTTP::Get(const std::string& IP) {
std::string HTTP::Get(std::string IP, const bool& redirect) {
std::string Ret;
static thread_local CURL* curl = curl_easy_init();
if (redirect) {
IP = RegionHandler::RedirectURL(IP);
}
if (curl) {
CURLcode res;
char errbuf[CURL_ERROR_SIZE];
Expand All @@ -46,7 +51,18 @@ std::string HTTP::Get(const std::string& IP) {
if (res != CURLE_OK) {
error("GET to " + IP + " failed: " + std::string(curl_easy_strerror(res)));
error("Curl error: " + std::string(errbuf));
return "";
if (!redirect) {
return "";
}
RegionHandler::TopLevelDomainFailed();
IP = RegionHandler::RedirectURL(IP);
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str());
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
error("GET to " + IP + " failed: " + std::string(curl_easy_strerror(res)));
error("Curl error: " + std::string(errbuf));
return "";
}
}
} else {
error("Curl easy init failed");
Expand All @@ -55,9 +71,12 @@ std::string HTTP::Get(const std::string& IP) {
return Ret;
}

std::string HTTP::Post(const std::string& IP, const std::string& Fields) {
std::string HTTP::Post(std::string IP, const std::string& Fields, const bool& redirect) {
std::string Ret;
static thread_local CURL* curl = curl_easy_init();
if (redirect) {
IP = RegionHandler::RedirectURL(IP);
}
if (curl) {
CURLcode res;
char errbuf[CURL_ERROR_SIZE];
Expand All @@ -79,7 +98,18 @@ std::string HTTP::Post(const std::string& IP, const std::string& Fields) {
if (res != CURLE_OK) {
error("POST to " + IP + " failed: " + std::string(curl_easy_strerror(res)));
error("Curl error: " + std::string(errbuf));
return "";
if (!redirect) {
return "";
}
RegionHandler::TopLevelDomainFailed();
IP = RegionHandler::RedirectURL(IP);
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str());
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
error("GET to " + IP + " failed: " + std::string(curl_easy_strerror(res)));
error("Curl error: " + std::string(errbuf));
return "";
}
}
} else {
error("Curl easy init failed");
Expand All @@ -88,12 +118,12 @@ std::string HTTP::Post(const std::string& IP, const std::string& Fields) {
return Ret;
}

bool HTTP::Download(const std::string& IP, const beammp_fs_string& Path, const std::string& Hash) {
bool HTTP::Download(const std::string& IP, const beammp_fs_string& Path, const std::string& Hash, const bool& redirect) {
static std::mutex Lock;
std::scoped_lock Guard(Lock);

info("Downloading an update (this may take a while)");
std::string Ret = Get(IP);
std::string Ret = Get(IP, redirect);

if (Ret.empty()) {
error("Download failed");
Expand Down
39 changes: 39 additions & 0 deletions src/Network/RegionHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
Copyright (C) 2024 BeamMP Ltd., BeamMP team and contributors.
Licensed under AGPL-3.0 (or later), see <https://www.gnu.org/licenses/>.
SPDX-License-Identifier: AGPL-3.0-or-later
*/

#include "RegionHandler.h"
#include "Logger.h"
#include "Options.h"

#include <regex>

void RegionHandler::TopLevelDomainFailed()
{
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()
{
static bool isDeveloperRegion = options.region == "Developer";
if (isDeveloperRegion) {
return "beammp.dev";
}
return mValidTLDs[mRegionIndex % mValidTLDs.size()]; // Global
}

std::string RegionHandler::RedirectURL(const std::string &URL)
{
std::regex link_pattern(R"(^(https:\/\/.*)beammp\.com(\/.*)?$)");
Comment thread
SaltySnail marked this conversation as resolved.
std::smatch link_match;
if (std::regex_search(URL, link_match, link_pattern) && link_match.position() == 0) {
//TLD matched beammp.com
std::string before = link_match[1].str(); // "https://..." up to beammp
std::string after = link_match[2].matched ? link_match[2].str() : ""; // "/path" or ""
return before + RegionToTopLevelDomain() + after;
}
return URL; //if it didn't match, just return the unmodified URL
}
7 changes: 7 additions & 0 deletions src/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ void InitOptions(int argc, const char *argv[], Options &options) {
}
options.user_path = argv[i + 1];
i++;
} else if (argument == "--region") {
if (i + 1 >= argc) {
error("You must specify a region after the `--region` argument");
}
options.region = argv[i + 1];
info("Set the region to: " + options.region);
i++;
} else if (argument == "--" || argument == "--game") {
options.game_arguments = &argv[i + 1];
options.game_arguments_length = argc - i - 1;
Expand Down
2 changes: 2 additions & 0 deletions src/Security/Login.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@


#include "Http.h"
#include "Options.h"
#include "RegionHandler.h"
#include "Logger.h"
#include <filesystem>
#include <fstream>
Expand Down
10 changes: 6 additions & 4 deletions src/Startup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "Security/Init.h"
#include "Startup.h"
#include "Utils.h"
#include "RegionHandler.h"
#include "hashpp.h"
#include <filesystem>
#include <fstream>
Expand Down Expand Up @@ -332,8 +333,7 @@ bool VerifySignature(const std::filesystem::path& filePath)

void CheckForUpdates(const std::string& CV) {
std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/launcher?branch=" + Branch + "&pk=" + PublicKey);
std::string LatestVersion = HTTP::Get(
"https://backend.beammp.com/version/launcher?branch=" + Branch + "&pk=" + PublicKey);
std::string LatestVersion = HTTP::Get("https://backend.beammp.com/version/launcher?branch=" + Branch + "&pk=" + PublicKey);

std::regex sha256_pattern(R"(^[a-fA-F0-9]{64}$)");
std::smatch match;
Expand All @@ -357,11 +357,13 @@ void CheckForUpdates(const std::string& CV) {
#else
info("Downloading Launcher update " + LatestHash);
std::wstring DownloadLocation = GetBP() / (beammp_wide("new_") + GetEN());
if (HTTP::Download(
bool downloadSuccess = false;
downloadSuccess = HTTP::Download(
"https://backend.beammp.com/builds/launcher?download=true"
"&pk="
+ PublicKey + "&branch=" + Branch,
DownloadLocation, LatestHash)) {
DownloadLocation, LatestHash);
if (downloadSuccess) {
if (!VerifySignature(DownloadLocation) || !CheckThumbprint(DownloadLocation)) {
std::error_code ec;
fs::remove(DownloadLocation, ec);
Expand Down
Loading