7 Commits

Author SHA1 Message Date
Starystars67
7217cb1cab Update Startup.cpp 2023-12-16 03:01:28 +00:00
Anonymous275
c2f260a86c v2.0.84
- remove comment
2023-12-15 19:39:55 +00:00
Anonymous275
2781179b4b v2.0.84
- proxy tweaking
2023-12-15 19:38:47 +00:00
Anonymous275
3b479abf64 v2.0.84
- add hash check
- new routes for updates
- use C++ 20
2023-12-15 18:16:12 +00:00
Anonymous275
c731718f50 v2.0.84
- HTTP Proxy for backend.beammp.com
- Fix Attempt for mod loading, game detecting partial zip file
- Use nlohmann JSON
- Update vcpkg parameters and commit ID
- Add ability to open URL using default browser with filter
2023-12-15 17:38:47 +00:00
Anonymous-275
0fd0a9fe7e Merge remote-tracking branch 'origin/master' 2023-10-26 00:09:04 +01:00
Anonymous-275
302582bfe1 v2.0.83
- removed code that is no longer needed
2023-10-26 00:08:56 +01:00
18 changed files with 4874 additions and 7734 deletions

View File

@@ -18,9 +18,9 @@ jobs:
uses: lukka/run-vcpkg@v7 uses: lukka/run-vcpkg@v7
id: runvcpkg id: runvcpkg
with: with:
vcpkgArguments: 'discord-rpc zlib rapidjson openssl' vcpkgArguments: 'discord-rpc zlib nlohmann-json openssl cpp-httplib[openssl]'
vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg' vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg'
vcpkgGitCommitId: '06b5f4a769d848d1a20fa0acd556019728b56273' vcpkgGitCommitId: '16ee2ecb31788c336ace8bb14c21801efb6836e4'
vcpkgTriplet: 'x64-windows-static' vcpkgTriplet: 'x64-windows-static'
- name: Create Build Environment - name: Create Build Environment

View File

@@ -42,9 +42,9 @@ jobs:
uses: lukka/run-vcpkg@main uses: lukka/run-vcpkg@main
id: runvcpkg id: runvcpkg
with: with:
vcpkgArguments: 'discord-rpc zlib rapidjson openssl' vcpkgArguments: 'discord-rpc zlib nlohmann-json openssl cpp-httplib[openssl]'
vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg' vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg'
vcpkgGitCommitId: '06b5f4a769d848d1a20fa0acd556019728b56273' vcpkgGitCommitId: '16ee2ecb31788c336ace8bb14c21801efb6836e4'
vcpkgTriplet: 'x64-windows-static' vcpkgTriplet: 'x64-windows-static'
- name: Create Build Environment - name: Create Build Environment

View File

@@ -7,15 +7,18 @@ if (WIN32)
STRING(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) STRING(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
endif(WIN32) endif(WIN32)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
file(GLOB source_files "src/*.cpp" "src/*/*.cpp" "src/*/*.hpp" "include/*.h" "include/*/*.h" "include/*/*/*.h") file(GLOB source_files "src/*.cpp" "src/*/*.cpp" "src/*/*.hpp" "include/*.h" "include/*/*.h" "include/*/*/*.h")
find_package(httplib CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
add_executable(${PROJECT_NAME} ${source_files}) add_executable(${PROJECT_NAME} ${source_files})
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "BeamMP-Launcher") set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "BeamMP-Launcher")
if (WIN32) if (WIN32)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
@@ -23,8 +26,14 @@ if (WIN32)
set(VcpkgRoot ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}) set(VcpkgRoot ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET})
include_directories(${VcpkgRoot}/include) include_directories(${VcpkgRoot}/include)
link_directories(${VcpkgRoot}/lib) link_directories(${VcpkgRoot}/lib)
target_link_libraries(${PROJECT_NAME} PRIVATE ${VcpkgRoot}/lib/discord-rpc.lib target_link_libraries(${PROJECT_NAME} PRIVATE
ZLIB::ZLIB OpenSSL::SSL OpenSSL::Crypto ws2_32) ZLIB::ZLIB OpenSSL::SSL OpenSSL::Crypto ws2_32 httplib::httplib nlohmann_json::nlohmann_json)
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
target_link_libraries(${PROJECT_NAME} PRIVATE ${VcpkgRoot}/lib/discord-rpc.lib)
else ()
target_link_libraries(${PROJECT_NAME} PRIVATE ${VcpkgRoot}/debug/lib/discord-rpc.lib)
endif()
else(WIN32) #MINGW else(WIN32) #MINGW
add_definitions("-D_WIN32_WINNT=0x0600") add_definitions("-D_WIN32_WINNT=0x0600")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -s --static") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -s --static")

View File

@@ -16,5 +16,4 @@ public:
static bool ProgressBar(size_t c, size_t t); static bool ProgressBar(size_t c, size_t t);
public: public:
static bool isDownload; static bool isDownload;
static std::string Codes_[];
}; };

View File

@@ -1,12 +0,0 @@
// Copyright (c) 2019-present Anonymous275.
// BeamMP Launcher code is not in the public domain and is not free software.
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
///
/// Created by Anonymous275 on 11/27/2020
///
#pragma once
#include "rapidjson/stringbuffer.h"
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
namespace json = rapidjson;

View File

@@ -14,6 +14,7 @@ extern bool Dev;
extern int ping; extern int ping;
[[noreturn]] void CoreNetwork(); [[noreturn]] void CoreNetwork();
extern int ProxyPort;
extern int ClientID; extern int ClientID;
extern int LastPort; extern int LastPort;
extern bool ModLoaded; extern bool ModLoaded;
@@ -27,6 +28,7 @@ extern std::string LastIP;
extern std::string MStatus; extern std::string MStatus;
extern std::string UlStatus; extern std::string UlStatus;
extern std::string PublicKey; extern std::string PublicKey;
extern std::string PrivateKey;
extern std::string ListOfMods; extern std::string ListOfMods;
int KillSocket(uint64_t Dead); int KillSocket(uint64_t Dead);
void UUl(const std::string& R); void UUl(const std::string& R);

View File

@@ -7,10 +7,22 @@
/// ///
#pragma once #pragma once
#include <string> #include <string>
#include <compare>
#include <vector>
void InitLauncher(int argc, char* argv[]); void InitLauncher(int argc, char* argv[]);
std::string GetEP(char*P = nullptr); std::string GetEP(char*P = nullptr);
std::string GetGamePath(); std::string GetGamePath();
std::string GetVer(); std::string GetVer();
std::string GetEN(); std::string GetEN();
void StartProxy();
void ConfigInit(); void ConfigInit();
extern bool Dev; extern bool Dev;
struct VersionParser {
explicit VersionParser(const std::string& from_string);
std::strong_ordering operator<=>(VersionParser const& rhs) const noexcept;
bool operator==(VersionParser const& rhs) const noexcept;
std::vector<std::string> split;
std::vector<size_t> data;
};

4642
include/hashpp.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,18 +2,18 @@
/// Created by Anonymous275 on 2/23/2021 /// Created by Anonymous275 on 2/23/2021
/// ///
#include <nlohmann/json.hpp>
#include "Network/network.h" #include "Network/network.h"
#include <filesystem> #include <filesystem>
#include "Logger.h" #include "Logger.h"
#include <fstream> #include <fstream>
#include "Json.h"
#include <cstdint> #include <cstdint>
namespace fs = std::filesystem; namespace fs = std::filesystem;
std::string Branch; std::string Branch;
void ParseConfig(const json::Document& d){ void ParseConfig(const nlohmann::json& d){
if(d["Port"].IsInt()){ if(d["Port"].is_number()){
DEFAULT_PORT = d["Port"].GetInt(); DEFAULT_PORT = d["Port"].get<int>();
} }
//Default -1 //Default -1
//Release 1 //Release 1
@@ -21,8 +21,8 @@ void ParseConfig(const json::Document& d){
//Dev 3 //Dev 3
//Custom 3 //Custom 3
if(d["Build"].IsString()){ if(d["Build"].is_string()){
Branch = d["Build"].GetString(); Branch = d["Build"].get<std::string>();
for(char& c : Branch)c = char(tolower(c)); for(char& c : Branch)c = char(tolower(c));
} }
} }
@@ -35,10 +35,9 @@ void ConfigInit(){
std::string Buffer(Size, 0); std::string Buffer(Size, 0);
cfg.read(&Buffer[0], Size); cfg.read(&Buffer[0], Size);
cfg.close(); cfg.close();
json::Document d; nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false);
d.Parse(Buffer.c_str()); if(d.is_discarded()){
if(d.HasParseError()){ fatal("Config failed to parse make sure it's valid JSON!");
fatal("Config failed to parse make sure it's valid JSON! Code : " + std::to_string(d.GetParseError()));
} }
ParseConfig(d); ParseConfig(d);
}else fatal("Failed to open Launcher.cfg!"); }else fatal("Failed to open Launcher.cfg!");

View File

@@ -61,6 +61,7 @@ void StartGame(std::string Dir){
std::this_thread::sleep_for(std::chrono::seconds(5)); std::this_thread::sleep_for(std::chrono::seconds(5));
exit(2); exit(2);
} }
void InitGame(const std::string& Dir){ void InitGame(const std::string& Dir){
if(!Dev){ if(!Dev){
std::thread Game(StartGame, Dir); std::thread Game(StartGame, Dir);

View File

@@ -5,9 +5,10 @@
/// ///
/// Created by Anonymous275 on 7/20/2020 /// Created by Anonymous275 on 7/20/2020
/// ///
#include "Network/network.h" #include "Network/network.h"
#include "Security/Init.h" #include "Security/Init.h"
#include <regex>
#include "Http.h" #include "Http.h"
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
@@ -47,6 +48,13 @@ void StartSync(const std::string &Data){
GS.detach(); GS.detach();
info("Connecting to server"); info("Connecting to server");
} }
bool IsAllowedLink(const std::string& Link) {
std::regex link_pattern(R"(https:\/\/(?:\w+)?(?:\.)?(?:beammp\.com|discord\.gg))");
std::smatch link_match;
return std::regex_search(Link,link_match, link_pattern) && link_match.position() == 0;
}
void Parse(std::string Data,SOCKET CSocket){ void Parse(std::string Data,SOCKET CSocket){
char Code = Data.at(0), SubCode = 0; char Code = Data.at(0), SubCode = 0;
if(Data.length() > 1)SubCode = Data.at(1); if(Data.length() > 1)SubCode = Data.at(1);
@@ -69,6 +77,16 @@ void Parse(std::string Data,SOCKET CSocket){
if(ListOfMods == "-")Data = "L"; if(ListOfMods == "-")Data = "L";
else Data = "L"+ListOfMods; else Data = "L"+ListOfMods;
break; break;
case 'O': //open default browser with URL
if(IsAllowedLink(Data.substr(1))) {
ShellExecuteA(nullptr, "open", Data.substr(1).c_str(), nullptr, nullptr,SW_SHOW); ///TODO: Look at when working on linux port
info("Opening Link \"" + Data.substr(1) + "\"");
}
Data.clear();
break;
case 'P':
Data = Code + std::to_string(ProxyPort);
break;
case 'U': case 'U':
if(SubCode == 'l')Data = UlStatus; if(SubCode == 'l')Data = UlStatus;
if(SubCode == 'p'){ if(SubCode == 'p'){

View File

@@ -15,13 +15,6 @@
#include <cmath> #include <cmath>
#include <httplib.h> #include <httplib.h>
std::string HTTP::Codes_[] =
{
"Success","Unknown","Connection","BindIPAddress",
"Read","Write","ExceedRedirectCount","Canceled",
"SSLConnection","SSLLoadingCerts","SSLServerVerification",
"UnsupportedMultipartBoundaryChars","Compression"
};
bool HTTP::isDownload = false; bool HTTP::isDownload = false;
std::string HTTP::Get(const std::string &IP) { std::string HTTP::Get(const std::string &IP) {
static std::mutex Lock; static std::mutex Lock;
@@ -35,7 +28,7 @@ std::string HTTP::Get(const std::string &IP) {
auto res = cli.Get(IP.substr(pos).c_str(), ProgressBar); auto res = cli.Get(IP.substr(pos).c_str(), ProgressBar);
std::string Ret; std::string Ret;
if(res.error() == 0){ if(res){
if(res->status == 200){ if(res->status == 200){
Ret = res->body; Ret = res->body;
}else error(res->reason); }else error(res->reason);
@@ -44,7 +37,7 @@ std::string HTTP::Get(const std::string &IP) {
if(isDownload) { if(isDownload) {
std::cout << "\n"; std::cout << "\n";
} }
error("HTTP Get failed on " + Codes_[res.error()]); error("HTTP Get failed on " + to_string(res.error()));
} }
return Ret; return Ret;
@@ -63,23 +56,23 @@ std::string HTTP::Post(const std::string& IP, const std::string& Fields) {
if(!Fields.empty()) { if(!Fields.empty()) {
httplib::Result res = cli.Post(IP.substr(pos).c_str(), Fields, "application/json"); httplib::Result res = cli.Post(IP.substr(pos).c_str(), Fields, "application/json");
if(res.error() == 0) { if(res) {
if (res->status != 200) { if (res->status != 200) {
error(res->reason); error(res->reason);
} }
Ret = res->body; Ret = res->body;
}else{ }else{
error("HTTP Post failed on " + Codes_[res.error()]); error("HTTP Post failed on " + to_string(res.error()));
} }
}else{ }else{
httplib::Result res = cli.Post(IP.substr(pos).c_str()); httplib::Result res = cli.Post(IP.substr(pos).c_str());
if(res.error() == 0) { if(res) {
if (res->status != 200) { if (res->status != 200) {
error(res->reason); error(res->reason);
} }
Ret = res->body; Ret = res->body;
}else{ }else{
error("HTTP Post failed on " + Codes_[res.error()]); error("HTTP Post failed on " + to_string(res.error()));
} }
} }

View File

@@ -102,7 +102,7 @@ std::string Auth(SOCKET Sock){
return Res; return Res;
} }
void UpdateUl(bool D,const std::string&msg){ void UpdateUl(bool D,const std::string& msg){
if(D)UlStatus = "UlDownloading Resource " + msg; if(D)UlStatus = "UlDownloading Resource " + msg;
else UlStatus = "UlLoading Resource " + msg; else UlStatus = "UlLoading Resource " + msg;
} }
@@ -267,8 +267,10 @@ void SyncResources(SOCKET Sock){
if(!fs::exists(GetGamePath() + "mods/multiplayer")){ if(!fs::exists(GetGamePath() + "mods/multiplayer")){
fs::create_directories(GetGamePath() + "mods/multiplayer"); fs::create_directories(GetGamePath() + "mods/multiplayer");
} }
fs::copy_file(a, GetGamePath() + "mods/multiplayer" + a.substr(a.find_last_of('/')), auto name = GetGamePath() + "mods/multiplayer" + a.substr(a.find_last_of('/'));
fs::copy_options::overwrite_existing); auto tmp_name = name + ".tmp";
fs::copy_file(a,tmp_name,fs::copy_options::overwrite_existing);
fs::rename(tmp_name, name);
} catch (std::exception& e) { } catch (std::exception& e) {
error("Failed copy to the mods folder! " + std::string(e.what())); error("Failed copy to the mods folder! " + std::string(e.what()));
Terminate = true; Terminate = true;

View File

@@ -144,9 +144,9 @@ void FileList(std::vector<std::string>&a,const std::string& Path){
for (const auto &entry : fs::directory_iterator(Path)) { for (const auto &entry : fs::directory_iterator(Path)) {
const auto& DPath = entry.path(); const auto& DPath = entry.path();
if (!entry.is_directory()) { if (!entry.is_directory()) {
a.emplace_back(DPath.u8string()); a.emplace_back(DPath.string());
}else if(NameValid(DPath.filename().u8string())){ }else if(NameValid(DPath.filename().string())){
FileList(a, DPath.u8string()); FileList(a, DPath.string());
} }
} }
} }
@@ -165,7 +165,7 @@ bool Find(const std::string& FName,const std::string& Path){
bool FindHack(const std::string& Path){ bool FindHack(const std::string& Path){
bool s = true; bool s = true;
for (const auto &entry : fs::directory_iterator(Path)) { for (const auto &entry : fs::directory_iterator(Path)) {
std::string Name = entry.path().filename().u8string(); std::string Name = entry.path().filename().string();
for(char&c : Name)c = char(tolower(c)); for(char&c : Name)c = char(tolower(c));
if(Name == "steam.exe")s = false; if(Name == "steam.exe")s = false;
if(Name.find("greenluma") != -1){ if(Name.find("greenluma") != -1){

View File

@@ -6,19 +6,22 @@
/// Created by Anonymous275 on 11/26/2020 /// Created by Anonymous275 on 11/26/2020
/// ///
#include <nlohmann/json.hpp>
#include "Http.h" #include "Http.h"
#include <filesystem> #include <filesystem>
#include "Logger.h" #include "Logger.h"
#include <fstream> #include <fstream>
#include "Json.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
std::string PublicKey; std::string PublicKey;
std::string PrivateKey;
extern bool LoginAuth; extern bool LoginAuth;
std::string Role; std::string Role;
void UpdateKey(const char* newKey){ void UpdateKey(const char* newKey){
if(newKey && std::isalnum(newKey[0])){ if(newKey && std::isalnum(newKey[0])){
PrivateKey = newKey;
std::ofstream Key("key"); std::ofstream Key("key");
if(Key.is_open()){ if(Key.is_open()){
Key << newKey; Key << newKey;
@@ -48,33 +51,31 @@ std::string Login(const std::string& fields){
} }
info("Attempting to authenticate..."); info("Attempting to authenticate...");
std::string Buffer = HTTP::Post("https://auth.beammp.com/userlogin", fields); std::string Buffer = HTTP::Post("https://auth.beammp.com/userlogin", fields);
json::Document d;
d.Parse(Buffer.c_str());
if(Buffer == "-1"){ if(Buffer == "-1"){
return GetFail("Failed to communicate with the auth system!"); return GetFail("Failed to communicate with the auth system!");
} }
if (Buffer.at(0) != '{' || d.HasParseError()) { nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false);
if (Buffer.at(0) != '{' || d.is_discarded()) {
error(Buffer); error(Buffer);
return GetFail("Invalid answer from authentication servers, please try again later!"); return GetFail("Invalid answer from authentication servers, please try again later!");
} }
if(!d["success"].IsNull() && d["success"].GetBool()){ if(d.contains("success") && d["success"].get<bool>()){
LoginAuth = true; LoginAuth = true;
if(!d["private_key"].IsNull()){ if(!d.contains("private_key")) {
UpdateKey(d["private_key"].GetString()); UpdateKey(d["private_key"].get<std::string>().c_str());
} }
if(!d["public_key"].IsNull()){ if(!d.contains("public_key")){
PublicKey = d["public_key"].GetString(); PublicKey = d["public_key"].get<std::string>();
} }
info("Authentication successful!"); info("Authentication successful!");
}else info("Authentication failed!"); }else info("Authentication failed!");
if(!d["message"].IsNull()){ if(!d.contains("message")){
d.RemoveMember("private_key"); d.erase("private_key");
d.RemoveMember("public_key"); d.erase("public_key");
rapidjson::StringBuffer buffer; return d.dump();
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
d.Accept(writer);
return buffer.GetString();
} }
return GetFail("Invalid message parsing!"); return GetFail("Invalid message parsing!");
} }
@@ -97,18 +98,18 @@ void CheckLocalKey(){
Buffer = HTTP::Post("https://auth.beammp.com/userlogin", R"({"pk":")" + Buffer + "\"}"); Buffer = HTTP::Post("https://auth.beammp.com/userlogin", R"({"pk":")" + Buffer + "\"}");
json::Document d; nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false);
d.Parse(Buffer.c_str());
if (Buffer == "-1" || Buffer.at(0) != '{' || d.HasParseError()) { if (Buffer == "-1" || Buffer.at(0) != '{' || d.is_discarded()) {
error(Buffer); error(Buffer);
info("Invalid answer from authentication servers."); info("Invalid answer from authentication servers.");
UpdateKey(nullptr); UpdateKey(nullptr);
} }
if(d["success"].GetBool()){ if(d["success"].get<bool>()){
LoginAuth = true; LoginAuth = true;
UpdateKey(d["private_key"].GetString()); UpdateKey(d["private_key"].get<std::string>().c_str());
PublicKey = d["public_key"].GetString(); PublicKey = d["public_key"].get<std::string>();
Role = d["role"].GetString(); Role = d["role"].get<std::string>();
//info(Role); //info(Role);
}else{ }else{
info("Auto-Authentication unsuccessful please re-login!"); info("Auto-Authentication unsuccessful please re-login!");

View File

@@ -5,6 +5,9 @@
/// ///
/// Created by Anonymous275 on 7/16/2020 /// Created by Anonymous275 on 7/16/2020
/// ///
#include <nlohmann/json.hpp>
#include <httplib.h>
#include "zip_file.h" #include "zip_file.h"
#include <windows.h> #include <windows.h>
#include "Discord/discord_info.h" #include "Discord/discord_info.h"
@@ -12,16 +15,46 @@
#include "Security/Init.h" #include "Security/Init.h"
#include <filesystem> #include <filesystem>
#include "Startup.h" #include "Startup.h"
#include "hashpp.h"
#include "Logger.h" #include "Logger.h"
#include <fstream> #include <fstream>
#include <thread> #include <thread>
#include "Http.h" #include "Http.h"
#include "Json.h"
extern int TraceBack; extern int TraceBack;
bool Dev = false; bool Dev = false;
int ProxyPort = 0;
namespace fs = std::filesystem; namespace fs = std::filesystem;
VersionParser::VersionParser(const std::string& from_string) {
std::string token;
std::istringstream tokenStream(from_string);
while (std::getline(tokenStream, token, '.')) {
data.emplace_back(std::stol(token));
split.emplace_back(token);
}
}
std::strong_ordering VersionParser::operator<=>(
const VersionParser& rhs) const noexcept {
size_t const fields = std::min(data.size(), rhs.data.size());
for (size_t i = 0; i != fields; ++i) {
if (data[i] == rhs.data[i]) continue;
else if (data[i] < rhs.data[i]) return std::strong_ordering::less;
else return std::strong_ordering::greater;
}
if (data.size() == rhs.data.size()) return std::strong_ordering::equal;
else if (data.size() > rhs.data.size()) return std::strong_ordering::greater;
else return std::strong_ordering::less;
}
bool VersionParser::operator==(const VersionParser& rhs) const noexcept {
return std::is_eq(*this <=> rhs);
}
std::string GetEN(){ std::string GetEN(){
return "BeamMP-Launcher.exe"; return "BeamMP-Launcher.exe";
} }
@@ -29,7 +62,7 @@ std::string GetVer(){
return "2.0"; return "2.0";
} }
std::string GetPatch(){ std::string GetPatch(){
return ".82"; return ".84";
} }
std::string GetEP(char*P){ std::string GetEP(char*P){
@@ -72,43 +105,28 @@ void CheckName(int argc,char* args[]){
} }
} }
void CheckForUpdates(int argc,char*args[],const std::string& CV){ void CheckForUpdates(int argc, char* args[], const std::string& CV) {
std::string link; std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/launcher?branch=" + Branch + "&pk=" + PublicKey);
std::string HTTP = HTTP::Get("https://beammp.com/builds/launcher?version=true"); std::string LatestVersion = HTTP::Get(
bool fallback = false; "https://backend.beammp.com/version/launcher?branch=" + Branch + "&pk=" + PublicKey);
if(HTTP.find_first_of("0123456789") == std::string::npos){
HTTP = HTTP::Get("https://backup1.beammp.com/builds/launcher?version=true");
fallback = true;
if(HTTP.find_first_of("0123456789") == std::string::npos) {
fatal("Primary Servers Offline! sorry for the inconvenience!");
}
}
if(fallback){
link = "https://backup1.beammp.com/builds/launcher?download=true";
}else link = "https://beammp.com/builds/launcher?download=true";
transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower);
std::string EP(GetEP() + GetEN()), Back(GetEP() + "BeamMP-Launcher.back"); std::string EP(GetEP() + GetEN()), Back(GetEP() + "BeamMP-Launcher.back");
if(fs::exists(Back))remove(Back.c_str()); std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, EP);
if(HTTP > CV){ if (FileHash != LatestHash && VersionParser(LatestVersion) > VersionParser(GetVer()+GetPatch())) {
system("cls"); info("Launcher update found!");
info("Update found!"); fs::remove(Back);
info("Updating..."); fs::rename(EP, Back);
if(std::rename(EP.c_str(), Back.c_str()))error("failed creating a backup!"); info("Downloading Launcher update " + LatestHash);
HTTP::Download(
if(!HTTP::Download(link, EP)){ "https://backend.beammp.com/builds/launcher?download=true"
error("Launcher Update failed! trying again..."); "&pk=" +
std::this_thread::sleep_for(std::chrono::seconds(2)); PublicKey + "&branch=" + Branch,
EP);
if(!HTTP::Download(link, EP)){ URelaunch(argc, args);
error("Launcher Update failed!"); } else info("Launcher version is up to date");
std::this_thread::sleep_for(std::chrono::seconds(5));
ReLaunch(argc,args);
}
}
URelaunch(argc,args);
}else info("Launcher version is up to date");
TraceBack++; TraceBack++;
} }
@@ -148,31 +166,6 @@ void LinuxPatch(){
} }
RegCloseKey(hKey); RegCloseKey(hKey);
std::string Path = R"(Z:\home\)" + std::string(getenv("USER")) + R"(\.steam\steam\Steam.exe)";
if(!fs::exists(Path)) {
std::ofstream ofs(Path);
if (!ofs.is_open()) {
fatal("Failed to create file \"" + Path + "\"");
return;
} else ofs.close();
}
result = RegOpenKeyEx(HKEY_CURRENT_USER, R"(Software\Valve\Steam)", 0, KEY_ALL_ACCESS, &hKey);
if (result != ERROR_SUCCESS){
fatal(R"(failed to open HKEY_CURRENT_USER\Software\Valve\Steam)");
return;
}
result = RegSetValueEx(hKey, "SteamExe", 0, REG_SZ, (BYTE*)Path.c_str(), Path.size());
if (result != ERROR_SUCCESS){
fatal(R"(failed to create the value "Name" under HKEY_CURRENT_USER\Software\Valve\Steam\Apps\284160)");
return;
}
RegCloseKey(hKey);
info("Patched!"); info("Patched!");
} }
@@ -199,7 +192,7 @@ void CheckMP(const std::string& Path) {
try { try {
for (auto& p : fs::directory_iterator(Path)){ for (auto& p : fs::directory_iterator(Path)){
if(p.exists() && !p.is_directory()){ if(p.exists() && !p.is_directory()){
std::string Name = p.path().filename().u8string(); std::string Name = p.path().filename().string();
for(char&Ch : Name)Ch = char(tolower(Ch)); for(char&Ch : Name)Ch = char(tolower(Ch));
if(Name != "beammp.zip")fs::remove(p.path()); if(Name != "beammp.zip")fs::remove(p.path());
} }
@@ -220,20 +213,16 @@ void EnableMP(){
std::string Data(Size, 0); std::string Data(Size, 0);
db.read(&Data[0], Size); db.read(&Data[0], Size);
db.close(); db.close();
json::Document d; nlohmann::json d = nlohmann::json::parse(Data, nullptr, false);
d.Parse(Data.c_str()); if(Data.at(0) != '{' || d.is_discarded()) {
if(Data.at(0) != '{' || d.HasParseError()){
//error("Failed to parse " + File); //TODO illegal formatting //error("Failed to parse " + File); //TODO illegal formatting
return; return;
} }
if(!d["mods"].IsNull() && !d["mods"]["multiplayerbeammp"].IsNull()){ if(d.contains("mods") && d["mods"].contains("multiplayerbeammp")){
d["mods"]["multiplayerbeammp"]["active"] = true; d["mods"]["multiplayerbeammp"]["active"] = true;
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
d.Accept(writer);
std::ofstream ofs(File); std::ofstream ofs(File);
if(ofs.is_open()){ if(ofs.is_open()){
ofs << buffer.GetString(); ofs << d.dump();
ofs.close(); ofs.close();
}else{ }else{
error("Failed to write " + File); error("Failed to write " + File);
@@ -249,7 +238,11 @@ void PreGame(const std::string& GamePath){
CheckMP(GetGamePath() + "mods/multiplayer"); CheckMP(GetGamePath() + "mods/multiplayer");
if(!Dev) { if(!Dev) {
info("Downloading mod please wait..."); std::string LatestHash = HTTP::Get("https://backend.beammp.com/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); } ), LatestHash.end());
try { try {
if (!fs::exists(GetGamePath() + "mods/multiplayer")) { if (!fs::exists(GetGamePath() + "mods/multiplayer")) {
fs::create_directories(GetGamePath() + "mods/multiplayer"); fs::create_directories(GetGamePath() + "mods/multiplayer");
@@ -258,18 +251,76 @@ void PreGame(const std::string& GamePath){
}catch(std::exception&e){ }catch(std::exception&e){
fatal(e.what()); fatal(e.what());
} }
std::string ZipPath(GetGamePath() + R"(mods\multiplayer\BeamMP.zip)"); std::string ZipPath(GetGamePath() + R"(mods\multiplayer\BeamMP.zip)");
HTTP::Download("https://backend.beammp.com/builds/client?download=true" std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, ZipPath);
"&pk=" + PublicKey + "&branch=" + Branch, ZipPath);
if (FileHash != LatestHash) {
info("Downloading BeamMP Update " + LatestHash);
HTTP::Download("https://backend.beammp.com/builds/client?download=true"
"&pk=" + PublicKey + "&branch=" + Branch, ZipPath);
}
std::string Target(GetGamePath() + "mods/unpacked/beammp"); std::string Target(GetGamePath() + "mods/unpacked/beammp");
if(fs::is_directory(Target)) { if(fs::is_directory(Target)) {
fs::remove_all(Target); fs::remove_all(Target);
} }
//HTTP::Download("beammp.com/builds/client", GetGamePath() + R"(mods\multiplayer\BeamMP.zip)");
} }
}
void set_headers(httplib::Response& res) {
res.set_header("Access-Control-Allow-Origin", "*");
res.set_header("Access-Control-Allow-Headers", "X-API-Version");
res.set_header("Access-Control-Allow-Method", "GET,POST,OPTIONS");
}
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();
} }

View File

@@ -21,20 +21,21 @@
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
#ifdef DEBUG #ifdef DEBUG
std::thread th(flush); std::thread th(flush);
th.detach(); th.detach();
#endif #endif
GetEP(argv[0]); GetEP(argv[0]);
InitLauncher(argc,argv); InitLauncher(argc, argv);
try { try {
LegitimacyCheck(); LegitimacyCheck();
}catch (std::exception& e){ } catch (std::exception &e) {
fatal("Main 1 : " + std::string(e.what())); fatal("Main 1 : " + std::string(e.what()));
} }
StartProxy();
PreGame(GetGameDir()); PreGame(GetGameDir());
InitGame(GetGameDir()); InitGame(GetGameDir());
CoreNetwork(); CoreNetwork();