mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2026-04-03 14:26:15 +00:00
Compare commits
31 Commits
v2.0.82
...
add-warnin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e5fe80202 | ||
|
|
7ff4681263 | ||
|
|
3be1262b07 | ||
|
|
cfcabf31a4 | ||
|
|
5714c3de76 | ||
|
|
12711d77c7 | ||
|
|
e08a4de6db | ||
|
|
acd5f4ed09 | ||
|
|
c4e7b9a919 | ||
|
|
3db1f6773e | ||
|
|
8c9d3a5455 | ||
|
|
9dcfa1dca4 | ||
|
|
bd4cfe06b1 | ||
|
|
9c7034e401 | ||
|
|
aeb167c1e8 | ||
|
|
7967ec38e8 | ||
|
|
250be2ccdc | ||
|
|
6158069d4d | ||
|
|
b2e5b8d2d3 | ||
|
|
5db1b48e07 | ||
|
|
56dcfcc5ed | ||
|
|
7c1106a46a | ||
|
|
9afdfd4d1b | ||
|
|
c2f260a86c | ||
|
|
2781179b4b | ||
|
|
3b479abf64 | ||
|
|
c731718f50 | ||
|
|
0fd0a9fe7e | ||
|
|
302582bfe1 | ||
|
|
839bb48cd6 | ||
|
|
c4ebdda1a4 |
4
.github/workflows/cmake-windows.yml
vendored
4
.github/workflows/cmake-windows.yml
vendored
@@ -18,9 +18,9 @@ jobs:
|
||||
uses: lukka/run-vcpkg@v7
|
||||
id: runvcpkg
|
||||
with:
|
||||
vcpkgArguments: 'discord-rpc zlib rapidjson openssl'
|
||||
vcpkgArguments: 'discord-rpc zlib nlohmann-json openssl cpp-httplib[openssl]'
|
||||
vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg'
|
||||
vcpkgGitCommitId: '06b5f4a769d848d1a20fa0acd556019728b56273'
|
||||
vcpkgGitCommitId: '16ee2ecb31788c336ace8bb14c21801efb6836e4'
|
||||
vcpkgTriplet: 'x64-windows-static'
|
||||
|
||||
- name: Create Build Environment
|
||||
|
||||
4
.github/workflows/release-build.yml
vendored
4
.github/workflows/release-build.yml
vendored
@@ -42,9 +42,9 @@ jobs:
|
||||
uses: lukka/run-vcpkg@main
|
||||
id: runvcpkg
|
||||
with:
|
||||
vcpkgArguments: 'discord-rpc zlib rapidjson openssl'
|
||||
vcpkgArguments: 'discord-rpc zlib nlohmann-json openssl cpp-httplib[openssl]'
|
||||
vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg'
|
||||
vcpkgGitCommitId: '06b5f4a769d848d1a20fa0acd556019728b56273'
|
||||
vcpkgGitCommitId: '16ee2ecb31788c336ace8bb14c21801efb6836e4'
|
||||
vcpkgTriplet: 'x64-windows-static'
|
||||
|
||||
- name: Create Build Environment
|
||||
|
||||
@@ -7,15 +7,18 @@ if (WIN32)
|
||||
STRING(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
|
||||
endif(WIN32)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
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")
|
||||
find_package(httplib CONFIG REQUIRED)
|
||||
find_package(nlohmann_json CONFIG REQUIRED)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${source_files})
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "BeamMP-Launcher")
|
||||
|
||||
|
||||
if (WIN32)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
@@ -23,8 +26,14 @@ if (WIN32)
|
||||
set(VcpkgRoot ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET})
|
||||
include_directories(${VcpkgRoot}/include)
|
||||
link_directories(${VcpkgRoot}/lib)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${VcpkgRoot}/lib/discord-rpc.lib
|
||||
ZLIB::ZLIB OpenSSL::SSL OpenSSL::Crypto ws2_32)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
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
|
||||
add_definitions("-D_WIN32_WINNT=0x0600")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -s --static")
|
||||
|
||||
@@ -16,5 +16,4 @@ public:
|
||||
static bool ProgressBar(size_t c, size_t t);
|
||||
public:
|
||||
static bool isDownload;
|
||||
static std::string Codes_[];
|
||||
};
|
||||
@@ -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;
|
||||
@@ -13,7 +13,10 @@ void NetReset();
|
||||
extern bool Dev;
|
||||
extern int ping;
|
||||
|
||||
extern bool ModWarningConfirmed;
|
||||
|
||||
[[noreturn]] void CoreNetwork();
|
||||
extern int ProxyPort;
|
||||
extern int ClientID;
|
||||
extern int LastPort;
|
||||
extern bool ModLoaded;
|
||||
@@ -27,6 +30,7 @@ extern std::string LastIP;
|
||||
extern std::string MStatus;
|
||||
extern std::string UlStatus;
|
||||
extern std::string PublicKey;
|
||||
extern std::string PrivateKey;
|
||||
extern std::string ListOfMods;
|
||||
int KillSocket(uint64_t Dead);
|
||||
void UUl(const std::string& R);
|
||||
@@ -44,3 +48,4 @@ void TCPClientMain(const std::string& IP,int Port);
|
||||
void UDPClientMain(const std::string& IP,int Port);
|
||||
void TCPGameServer(const std::string& IP, int Port);
|
||||
|
||||
|
||||
|
||||
@@ -7,10 +7,22 @@
|
||||
///
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <compare>
|
||||
#include <vector>
|
||||
|
||||
void InitLauncher(int argc, char* argv[]);
|
||||
std::string GetEP(char*P = nullptr);
|
||||
std::string GetGamePath();
|
||||
std::string GetVer();
|
||||
std::string GetEN();
|
||||
void StartProxy();
|
||||
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
4642
include/hashpp.h
Normal file
File diff suppressed because it is too large
Load Diff
7578
include/httplib.h
7578
include/httplib.h
File diff suppressed because it is too large
Load Diff
@@ -2,18 +2,18 @@
|
||||
/// Created by Anonymous275 on 2/23/2021
|
||||
///
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "Network/network.h"
|
||||
#include <filesystem>
|
||||
#include "Logger.h"
|
||||
#include <fstream>
|
||||
#include "Json.h"
|
||||
#include <cstdint>
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::string Branch;
|
||||
void ParseConfig(const json::Document& d){
|
||||
if(d["Port"].IsInt()){
|
||||
DEFAULT_PORT = d["Port"].GetInt();
|
||||
void ParseConfig(const nlohmann::json& d){
|
||||
if(d["Port"].is_number()){
|
||||
DEFAULT_PORT = d["Port"].get<int>();
|
||||
}
|
||||
//Default -1
|
||||
//Release 1
|
||||
@@ -21,8 +21,8 @@ void ParseConfig(const json::Document& d){
|
||||
//Dev 3
|
||||
//Custom 3
|
||||
|
||||
if(d["Build"].IsString()){
|
||||
Branch = d["Build"].GetString();
|
||||
if(d["Build"].is_string()){
|
||||
Branch = d["Build"].get<std::string>();
|
||||
for(char& c : Branch)c = char(tolower(c));
|
||||
}
|
||||
}
|
||||
@@ -35,10 +35,9 @@ void ConfigInit(){
|
||||
std::string Buffer(Size, 0);
|
||||
cfg.read(&Buffer[0], Size);
|
||||
cfg.close();
|
||||
json::Document d;
|
||||
d.Parse(Buffer.c_str());
|
||||
if(d.HasParseError()){
|
||||
fatal("Config failed to parse make sure it's valid JSON! Code : " + std::to_string(d.GetParseError()));
|
||||
nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false);
|
||||
if(d.is_discarded()){
|
||||
fatal("Config failed to parse make sure it's valid JSON!");
|
||||
}
|
||||
ParseConfig(d);
|
||||
}else fatal("Failed to open Launcher.cfg!");
|
||||
|
||||
@@ -61,6 +61,7 @@ void StartGame(std::string Dir){
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
exit(2);
|
||||
}
|
||||
|
||||
void InitGame(const std::string& Dir){
|
||||
if(!Dev){
|
||||
std::thread Game(StartGame, Dir);
|
||||
|
||||
@@ -5,14 +5,16 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/20/2020
|
||||
///
|
||||
|
||||
#include "Network/network.h"
|
||||
#include "Security/Init.h"
|
||||
|
||||
#include <regex>
|
||||
#include "Http.h"
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include "Startup.h"
|
||||
#include "Logger.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <charconv>
|
||||
#include <thread>
|
||||
#include <set>
|
||||
@@ -23,6 +25,8 @@ bool TCPTerminate = false;
|
||||
int DEFAULT_PORT = 4444;
|
||||
bool Terminate = false;
|
||||
bool LoginAuth = false;
|
||||
std::string Username = "";
|
||||
std::string UserRole = "";
|
||||
std::string UlStatus;
|
||||
std::string MStatus;
|
||||
bool ModLoaded;
|
||||
@@ -47,6 +51,15 @@ void StartSync(const std::string &Data){
|
||||
GS.detach();
|
||||
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;
|
||||
}
|
||||
|
||||
bool ModWarningConfirmed = false;
|
||||
|
||||
void Parse(std::string Data,SOCKET CSocket){
|
||||
char Code = Data.at(0), SubCode = 0;
|
||||
if(Data.length() > 1)SubCode = Data.at(1);
|
||||
@@ -69,6 +82,27 @@ void Parse(std::string Data,SOCKET CSocket){
|
||||
if(ListOfMods == "-")Data = "L";
|
||||
else Data = "L"+ListOfMods;
|
||||
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;
|
||||
// response to "WMODS_FOUND" message, either Y (yes ok) or N (no)
|
||||
case 'W': {
|
||||
if (SubCode == 'Y') {
|
||||
ModWarningConfirmed = true;
|
||||
} else if (SubCode == 'N') {
|
||||
ModWarningConfirmed = false;
|
||||
NetReset();
|
||||
Terminate = true;
|
||||
TCPTerminate = true;
|
||||
}
|
||||
}
|
||||
case 'P':
|
||||
Data = Code + std::to_string(ProxyPort);
|
||||
break;
|
||||
case 'U':
|
||||
if(SubCode == 'l')Data = UlStatus;
|
||||
if(SubCode == 'p'){
|
||||
@@ -108,7 +142,16 @@ void Parse(std::string Data,SOCKET CSocket){
|
||||
break;
|
||||
case 'N':
|
||||
if (SubCode == 'c'){
|
||||
Data = "N{\"Auth\":"+std::to_string(LoginAuth)+"}";
|
||||
nlohmann::json Auth = {
|
||||
{"Auth", LoginAuth ? 1 : 0 },
|
||||
};
|
||||
if (!Username.empty()) {
|
||||
Auth["username"] = Username;
|
||||
}
|
||||
if (!UserRole.empty()) {
|
||||
Auth["role"] = UserRole;
|
||||
}
|
||||
Data = "N" + Auth.dump();
|
||||
}else{
|
||||
Data = "N" + Login(Data.substr(Data.find(':') + 1));
|
||||
}
|
||||
@@ -175,6 +218,10 @@ void localRes(){
|
||||
}
|
||||
ConfList = new std::set<std::string>;
|
||||
}
|
||||
|
||||
|
||||
uint64_t TheClientSocket;
|
||||
|
||||
void CoreMain() {
|
||||
debug("Core Network on start!");
|
||||
WSADATA wsaData;
|
||||
@@ -223,6 +270,7 @@ void CoreMain() {
|
||||
error("(Core) accept failed with error: " + std::to_string(WSAGetLastError()));
|
||||
continue;
|
||||
}
|
||||
TheClientSocket = CSocket;
|
||||
localRes();
|
||||
info("Game Connected!");
|
||||
GameHandler(CSocket);
|
||||
|
||||
@@ -15,13 +15,6 @@
|
||||
#include <cmath>
|
||||
#include <httplib.h>
|
||||
|
||||
std::string HTTP::Codes_[] =
|
||||
{
|
||||
"Success","Unknown","Connection","BindIPAddress",
|
||||
"Read","Write","ExceedRedirectCount","Canceled",
|
||||
"SSLConnection","SSLLoadingCerts","SSLServerVerification",
|
||||
"UnsupportedMultipartBoundaryChars","Compression"
|
||||
};
|
||||
bool HTTP::isDownload = false;
|
||||
std::string HTTP::Get(const std::string &IP) {
|
||||
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);
|
||||
std::string Ret;
|
||||
|
||||
if(res.error() == 0){
|
||||
if(res){
|
||||
if(res->status == 200){
|
||||
Ret = res->body;
|
||||
}else error(res->reason);
|
||||
@@ -44,7 +37,7 @@ std::string HTTP::Get(const std::string &IP) {
|
||||
if(isDownload) {
|
||||
std::cout << "\n";
|
||||
}
|
||||
error("HTTP Get failed on " + Codes_[res.error()]);
|
||||
error("HTTP Get failed on " + to_string(res.error()));
|
||||
}
|
||||
|
||||
return Ret;
|
||||
@@ -63,23 +56,23 @@ std::string HTTP::Post(const std::string& IP, const std::string& Fields) {
|
||||
if(!Fields.empty()) {
|
||||
httplib::Result res = cli.Post(IP.substr(pos).c_str(), Fields, "application/json");
|
||||
|
||||
if(res.error() == 0) {
|
||||
if(res) {
|
||||
if (res->status != 200) {
|
||||
error(res->reason);
|
||||
}
|
||||
Ret = res->body;
|
||||
}else{
|
||||
error("HTTP Post failed on " + Codes_[res.error()]);
|
||||
error("HTTP Post failed on " + to_string(res.error()));
|
||||
}
|
||||
}else{
|
||||
httplib::Result res = cli.Post(IP.substr(pos).c_str());
|
||||
if(res.error() == 0) {
|
||||
if(res) {
|
||||
if (res->status != 200) {
|
||||
error(res->reason);
|
||||
}
|
||||
Ret = res->body;
|
||||
}else{
|
||||
error("HTTP Post failed on " + Codes_[res.error()]);
|
||||
error("HTTP Post failed on " + to_string(res.error()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <future>
|
||||
#include <cmath>
|
||||
|
||||
extern SOCKET TheClientSocket;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
std::string ListOfMods;
|
||||
std::vector<std::string> Split(const std::string& String,const std::string& delimiter){
|
||||
@@ -102,7 +104,7 @@ std::string Auth(SOCKET Sock){
|
||||
return Res;
|
||||
}
|
||||
|
||||
void UpdateUl(bool D,const std::string&msg){
|
||||
void UpdateUl(bool D,const std::string& msg){
|
||||
if(D)UlStatus = "UlDownloading Resource " + msg;
|
||||
else UlStatus = "UlLoading Resource " + msg;
|
||||
}
|
||||
@@ -221,6 +223,23 @@ void SyncResources(SOCKET Sock){
|
||||
std::string Ret = Auth(Sock);
|
||||
if(Ret.empty())return;
|
||||
|
||||
ModWarningConfirmed = false;
|
||||
Terminate = false;
|
||||
|
||||
std::string Data = "WMODS_FOUND";
|
||||
send(TheClientSocket, (Data + "\n").c_str(), int(Data.size())+1, 0);
|
||||
|
||||
while (!Terminate && !ModWarningConfirmed) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
if (!ModWarningConfirmed) {
|
||||
UlStatus = "UlMods rejected!";
|
||||
info("Mods rejected by user!");
|
||||
// game has already cancelled by now
|
||||
return;
|
||||
}
|
||||
|
||||
info("Checking Resources...");
|
||||
CheckForDir();
|
||||
|
||||
@@ -267,8 +286,10 @@ void SyncResources(SOCKET Sock){
|
||||
if(!fs::exists(GetGamePath() + "mods/multiplayer")){
|
||||
fs::create_directories(GetGamePath() + "mods/multiplayer");
|
||||
}
|
||||
fs::copy_file(a, GetGamePath() + "mods/multiplayer" + a.substr(a.find_last_of('/')),
|
||||
fs::copy_options::overwrite_existing);
|
||||
auto name = GetGamePath() + "mods/multiplayer" + a.substr(a.find_last_of('/'));
|
||||
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) {
|
||||
error("Failed copy to the mods folder! " + std::string(e.what()));
|
||||
Terminate = true;
|
||||
@@ -320,4 +341,4 @@ void SyncResources(SOCKET Sock){
|
||||
UlStatus = "Ulstart";
|
||||
info("Connection Terminated!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,9 +144,9 @@ void FileList(std::vector<std::string>&a,const std::string& Path){
|
||||
for (const auto &entry : fs::directory_iterator(Path)) {
|
||||
const auto& DPath = entry.path();
|
||||
if (!entry.is_directory()) {
|
||||
a.emplace_back(DPath.u8string());
|
||||
}else if(NameValid(DPath.filename().u8string())){
|
||||
FileList(a, DPath.u8string());
|
||||
a.emplace_back(DPath.string());
|
||||
}else if(NameValid(DPath.filename().string())){
|
||||
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 s = true;
|
||||
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));
|
||||
if(Name == "steam.exe")s = false;
|
||||
if(Name.find("greenluma") != -1){
|
||||
|
||||
@@ -6,19 +6,23 @@
|
||||
/// Created by Anonymous275 on 11/26/2020
|
||||
///
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "Http.h"
|
||||
#include <filesystem>
|
||||
#include "Logger.h"
|
||||
#include <fstream>
|
||||
#include "Json.h"
|
||||
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
std::string PublicKey;
|
||||
std::string PrivateKey;
|
||||
extern bool LoginAuth;
|
||||
std::string Role;
|
||||
extern std::string Username;
|
||||
extern std::string UserRole;
|
||||
|
||||
void UpdateKey(const char* newKey){
|
||||
if(newKey && std::isalnum(newKey[0])){
|
||||
PrivateKey = newKey;
|
||||
std::ofstream Key("key");
|
||||
if(Key.is_open()){
|
||||
Key << newKey;
|
||||
@@ -42,41 +46,51 @@ std::string GetFail(const std::string& R){
|
||||
|
||||
std::string Login(const std::string& fields){
|
||||
if(fields == "LO"){
|
||||
Username = "";
|
||||
UserRole = "";
|
||||
LoginAuth = false;
|
||||
UpdateKey(nullptr);
|
||||
return "";
|
||||
}
|
||||
info("Attempting to authenticate...");
|
||||
std::string Buffer = HTTP::Post("https://auth.beammp.com/userlogin", fields);
|
||||
json::Document d;
|
||||
d.Parse(Buffer.c_str());
|
||||
if(Buffer == "-1"){
|
||||
return GetFail("Failed to communicate with the auth system!");
|
||||
}
|
||||
try {
|
||||
std::string Buffer = HTTP::Post("https://auth.beammp.com/userlogin", fields);
|
||||
|
||||
if (Buffer.at(0) != '{' || d.HasParseError()) {
|
||||
error(Buffer);
|
||||
return GetFail("Invalid answer from authentication servers, please try again later!");
|
||||
}
|
||||
if(!d["success"].IsNull() && d["success"].GetBool()){
|
||||
LoginAuth = true;
|
||||
if(!d["private_key"].IsNull()){
|
||||
UpdateKey(d["private_key"].GetString());
|
||||
if(Buffer == "-1"){
|
||||
return GetFail("Failed to communicate with the auth system!");
|
||||
}
|
||||
if(!d["public_key"].IsNull()){
|
||||
PublicKey = d["public_key"].GetString();
|
||||
|
||||
nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false);
|
||||
|
||||
if (Buffer.at(0) != '{' || d.is_discarded()) {
|
||||
error(Buffer);
|
||||
return GetFail("Invalid answer from authentication servers, please try again later!");
|
||||
}
|
||||
info("Authentication successful!");
|
||||
}else info("Authentication failed!");
|
||||
if(!d["message"].IsNull()){
|
||||
d.RemoveMember("private_key");
|
||||
d.RemoveMember("public_key");
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
d.Accept(writer);
|
||||
return buffer.GetString();
|
||||
if(d.contains("success") && d["success"].get<bool>()){
|
||||
LoginAuth = true;
|
||||
if (d.contains("username")) {
|
||||
Username = d["username"].get<std::string>();
|
||||
}
|
||||
if (d.contains("role")) {
|
||||
UserRole = d["role"].get<std::string>();
|
||||
}
|
||||
if(d.contains("private_key")) {
|
||||
UpdateKey(d["private_key"].get<std::string>().c_str());
|
||||
}
|
||||
if(d.contains("public_key")){
|
||||
PublicKey = d["public_key"].get<std::string>();
|
||||
}
|
||||
info("Authentication successful!");
|
||||
}else info("Authentication failed!");
|
||||
if(d.contains("message")){
|
||||
d.erase("private_key");
|
||||
d.erase("public_key");
|
||||
return d.dump();
|
||||
}
|
||||
return GetFail("Invalid message parsing!");
|
||||
} catch (const std::exception& e) {
|
||||
return GetFail(e.what());
|
||||
}
|
||||
return GetFail("Invalid message parsing!");
|
||||
}
|
||||
|
||||
void CheckLocalKey(){
|
||||
@@ -97,18 +111,23 @@ void CheckLocalKey(){
|
||||
|
||||
Buffer = HTTP::Post("https://auth.beammp.com/userlogin", R"({"pk":")" + Buffer + "\"}");
|
||||
|
||||
json::Document d;
|
||||
d.Parse(Buffer.c_str());
|
||||
if (Buffer == "-1" || Buffer.at(0) != '{' || d.HasParseError()) {
|
||||
nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false);
|
||||
|
||||
if (Buffer == "-1" || Buffer.at(0) != '{' || d.is_discarded()) {
|
||||
error(Buffer);
|
||||
info("Invalid answer from authentication servers.");
|
||||
UpdateKey(nullptr);
|
||||
}
|
||||
if(d["success"].GetBool()){
|
||||
if(d["success"].get<bool>()){
|
||||
LoginAuth = true;
|
||||
UpdateKey(d["private_key"].GetString());
|
||||
PublicKey = d["public_key"].GetString();
|
||||
Role = d["role"].GetString();
|
||||
UpdateKey(d["private_key"].get<std::string>().c_str());
|
||||
PublicKey = d["public_key"].get<std::string>();
|
||||
if (d.contains("username")) {
|
||||
Username = d["username"].get<std::string>();
|
||||
}
|
||||
if (d.contains("role")) {
|
||||
UserRole = d["role"].get<std::string>();
|
||||
}
|
||||
//info(Role);
|
||||
}else{
|
||||
info("Auto-Authentication unsuccessful please re-login!");
|
||||
|
||||
203
src/Startup.cpp
203
src/Startup.cpp
@@ -5,6 +5,9 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/16/2020
|
||||
///
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <httplib.h>
|
||||
#include "zip_file.h"
|
||||
#include <windows.h>
|
||||
#include "Discord/discord_info.h"
|
||||
@@ -12,16 +15,46 @@
|
||||
#include "Security/Init.h"
|
||||
#include <filesystem>
|
||||
#include "Startup.h"
|
||||
#include "hashpp.h"
|
||||
#include "Logger.h"
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
#include "Http.h"
|
||||
#include "Json.h"
|
||||
|
||||
|
||||
extern int TraceBack;
|
||||
bool Dev = false;
|
||||
int ProxyPort = 0;
|
||||
|
||||
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(){
|
||||
return "BeamMP-Launcher.exe";
|
||||
}
|
||||
@@ -29,7 +62,7 @@ std::string GetVer(){
|
||||
return "2.0";
|
||||
}
|
||||
std::string GetPatch(){
|
||||
return ".82";
|
||||
return ".85";
|
||||
}
|
||||
|
||||
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){
|
||||
std::string link;
|
||||
std::string HTTP = HTTP::Get("https://beammp.com/builds/launcher?version=true");
|
||||
bool fallback = false;
|
||||
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";
|
||||
void CheckForUpdates(int argc, char* args[], 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);
|
||||
|
||||
transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower);
|
||||
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){
|
||||
system("cls");
|
||||
info("Update found!");
|
||||
info("Updating...");
|
||||
if(std::rename(EP.c_str(), Back.c_str()))error("failed creating a backup!");
|
||||
|
||||
if(!HTTP::Download(link, EP)){
|
||||
error("Launcher Update failed! trying again...");
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
|
||||
if(!HTTP::Download(link, EP)){
|
||||
error("Launcher Update failed!");
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
ReLaunch(argc,args);
|
||||
}
|
||||
}
|
||||
URelaunch(argc,args);
|
||||
}else info("Launcher version is up to date");
|
||||
if (FileHash != LatestHash && VersionParser(LatestVersion) > VersionParser(GetVer()+GetPatch())) {
|
||||
info("Launcher update found!");
|
||||
fs::remove(Back);
|
||||
fs::rename(EP, Back);
|
||||
info("Downloading Launcher update " + LatestHash);
|
||||
HTTP::Download(
|
||||
"https://backend.beammp.com/builds/launcher?download=true"
|
||||
"&pk=" +
|
||||
PublicKey + "&branch=" + Branch,
|
||||
EP);
|
||||
URelaunch(argc, args);
|
||||
} else info("Launcher version is up to date");
|
||||
TraceBack++;
|
||||
}
|
||||
|
||||
@@ -148,31 +166,6 @@ void LinuxPatch(){
|
||||
}
|
||||
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!");
|
||||
}
|
||||
|
||||
@@ -199,13 +192,13 @@ void CheckMP(const std::string& Path) {
|
||||
try {
|
||||
for (auto& p : fs::directory_iterator(Path)){
|
||||
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));
|
||||
if(Name != "beammp.zip")fs::remove(p.path());
|
||||
}
|
||||
}
|
||||
} 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?");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -220,20 +213,16 @@ void EnableMP(){
|
||||
std::string Data(Size, 0);
|
||||
db.read(&Data[0], Size);
|
||||
db.close();
|
||||
json::Document d;
|
||||
d.Parse(Data.c_str());
|
||||
if(Data.at(0) != '{' || d.HasParseError()){
|
||||
nlohmann::json d = nlohmann::json::parse(Data, nullptr, false);
|
||||
if(Data.at(0) != '{' || d.is_discarded()) {
|
||||
//error("Failed to parse " + File); //TODO illegal formatting
|
||||
return;
|
||||
}
|
||||
if(!d["mods"].IsNull() && !d["mods"]["multiplayerbeammp"].IsNull()){
|
||||
if(d.contains("mods") && d["mods"].contains("multiplayerbeammp")){
|
||||
d["mods"]["multiplayerbeammp"]["active"] = true;
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
d.Accept(writer);
|
||||
std::ofstream ofs(File);
|
||||
if(ofs.is_open()){
|
||||
ofs << buffer.GetString();
|
||||
ofs << d.dump();
|
||||
ofs.close();
|
||||
}else{
|
||||
error("Failed to write " + File);
|
||||
@@ -249,7 +238,11 @@ void PreGame(const std::string& GamePath){
|
||||
CheckMP(GetGamePath() + "mods/multiplayer");
|
||||
|
||||
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 {
|
||||
if (!fs::exists(GetGamePath() + "mods/multiplayer")) {
|
||||
fs::create_directories(GetGamePath() + "mods/multiplayer");
|
||||
@@ -258,18 +251,76 @@ void PreGame(const std::string& GamePath){
|
||||
}catch(std::exception&e){
|
||||
fatal(e.what());
|
||||
}
|
||||
|
||||
std::string ZipPath(GetGamePath() + R"(mods\multiplayer\BeamMP.zip)");
|
||||
|
||||
HTTP::Download("https://backend.beammp.com/builds/client?download=true"
|
||||
"&pk=" + PublicKey + "&branch=" + Branch, ZipPath);
|
||||
std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, 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");
|
||||
|
||||
if(fs::is_directory(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-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();
|
||||
}
|
||||
|
||||
13
src/main.cpp
13
src/main.cpp
@@ -21,20 +21,21 @@
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef DEBUG
|
||||
std::thread th(flush);
|
||||
th.detach();
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
std::thread th(flush);
|
||||
th.detach();
|
||||
#endif
|
||||
GetEP(argv[0]);
|
||||
|
||||
InitLauncher(argc,argv);
|
||||
InitLauncher(argc, argv);
|
||||
|
||||
try {
|
||||
LegitimacyCheck();
|
||||
}catch (std::exception& e){
|
||||
} catch (std::exception &e) {
|
||||
fatal("Main 1 : " + std::string(e.what()));
|
||||
}
|
||||
|
||||
StartProxy();
|
||||
PreGame(GetGameDir());
|
||||
InitGame(GetGameDir());
|
||||
CoreNetwork();
|
||||
|
||||
Reference in New Issue
Block a user