- new backend links

- self updating
- add open_url lua function with filter
This commit is contained in:
Anonymous-275 2023-07-12 21:30:05 +01:00
parent 58e9fef53f
commit a504114809
10 changed files with 4822 additions and 114 deletions

View File

@ -35,7 +35,7 @@ add_executable(${PROJECT_NAME}
src/Memory/IPC.cpp include/Memory/IPC.h
src/Logger.cpp include/Logger.h
#src/gui/Gui.cpp
include/Json.h
include/Json.h include/hashpp.h
src/Network/HttpAPI.cpp include/HttpAPI.h
src/Network/Server.cpp include/Server.h
src/Network/Login.cpp src/Network/Update.cpp

View File

@ -33,10 +33,12 @@ class Launcher {
void SendIPC(const std::string& Data, bool core = true);
void LoadConfig(const fs::path& conf);
void RunDiscordRPC();
void UpdateCheck();
void WaitForGame();
void LaunchGame();
void CheckKey();
void SetupMOD();
static std::string QueryValue(HKEY& hKey, const char* Name);
public: // Getters and Setters
@ -53,6 +55,7 @@ class Launcher {
private: // functions
void HandleIPC(const std::string& Data);
bool IsAllowedLink(const std::string& Link);
std::string GetProfileVersion();
fs::path GetProfileRoot();
void UpdatePresence();
@ -65,8 +68,8 @@ class Launcher {
public: // variables
static inline std::thread EntryThread{};
static inline std::string Version{"2.0"};
static inline std::string FullVersion{Version + ".99"};
static inline std::string Version{"2.1"};
static inline std::string FullVersion{Version + ".0"};
private: // variables
uint32_t GamePID{0};

4642
include/hashpp.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -48,7 +48,8 @@ void Launcher::LoadConfig(const fs::path& conf) { // check if json (issue)
auto GameProfile = GetProfileRoot();
std::ofstream tml(conf);
if (tml.is_open()) {
tml << "Build = 'Default'\n"
tml << "# Build is the lua build, it can be either default, canary, or public\n"
"Build = 'default'\n"
"CachePath = 'Resources'\n"
"ProfilePath = '"
<< GameProfile.string() << "'";

View File

@ -8,57 +8,69 @@
#include "Logger.h"
#include "Memory/BeamNG.h"
#include "Memory/Memory.h"
#include <regex>
void Launcher::HandleIPC(const std::string& Data) { //TODO Improve all cases since SendIPC can be called async
char Code = Data.at(0), SubCode = 0;
if (Data.length() > 1) SubCode = Data.at(1);
switch (Code) {
case 'A':
ServerHandler.StartUDP();
break;
case 'B':
ServerHandler.Close();
SendIPC(Code + HTTP::Get("https://backend.beammp.com/servers-info"));
LOG(INFO) << "Sent Server List";
break;
case 'C':
ServerHandler.Close();
ServerHandler.Connect(Data);
while (ServerHandler.getModList().empty() &&
!ServerHandler.Terminated()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
if (ServerHandler.getModList() == "-") SendIPC("L");
else SendIPC("L" + ServerHandler.getModList());
break;
case 'U':
SendIPC("Ul" + ServerHandler.getUIStatus());
break;
case 'M':
SendIPC(ServerHandler.getMap());
break;
case 'Q':
if (SubCode == 'S') {
char Code = Data.at(0), SubCode = 0;
if (Data.length() > 1) SubCode = Data.at(1);
switch (Code) {
case 'A':
ServerHandler.StartUDP();
break;
case 'B':
ServerHandler.Close();
}
if (SubCode == 'G') exit(2);
break;
case 'R': // will send mod name
ServerHandler.setModLoaded();
break;
case 'Z':
SendIPC("Z" + Version);
break;
case 'N':
if (SubCode == 'c') {
SendIPC("N{\"Auth\":" + std::to_string(LoginAuth) + "}");
} else {
SendIPC("N" + Login(Data.substr(Data.find(':') + 1)));
}
break;
default:
break;
}
SendIPC(Code + HTTP::Get("https://backend.beammp.com/servers-info"));
LOG(INFO) << "Sent Server List";
break;
case 'C':
ServerHandler.Close();
ServerHandler.Connect(Data);
while (ServerHandler.getModList().empty() &&
!ServerHandler.Terminated()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
if (ServerHandler.getModList() == "-") SendIPC("L");
else SendIPC("L" + ServerHandler.getModList());
break;
case 'U':
SendIPC("Ul" + ServerHandler.getUIStatus());
break;
case 'M':
SendIPC(ServerHandler.getMap());
break;
case 'Q':
if (SubCode == 'S') {
ServerHandler.Close();
}
if (SubCode == 'G') exit(2);
break;
case 'R': // will send mod name
ServerHandler.setModLoaded();
break;
case 'Z':
SendIPC("Z" + Version);
break;
case 'N':
if (SubCode == 'c') {
SendIPC("N{\"Auth\":" + std::to_string(LoginAuth) + "}");
} else {
SendIPC("N" + Login(Data.substr(Data.find(':') + 1)));
}
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
}
break;
default:
break;
}
}
bool Launcher::IsAllowedLink(const std::string& Link) {
std::regex link_pattern(R"(https:\/\/(?:\w+)?(?:\.)?(?:beammp|discord)\.com)");
std::smatch link_match;
return std::regex_search(Link,link_match, link_pattern) && link_match.position() == 0;
}
void Server::ServerParser(const std::string& Data) {

View File

@ -31,7 +31,7 @@ Launcher::Launcher(int argc, char* argv[]) :
DiscordTime = std::time(nullptr);
WindowsInit();
SetUnhandledExceptionFilter(CrashHandler);
LOG(INFO) << "Starting Launcher V" << FullVersion;
LOG(INFO) << "Starting Launcher v" << FullVersion;
if (argc > 1) LoadConfig(fs::current_path() / argv[1]);
else LoadConfig(fs::current_path() / "Launcher.toml");
}
@ -234,4 +234,4 @@ const fs::path& Launcher::getCachePath() {
fs::create_directories(LauncherCache);
}
return LauncherCache;
}
}

View File

@ -97,14 +97,25 @@ int LuaPop(lua_State* L) {
return 0;
}
int LuaOpenURL(lua_State* L) {
if (lua_gettop(L) == 1) {
size_t Size;
const char* Data = GELua::lua_tolstring(L, 1, &Size);
std::string msg(Data, Size);
BeamNG::SendIPC("CO" + msg);
}
return 0;
}
void BeamNG::RegisterGEFunctions() {
Memory::Print("Registering GE Functions");
GELuaTable::Begin(GELua::State);
GELuaTable::InsertFunction(GELua::State, "Core", Core);
GELuaTable::InsertFunction(GELua::State, "Game", Game);
GELuaTable::InsertFunction(GELua::State, "try_pop", LuaPop);
GELuaTable::End(GELua::State, "MP");
Memory::Print("Registered!");
Memory::Print("Registering GE Functions");
GELuaTable::Begin(GELua::State);
GELuaTable::InsertFunction(GELua::State, "Core", Core);
GELuaTable::InsertFunction(GELua::State, "Game", Game);
GELuaTable::InsertFunction(GELua::State, "try_pop", LuaPop);
GELuaTable::InsertFunction(GELua::State, "open_url", LuaOpenURL);
GELuaTable::End(GELua::State, "MP");
Memory::Print("Registered!");
}
void BeamNG::SendIPC(const std::string& Data) {

View File

@ -35,43 +35,47 @@ std::string GetFail(const std::string& R) {
}
std::string Launcher::Login(const std::string& fields) {
if (fields == "LO") {
LoginAuth = false;
UpdateKey("");
return "";
}
LOG(INFO) << "Attempting to authenticate...";
std::string Buffer = HTTP::Post("https://auth.beammp.com/userlogin", fields);
Json d = Json::parse(Buffer, nullptr, false);
if (fields == "LO") {
LoginAuth = false;
UpdateKey("");
return "";
}
LOG(INFO) << "Attempting to authenticate...";
std::string Buffer = HTTP::Post("https://auth.beammp.com/userlogin", fields);
Json d = Json::parse(Buffer, nullptr, false);
if (Buffer == "-1") {
return GetFail("Failed to communicate with the auth system!");
}
if (Buffer == "-1") {
return GetFail("Failed to communicate with the auth system!");
}
if (Buffer.at(0) != '{' || d.is_discarded()) {
LOG(ERROR) << Buffer;
return GetFail(
"Invalid answer from authentication servers, please try again "
"later!");
}
if (Buffer.at(0) != '{' || d.is_discarded()) {
LOG(ERROR) << Buffer;
return GetFail(
"Invalid answer from authentication servers, please try again "
"later!");
}
if (!d["success"].is_null() && d["success"].get<bool>()) {
LoginAuth = true;
if (!d["private_key"].is_null()) {
UpdateKey(d["private_key"].get<std::string>());
}
if (!d["public_key"].is_null()) {
PublicKey = d["public_key"].get<std::string>();
}
LOG(INFO) << "Authentication successful!";
} else LOG(WARNING) << "Authentication failed!";
if (!d["success"].is_null() && d["success"].get<bool>()) {
LoginAuth = true;
if (!d["private_key"].is_null()) {
UpdateKey(d["private_key"].get<std::string>());
}
if (!d["public_key"].is_null()) {
PublicKey = d["public_key"].get<std::string>();
}
if (!d["role"].is_null()) {
UserRole = d["role"].get<std::string>();
}
LOG(INFO) << "Authentication successful!";
} else
LOG(WARNING) << "Authentication failed!";
if (!d["message"].is_null()) {
d.erase("private_key");
d.erase("public_key");
return d.dump();
}
return GetFail("Invalid message parsing!");
if (!d["message"].is_null()) {
d.erase("private_key");
d.erase("public_key");
return d.dump();
}
return GetFail("Invalid message parsing!");
}
void Launcher::CheckKey() {

View File

@ -7,6 +7,7 @@
#include "Json.h"
#include "Launcher.h"
#include "Logger.h"
#include "hashpp.h"
VersionParser::VersionParser(const std::string& from_string) {
std::string token;
@ -40,17 +41,20 @@ size_t DirCount(const std::filesystem::path& path) {
}
void Launcher::ResetMods() {
if (!fs::exists(MPUserPath)) {
fs::create_directories(MPUserPath);
return;
}
if (DirCount(MPUserPath) > 3) {
LOG(WARNING)
<< "mods/multiplayer will be cleared in 15 seconds, close to abort";
std::this_thread::sleep_for(std::chrono::seconds(15));
}
fs::remove_all(MPUserPath);
fs::create_directories(MPUserPath);
if (!fs::exists(MPUserPath)) {
fs::create_directories(MPUserPath);
return;
}
if (DirCount(MPUserPath) > 3) {
LOG(WARNING)
<< "mods/multiplayer will be cleared in 15 seconds, close to abort";
std::this_thread::sleep_for(std::chrono::seconds(15));
}
for (auto &de: std::filesystem::directory_iterator(MPUserPath)) {
if (de.path().filename() != "BeamMP.zip") {
std::filesystem::remove(de.path());
}
}
}
void Launcher::EnableMP() {
@ -78,13 +82,43 @@ void Launcher::EnableMP() {
}
}
void Launcher::SetupMOD() {
ResetMods();
EnableMP();
LOG(INFO) << "Downloading mod please wait";
HTTP::Download(
"https://backend.beammp.com/builds/client?download=true"
"&pk=" +
PublicKey + "&branch=" + TargetBuild,
(MPUserPath/"BeamMP.zip").string());
std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/mod?branch=" + TargetBuild + "&pk=" + PublicKey);
transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower);
std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, (MPUserPath / "BeamMP.zip").string());
ResetMods();
EnableMP();
if (FileHash != LatestHash) {
LOG(INFO) << "Downloading BeamMP Update " << LatestHash;
HTTP::Download(
"https://backend.beammp.com/builds/mod?download=true"
"&pk=" +
PublicKey + "&branch=" + TargetBuild,
(MPUserPath / "BeamMP.zip").string());
}
}
void Launcher::UpdateCheck() {
std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/launcher?branch=" + TargetBuild + "&pk=" + PublicKey);
transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower);
std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, "BeamMP-Launcher.exe");
if(FileHash != LatestHash) {
LOG(INFO) << "Launcher update found!";
fs::remove("BeamMP-Launcher.back");
fs::rename("BeamMP-Launcher.exe", "BeamMP-Launcher.back");
LOG(INFO) << "Downloading Launcher update " << LatestHash;
HTTP::Download(
"https://backend.beammp.com/builds/launcher?download=true"
"&pk=" +
PublicKey + "&branch=" + TargetBuild,
"BeamMP-Launcher.exe");
throw ShutdownException("Launcher update");
}
}

View File

@ -9,9 +9,10 @@
int main(int argc, char* argv[]) {
try {
Launcher launcher(argc, argv);
launcher.UpdateCheck();
launcher.RunDiscordRPC();
launcher.CheckKey();
// launcher.SetupMOD();
launcher.SetupMOD();
launcher.LaunchGame();
launcher.WaitForGame();
LOG(INFO) << "Launcher shutting down";