46 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
Anonymous275
839bb48cd6 Merge pull request #58 from WhiteHusky/patch-1
Emit a useful message if cleaning the mods folder fails
2023-08-04 20:30:36 +01:00
Carlen White
c4ebdda1a4 Emit a useful message if cleaning the mods folder fails
The launcher complains if it can not delete a file when it's trying to clean the mods folder out. However the message it emits is unhelpful and does not offer a suggestion to what is going on.

This commit addresses this issue by telling the user what the launcher is trying to do and suggests checking if something is currently open in that directory. I figure not having to go into detail in *where* the folder is not necessary and (primarily) only happens if the user is inspecting the folder themselves and already knows where the folder is.
2023-07-02 23:02:14 -04:00
Anonymous275
d6b494c6c4 - release v2.0.82 2022-12-18 14:30:21 +00:00
Anonymous275
a80d4f5147 - quick fix for launcher crash 2022-12-18 14:29:38 +00:00
Anonymous275
811b04485c - try fix for github workflow 2022-12-18 13:20:20 +00:00
Simon Abed El Sater
a64fead653 update 2.0.81 2022-12-18 14:39:54 +02:00
Simon Abed El Sater
399461d1b1 remove version check 2022-12-18 14:39:28 +02:00
Anonymous275
ec5e8ed5b3 v2.0.80 2022-09-25 20:39:27 +03:00
Anonymous275
5655164e60 bump 2.0.80 2022-09-25 20:37:46 +03:00
Simon Abed El Sater
3d9b7c2d67 Merge pull request #49 from snepsnepsnep/master
Fix kick message for server 3.0+
2022-09-25 20:32:50 +03:00
snepsnepsnep
764e3ab5c1 Fix kick message for server 3.0+ 2022-09-25 19:26:46 +02:00
Simon Abed El Sater
3314362faf Merge pull request #48 from Mack29446/master
Decided by vote: Update BeamNG Version and remove Mod Delete warning & Delay
2022-09-25 01:18:58 +03:00
Mackenzie
e483f520db Bump launcher version
2.0.78 -> 2.0.79
2022-09-24 22:49:10 +01:00
Mackenzie
c92e32c0e1 Remove mod wipe warn and delay 2022-09-24 22:48:17 +01:00
Mackenzie
cb872f8a41 Update BeamNG Version 2022-09-24 22:46:38 +01:00
Anonymous275
0aae245054 release 2.0.78 2022-09-24 00:37:29 +03:00
Anonymous275
480a7d038f follow redirects if present 2022-09-24 00:37:04 +03:00
Anonymous275
f62f44d4c0 version 2.0.77 2022-09-20 22:27:26 +03:00
Anonymous275
e316b89fb1 bump 0.26 2022-09-20 22:26:51 +03:00
Anonymous275
3b2dbcac1b release 2.0.76 2022-09-05 03:23:15 +03:00
Anonymous275
d881c9faf6 release 2.0.75 2022-09-05 02:59:05 +03:00
Anonymous275
11d9375f36 fix invalid Key being used 2022-09-05 02:58:22 +03:00
Simon Abed El Sater
4207d7adcf Merge pull request #44 from snepsnepsnep/master
remove key if auth is unsuccessful
2022-09-05 02:40:50 +03:00
snepsnepsnep
832b1d66a0 remove key if auth is unsuccessful 2022-09-04 20:24:27 +02:00
Anonymous275
cd829f9f22 Update Startup.cpp
version 2.0.74
2022-08-12 12:14:31 +03:00
Anonymous275
f7c70eb6df Merge pull request #36 from Mack29446/master
Change serverlist request URL and Protocol
2022-08-12 12:11:22 +03:00
Mackenzie
01960f6470 Change serverlist request URL and Protocol 2022-08-11 20:27:26 +01:00
Anonymous275
f6065a1c00 Merge pull request #21 from Mack29446/master
Update version
2022-06-24 19:46:26 +03:00
Mackenzie
ba3b7f0ed0 Update version 2022-06-23 16:53:06 +01:00
Anonymous275
056eadbef2 Merge pull request #20 from Mack29446/master
Update version
2022-06-21 18:12:49 +03:00
Mackenzie
2bb2dc9040 Update version 2022-06-21 14:28:10 +01:00
Anonymous275
17553fd412 bump launcher version 2022-06-19 02:28:26 +03:00
Anonymous275
08c1c0f682 Merge pull request #19 from Mack29446/master
Update Version Number
2022-06-18 02:02:36 +03:00
Mackenzie
84959ae9c9 Update Version Number 2022-06-17 21:35:00 +01:00
Anonymous275
c90c102097 trying to fix github actions 2022-06-15 21:38:45 +03:00
Anonymous275
5b004426ce vcpkgGitCommitId update 2022-06-15 21:35:12 +03:00
Anonymous275
69c9060dd2 Update release-build.yml 2022-06-15 21:13:02 +03:00
Anonymous275
49870639ff Update cmake-windows.yml 2022-06-15 21:12:41 +03:00
Anonymous275
0843862af9 update for game version 0.25 2022-06-15 21:02:43 +03:00
20 changed files with 4894 additions and 7753 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: '75522bb1f2e7d863078bcd06322348f053a9e33f' 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: '75522bb1f2e7d863078bcd06322348f053a9e33f' 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

@@ -99,8 +99,8 @@ void ErrorAboard(){
exit(6); exit(6);
} }
void Discord_Main(){ void Discord_Main(){
std::thread t1(DMain); /*std::thread t1(DMain);
t1.detach(); t1.detach();*/
/*info("Connecting to discord client..."); /*info("Connecting to discord client...");
int C = 0; int C = 0;
while(DiscordInfo == nullptr && C < 80){ while(DiscordInfo == nullptr && C < 80){

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);
@@ -58,7 +66,7 @@ void Parse(std::string Data,SOCKET CSocket){
NetReset(); NetReset();
Terminate = true; Terminate = true;
TCPTerminate = true; TCPTerminate = true;
Data = Code + HTTP::Post("https://backend.beammp.com/servers",""); Data = Code + HTTP::Get("https://backend.beammp.com/servers-info");
break; break;
case 'C': case 'C':
ListOfMods.clear(); ListOfMods.clear();
@@ -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;
@@ -31,10 +24,11 @@ std::string HTTP::Get(const std::string &IP) {
httplib::Client cli(IP.substr(0, pos).c_str()); httplib::Client cli(IP.substr(0, pos).c_str());
cli.set_connection_timeout(std::chrono::seconds(10)); cli.set_connection_timeout(std::chrono::seconds(10));
cli.set_follow_location(true);
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);
@@ -43,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;
@@ -62,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

@@ -60,7 +60,7 @@ std::string Auth(SOCKET Sock){
auto Res = TCPRcv(Sock); auto Res = TCPRcv(Sock);
if(Res.empty() || Res[0] == 'E'){ if(Res.empty() || Res[0] == 'E' || Res[0] == 'K'){
Abord(); Abord();
return ""; return "";
} }
@@ -87,7 +87,7 @@ std::string Auth(SOCKET Sock){
Res = TCPRcv(Sock); Res = TCPRcv(Sock);
if(Res[0] == 'E'){ if(Res[0] == 'E' || Res[0] == 'K'){
Abord(); Abord();
return ""; return "";
} }
@@ -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

@@ -109,7 +109,7 @@ std::string TCPRcv(SOCKET Sock){
#ifdef DEBUG #ifdef DEBUG
//debug("Parsing from server -> " + std::to_string(Ret.size())); //debug("Parsing from server -> " + std::to_string(Ret.size()));
#endif #endif
if(Ret[0] == 'E')UUl(Ret.substr(1)); if(Ret[0] == 'E' || Ret[0] == 'K')UUl(Ret.substr(1));
return Ret; return Ret;
} }

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){ 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!");
} }
@@ -88,19 +89,27 @@ void CheckLocalKey(){
Key.read(&Buffer[0], Size); Key.read(&Buffer[0], Size);
Key.close(); Key.close();
for (char& c : Buffer) {
if (!std::isalnum(c) && c != '-') {
UpdateKey(nullptr);
return;
}
}
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);
fatal("Invalid answer from authentication servers, please try again later!"); info("Invalid answer from authentication servers.");
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,8 +62,9 @@ std::string GetVer(){
return "2.0"; return "2.0";
} }
std::string GetPatch(){ std::string GetPatch(){
return ".63"; return ".84";
} }
std::string GetEP(char*P){ std::string GetEP(char*P){
static std::string Ret = [&](){ static std::string Ret = [&](){
std::string path(P); std::string path(P);
@@ -71,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++;
} }
@@ -147,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!");
} }
@@ -195,20 +189,16 @@ size_t DirCount(const std::filesystem::path& path){
void CheckMP(const std::string& Path) { void CheckMP(const std::string& Path) {
if (!fs::exists(Path))return; if (!fs::exists(Path))return;
size_t c = DirCount(fs::path(Path)); size_t c = DirCount(fs::path(Path));
if (c > 3) {
warn(std::to_string(c - 1) + " multiplayer mods will be wiped from mods/multiplayer! Close this if you don't want that!");
std::this_thread::sleep_for(std::chrono::seconds(15));
}
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());
} }
} }
} catch (...) { } catch (...) {
fatal("Please close the game, and try again!"); fatal("We were unable to clean the multiplayer mods folder! Is the game still running or do you have something open in that folder?");
} }
} }
@@ -223,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);
@@ -246,18 +232,17 @@ void EnableMP(){
} }
void PreGame(const std::string& GamePath){ void PreGame(const std::string& GamePath){
const std::string CurrVer("0.24.0.1");
std::string GameVer = CheckVer(GamePath); std::string GameVer = CheckVer(GamePath);
info("Game Version : " + GameVer); info("Game Version : " + GameVer);
if(GameVer < CurrVer){
fatal("Game version is old! Please update.");
}else if(GameVer > CurrVer){
warn("Game is newer than recommended, multiplayer may not work as intended!");
}
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");
@@ -266,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();