57 Commits

Author SHA1 Message Date
Anonymous275
fb59b6997c Create release-build.yml 2021-04-04 23:37:32 +03:00
Anonymous275
a1f5ec9ba5 Update cmake-windows.yml 2021-04-04 23:23:11 +03:00
Anonymous-275
989ac981be Merge branch 'master' of ssh://github.com/BeamMP/BeamMP-Launcher 2021-04-04 23:22:02 +03:00
Anonymous-275
d425b8035a Update CMakeLists.txt 2021-04-04 23:22:00 +03:00
Anonymous275
f0540c2df5 Update cmake-windows.yml 2021-04-04 23:08:07 +03:00
Anonymous275
9df08025ad Create cmake-windows.yml 2021-04-04 23:02:40 +03:00
Anonymous-275
bb732f102f v2.0.2 2021-04-04 22:49:52 +03:00
Anonymous-275
ec3bcffe7c New header only http library 2021-04-04 19:20:25 +03:00
Anonymous-275
e70cf0f877 Fixed launcher crash in wine! 2021-04-02 03:52:31 +03:00
Anonymous-275
b40ab5e36a V2.0.1 2021-03-31 23:18:09 +03:00
Anonymous-275
54a27f5c4c Bump to 0.22.1.0 2021-03-31 22:57:05 +03:00
Anonymous-275
37cfec9fdc Added chat to reliable 2021-03-30 23:31:11 +03:00
Anonymous-275
16f0769f87 fixed new custom profile directory 2021-03-30 03:07:49 +03:00
Starystars67
9f1e58bb70 Launcher v2 updated strings 2021-03-29 22:15:50 +01:00
Anonymous-275
83b43d782d Small tweak 2021-03-30 00:03:43 +03:00
Anonymous-275
3a0b96da52 Client mod download system update 2021-03-30 00:01:20 +03:00
Anonymous-275
aa2b07b359 Updated Supported version 2021-03-29 23:34:49 +03:00
Anonymous-275
289402a9ba Switched to new default userdata 2021-03-29 23:29:03 +03:00
Anonymous-275
1afa81e420 updated submodule 2021-03-29 21:45:32 +03:00
Starystars67
ae6725ece3 Possible fix for new backend linix ~Anonymous275 2021-03-29 19:00:23 +01:00
Anonymous-275
fff747afca Replaced cURL with evpp 2021-03-29 16:43:17 +03:00
Anonymous-275
5c1b7b1dbf updated submodule 2021-03-29 16:13:00 +03:00
Anonymous-275
e290910312 updated submodule 2021-03-29 12:44:48 +03:00
Anonymous-275
fb7831d629 Added evpp with git link 2021-03-29 11:57:58 +03:00
Anonymous-275
5b4b930701 Removed broken module link 2021-03-29 11:52:03 +03:00
Anonymous-275
fe59083257 Added evpp 2021-03-29 11:47:49 +03:00
Anonymous-275
fbc5e28d25 Mingw Compatible 2021-03-29 11:43:24 +03:00
Anonymous275
d96f968dde Cleanup 2021-02-22 23:00:54 +02:00
Anonymous275
ba5ba4b8b4 Partial fix for directory startup location 2021-02-22 20:09:36 +02:00
Anonymous275
263b6c9c0d Potential auth fix 2021-01-07 15:28:51 +02:00
Anonymous275
78875c2c9c Fixed single player, fixed duplicated multiplayer mods 2021-01-02 20:58:23 +02:00
Anonymous275
8e55edaa29 1.80.92, fixed some startup crashes 2021-01-02 02:02:50 +02:00
Anonymous275
c77f8742b4 Update BeamNG.cpp 2021-01-01 16:40:37 +02:00
Anonymous275
0a58001b09 Update BeamNG.cpp 2021-01-01 16:39:31 +02:00
Anonymous275
075d4a8c4d 1.80.91 2021-01-01 16:36:44 +02:00
Anonymous275
00313e32f9 Merge pull request #3 from finicu212/patch-1
Close #2: Alert user of what malicious file has been found
2021-01-01 16:34:45 +02:00
Anonymous275
16ea84b4cf Merge branch 'master' into patch-1 2021-01-01 16:34:27 +02:00
Anonymous275
6b124e89a8 Update BeamNG.cpp 2020-12-28 18:07:04 +02:00
Anonymous275
543183b852 launcher is now more linux friendly 2020-12-28 18:05:32 +02:00
Anonymous275
fda7567044 fixed crash -report 2020-12-28 16:34:24 +02:00
Anonymous275
6b4211d9cf bump to 1.80.8 2020-12-27 23:34:19 +02:00
Anonymous275
3572a188d1 added try catch 2020-12-27 23:21:41 +02:00
Anonymous275
775e44a68f fixed crash when starting up 2020-12-27 23:19:24 +02:00
Anonymous275
eaa8796c02 final hotfix 2020-12-27 06:34:11 +02:00
Anonymous275
2a03448b3f Fix for custom document location 2020-12-27 06:31:03 +02:00
Anonymous275
9734a7f3d5 Hotfix 2020-12-27 05:50:51 +02:00
Anonymous275
e207f2febd Potential default dir fix 2020-12-27 05:14:02 +02:00
Anonymous275
9f821a01f0 Mod downloading hotfix 2020-12-27 00:23:58 +02:00
Anonymous275
9a04665c34 Unicode path support 2020-12-26 23:35:43 +02:00
Anonymous275
ab2a58bf42 switched to normal filesystem + crash fixes 2020-12-26 22:52:01 +02:00
finicu
32bcbac979 Alert user of what malicious file has been found 2020-12-26 13:34:09 +02:00
Anonymous275
757ac6303b Update README.md 2020-12-23 21:03:05 +02:00
Anonymous275
20ba2b9e0a Update README.md 2020-12-23 20:47:23 +02:00
Anonymous275
99006627a4 Update README.md 2020-12-23 20:46:17 +02:00
Anonymous275
7cd25fbb22 fixed mod downloading stuck at 50% 2020-12-22 19:38:01 +02:00
Anonymous275
76a1b05056 Update Login.cpp 2020-12-22 17:19:02 +02:00
Anonymous275
b7ffa153b1 Added more error returns on auth fail 2020-12-22 17:12:38 +02:00
72 changed files with 8651 additions and 817 deletions

43
.github/workflows/cmake-windows.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: CMake Windows Build
on: [push, pull_request]
env:
BUILD_TYPE: Release
jobs:
windows-build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
with:
submodules: 'true'
- name: Restore artifacts, or run vcpkg, build and cache artifacts
uses: lukka/run-vcpkg@main
id: runvcpkg
with:
vcpkgArguments: 'discord-rpc zlib rapidjson openssl'
vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg'
vcpkgGitCommitId: '75522bb1f2e7d863078bcd06322348f053a9e33f'
vcpkgTriplet: 'x64-windows-static'
- name: Create Build Environment
run: cmake -E make_directory ${{github.workspace}}/build-windows
- name: Configure CMake
shell: bash
working-directory: ${{github.workspace}}/build-windows
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE='${{ runner.workspace }}/b/vcpkg/scripts/buildsystems/vcpkg.cmake' -DVCPKG_TARGET_TRIPLET=x64-windows-static
- name: Build
working-directory: ${{github.workspace}}/build-windows
shell: bash
run: cmake --build . --config $BUILD_TYPE
- name: Archive artifacts
uses: actions/upload-artifact@v2
with:
name: BeamMP-Launcher.exe
path: ${{github.workspace}}/build-windows/Release/BeamMP-Launcher.exe

72
.github/workflows/release-build.yml vendored Normal file
View File

@@ -0,0 +1,72 @@
name: Release Create & Build
on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
env:
BUILD_TYPE: Release
jobs:
create-release:
runs-on: ubuntu-latest
name: Create Release
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
body: |
Files included in this release:
- `BeamMP-Launcher.exe` windows build
upload-release-files-windows:
name: Upload Windows Release Files
runs-on: windows-latest
needs: create-release
steps:
- uses: actions/checkout@v2
with:
submodules: 'true'
- name: Restore artifacts, or run vcpkg, build and cache artifacts
uses: lukka/run-vcpkg@main
id: runvcpkg
with:
vcpkgArguments: 'discord-rpc zlib rapidjson openssl'
vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg'
vcpkgGitCommitId: '75522bb1f2e7d863078bcd06322348f053a9e33f'
vcpkgTriplet: 'x64-windows-static'
- name: Create Build Environment
run: cmake -E make_directory ${{github.workspace}}/build-windows
- name: Configure CMake
shell: bash
working-directory: ${{github.workspace}}/build-windows
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE='${{ runner.workspace }}/b/vcpkg/scripts/buildsystems/vcpkg.cmake' -DVCPKG_TARGET_TRIPLET=x64-windows-static
- name: Build
working-directory: ${{github.workspace}}/build-windows
shell: bash
run: cmake --build . --config $BUILD_TYPE
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ${{github.workspace}}/build-windows/Release/BeamMP-Launcher.exe
asset_name: BeamMP-Launcher.exe
asset_content_type: application/vnd.microsoft.portable-executable

13
.gitignore vendored
View File

@@ -1,13 +1,4 @@
cmake-build-debug/CMakeFiles/ cmake-build-debug
cmake-build-release/CMakeFiles/ cmake-build-release
cmake-build-debug/BeamNG/
cmake-build-release/BeamNG/
cmake-build-debug/Resources/
cmake-build-release/Resources/
cmake-build-debug/*.*
cmake-build-release/*.*
cmake-build-debug/Makefile
cmake-build-release/Makefile
/.idea/ /.idea/
*.log *.log
cmake-build-release/key

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "evpp"]
path = evpp
url = https://github.com/BeamMP/evpp.git

View File

@@ -1,12 +1,33 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
project(Launcher) project(Launcher)
if (WIN32)
message(STATUS "MSVC -> forcing use of statically-linked runtime.")
STRING(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
STRING(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
endif(WIN32)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
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")
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")
find_package(ZLIB REQUIRED)
find_package(CURL CONFIG REQUIRED) if (WIN32)
target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 rstrtmgr discord-rpc CURL::libcurl ZLIB::ZLIB) find_package(ZLIB REQUIRED)
target_include_directories(${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>) find_package(OpenSSL REQUIRED)
#-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static
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)
else(WIN32) #MINGW
add_definitions("-D_WIN32_WINNT=0x0600")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -s --static")
target_link_libraries(${PROJECT_NAME} discord-rpc ssl crypto ws2_32 ssp crypt32 z)
endif(WIN32)
target_include_directories(${PROJECT_NAME} PRIVATE "include")

11
README.md Normal file → Executable file
View File

@@ -1 +1,10 @@
# BeamMP-Launcher # BeamMP-Launcher
The launcher is the way we communitcate to outside the game, it does a few automated actions such as but not limited to: downloading the mod, launching the game, and create a connection to a server.
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,
the only permission that has been granted is to use the software in its compiled form as distributed from the BeamMP.com website.
Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.

1
evpp Submodule

Submodule evpp added at 44e10774e2

0
include/Discord/discord_info.h Normal file → Executable file
View File

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#include <stdint.h> #include <cstdint>
// clang-format off // clang-format off

22
include/Json.h Normal file → Executable file
View File

@@ -1,12 +1,12 @@
// Copyright (c) 2019-present Anonymous275. // Copyright (c) 2019-present Anonymous275.
// BeamMP Launcher code is not in the public domain and is not free software. // 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. // 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. // 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 /// Created by Anonymous275 on 11/27/2020
/// ///
#pragma once #pragma once
#include "rapidjson/stringbuffer.h" #include "rapidjson/stringbuffer.h"
#include "rapidjson/document.h" #include "rapidjson/document.h"
#include "rapidjson/writer.h" #include "rapidjson/writer.h"
namespace json = rapidjson; namespace json = rapidjson;

0
include/Logger.h Normal file → Executable file
View File

3
include/Network/network.h Normal file → Executable file
View File

@@ -5,6 +5,8 @@
/// ///
/// Created by Anonymous275 on 7/18/2020 /// Created by Anonymous275 on 7/18/2020
/// ///
#pragma once #pragma once
#include <string> #include <string>
void NetReset(); void NetReset();
@@ -18,6 +20,7 @@ extern bool Terminate;
extern int DEFAULT_PORT; extern int DEFAULT_PORT;
extern uint64_t UDPSock; extern uint64_t UDPSock;
extern uint64_t TCPSock; extern uint64_t TCPSock;
extern std::string Branch;
extern bool TCPTerminate; extern bool TCPTerminate;
extern std::string LastIP; extern std::string LastIP;
extern std::string MStatus; extern std::string MStatus;

0
include/Security/Game.h Normal file → Executable file
View File

2
include/Security/Init.h Normal file → Executable file
View File

@@ -7,7 +7,7 @@
/// ///
#pragma once #pragma once
#include <string> #include <string>
void PreGame(int argc, char* argv[],const std::string& GamePath); void PreGame(const std::string& GamePath);
std::string CheckVer(const std::string &path); std::string CheckVer(const std::string &path);
void InitGame(const std::string& Dir); void InitGame(const std::string& Dir);
std::string GetGameDir(); std::string GetGameDir();

3
include/Startup.h Normal file → Executable file
View File

@@ -8,8 +8,9 @@
#pragma once #pragma once
#include <string> #include <string>
void InitLauncher(int argc, char* argv[]); void InitLauncher(int argc, char* argv[]);
void CheckDir(int argc,char* args[]); 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 ConfigInit();
extern bool Dev; extern bool Dev;

0
include/Zlib/Compressor.h Normal file → Executable file
View File

14
include/Curl/http.h → include/http.h Normal file → Executable file
View File

@@ -7,6 +7,14 @@
/// ///
#pragma once #pragma once
#include <string> #include <string>
int Download(const std::string& URL,const std::string& Path,bool close); #include "Logger.h"
std::string PostHTTP(const std::string& IP, const std::string& Fields); class HTTP{
std::string HTTP_REQUEST(const std::string& IP,int port); public:
static bool Download(const std::string &IP, const std::string &Path);
static std::string Post(const std::string& IP, const std::string& Fields);
static std::string Get(const std::string &IP);
static bool ProgressBar(size_t c, size_t t);
public:
static bool isDownload;
static std::string Codes_[];
};

7578
include/httplib.h Normal file

File diff suppressed because it is too large Load Diff

0
include/rapidjson/allocators.h Normal file → Executable file
View File

0
include/rapidjson/cursorstreamwrapper.h Normal file → Executable file
View File

0
include/rapidjson/document.h Normal file → Executable file
View File

0
include/rapidjson/encodedstream.h Normal file → Executable file
View File

0
include/rapidjson/encodings.h Normal file → Executable file
View File

0
include/rapidjson/error/en.h Normal file → Executable file
View File

0
include/rapidjson/error/error.h Normal file → Executable file
View File

0
include/rapidjson/filereadstream.h Normal file → Executable file
View File

0
include/rapidjson/filewritestream.h Normal file → Executable file
View File

0
include/rapidjson/fwd.h Normal file → Executable file
View File

0
include/rapidjson/internal/biginteger.h Normal file → Executable file
View File

0
include/rapidjson/internal/clzll.h Normal file → Executable file
View File

0
include/rapidjson/internal/diyfp.h Normal file → Executable file
View File

0
include/rapidjson/internal/dtoa.h Normal file → Executable file
View File

0
include/rapidjson/internal/ieee754.h Normal file → Executable file
View File

0
include/rapidjson/internal/itoa.h Normal file → Executable file
View File

0
include/rapidjson/internal/meta.h Normal file → Executable file
View File

0
include/rapidjson/internal/pow10.h Normal file → Executable file
View File

0
include/rapidjson/internal/regex.h Normal file → Executable file
View File

0
include/rapidjson/internal/stack.h Normal file → Executable file
View File

0
include/rapidjson/internal/strfunc.h Normal file → Executable file
View File

0
include/rapidjson/internal/strtod.h Normal file → Executable file
View File

0
include/rapidjson/internal/swap.h Normal file → Executable file
View File

0
include/rapidjson/istreamwrapper.h Normal file → Executable file
View File

0
include/rapidjson/memorybuffer.h Normal file → Executable file
View File

0
include/rapidjson/memorystream.h Normal file → Executable file
View File

0
include/rapidjson/msinttypes/inttypes.h Normal file → Executable file
View File

0
include/rapidjson/msinttypes/stdint.h Normal file → Executable file
View File

0
include/rapidjson/ostreamwrapper.h Normal file → Executable file
View File

0
include/rapidjson/pointer.h Normal file → Executable file
View File

0
include/rapidjson/prettywriter.h Normal file → Executable file
View File

0
include/rapidjson/rapidjson.h Normal file → Executable file
View File

0
include/rapidjson/reader.h Normal file → Executable file
View File

0
include/rapidjson/schema.h Normal file → Executable file
View File

0
include/rapidjson/stream.h Normal file → Executable file
View File

0
include/rapidjson/stringbuffer.h Normal file → Executable file
View File

0
include/rapidjson/writer.h Normal file → Executable file
View File

24
include/winmain-inl.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
namespace {
struct OnApp {
OnApp() {
#ifdef WIN32
// Initialize Winsock 2.2
WSADATA wsaData;
int err = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (err) {
std::cout << "WSAStartup() failed with error: %d" << err;
}
#endif
}
~OnApp() {
#ifdef WIN32
WSACleanup();
#endif
}
} __s_onexit_pause;
}

0
src/Compressor.cpp Normal file → Executable file
View File

60
src/Config.cpp Executable file
View File

@@ -0,0 +1,60 @@
///
/// Created by Anonymous275 on 2/23/2021
///
#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();
}
//Default -1
//Release 1
//EA 2
//Dev 3
//Custom 3
if(d["Build"].IsString()){
Branch = d["Build"].GetString();
for(char& c : Branch)c = char(tolower(c));
}
}
void ConfigInit(){
if(fs::exists("Launcher.cfg")){
std::ifstream cfg("Launcher.cfg");
if(cfg.is_open()){
auto Size = fs::file_size("Launcher.cfg");
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()));
}
ParseConfig(d);
}else fatal("Failed to open Launcher.cfg!");
}else{
std::ofstream cfg("Launcher.cfg");
if(cfg.is_open()){
cfg <<
R"({
"Port": 4444,
"Build": "Default"
})";
cfg.close();
}else{
fatal("Failed to write config on disk!");
}
}
}

2
src/Discord.cpp Normal file → Executable file
View File

@@ -7,7 +7,7 @@
/// ///
#include "Discord/discord_rpc.h" #include "Discord/discord_rpc.h"
#include "Logger.h" #include "Logger.h"
#include <iostream> #include <cstring>
#include <thread> #include <thread>
#include <ctime> #include <ctime>

21
src/GameStart.cpp Normal file → Executable file
View File

@@ -6,9 +6,9 @@
/// Created by Anonymous275 on 7/19/2020 /// Created by Anonymous275 on 7/19/2020
/// ///
#include <Windows.h> #include <Security/Init.h>
#include <windows.h>
#include "Startup.h" #include "Startup.h"
#include <ShlObj.h>
#include "Logger.h" #include "Logger.h"
#include <iostream> #include <iostream>
#include <thread> #include <thread>
@@ -23,21 +23,20 @@ std::string GetGamePath(){
LPCTSTR sk = "Software\\BeamNG\\BeamNG.drive"; LPCTSTR sk = "Software\\BeamNG\\BeamNG.drive";
LONG openRes = RegOpenKeyEx(HKEY_CURRENT_USER, sk, 0, KEY_ALL_ACCESS, &hKey); LONG openRes = RegOpenKeyEx(HKEY_CURRENT_USER, sk, 0, KEY_ALL_ACCESS, &hKey);
if (openRes != ERROR_SUCCESS){ if (openRes != ERROR_SUCCESS){
fatal("Please launch the game at least once"); fatal("Please launch the game at least once!");
} }
Path = QueryKey(hKey,4); Path = QueryKey(hKey,4);
if(Path.empty()){ if(Path.empty()){
CoInitialize(nullptr); sk = R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders)";
wchar_t * path = nullptr; openRes = RegOpenKeyEx(HKEY_CURRENT_USER, sk, 0, KEY_ALL_ACCESS, &hKey);
SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_SIMPLE_IDLIST, nullptr, (PWSTR *)(&path)); if (openRes != ERROR_SUCCESS){
CoTaskMemFree(path); fatal("Cannot get Local Appdata directory!");
std::wstring ws(path); }
std::string s(ws.begin(), ws.end()); Path = QueryKey(hKey,5);
Path = s;
Path += "\\BeamNG.drive\\"; Path += "\\BeamNG.drive\\";
} }
Path += CheckVer(GetGameDir()) + "\\";
return Path; return Path;
} }

4
src/Logger.cpp Normal file → Executable file
View File

@@ -44,14 +44,14 @@ std::string getDate() {
} }
void InitLog(){ void InitLog(){
std::ofstream LFS; std::ofstream LFS;
LFS.open ("Launcher.log"); LFS.open(GetEP() + "Launcher.log");
if(!LFS.is_open()){ if(!LFS.is_open()){
error("logger file init failed!"); error("logger file init failed!");
}else LFS.close(); }else LFS.close();
} }
void addToLog(const std::string& Line){ void addToLog(const std::string& Line){
std::ofstream LFS; std::ofstream LFS;
LFS.open("Launcher.log", std::ios_base::app); LFS.open(GetEP() + "Launcher.log", std::ios_base::app);
LFS << Line.c_str(); LFS << Line.c_str();
LFS.close(); LFS.close();
} }

12
src/Network/Core.cpp Normal file → Executable file
View File

@@ -8,9 +8,9 @@
#include "Network/network.h" #include "Network/network.h"
#include "Security/Init.h" #include "Security/Init.h"
#include "Curl/http.h" #include "http.h"
#include <WinSock2.h> #include <winsock2.h>
#include <WS2tcpip.h> #include <ws2tcpip.h>
#include "Startup.h" #include "Startup.h"
#include "Logger.h" #include "Logger.h"
#include <charconv> #include <charconv>
@@ -58,7 +58,7 @@ void Parse(std::string Data,SOCKET CSocket){
NetReset(); NetReset();
Terminate = true; Terminate = true;
TCPTerminate = true; TCPTerminate = true;
Data = Code + HTTP_REQUEST("https://beammp.com/servers-info",443); Data = Code + HTTP::Post("https://backend.beammp.com/servers","");
break; break;
case 'C': case 'C':
ListOfMods.clear(); ListOfMods.clear();
@@ -242,9 +242,13 @@ int Handle(EXCEPTION_POINTERS *ep){
void CoreNetwork(){ void CoreNetwork(){
while(TraceBack >= 4){ while(TraceBack >= 4){
#ifndef __MINGW32__
__try{ __try{
#endif
CoreMain(); CoreMain();
#ifndef __MINGW32__
}__except(Handle(GetExceptionInformation())){} }__except(Handle(GetExceptionInformation())){}
#endif
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
} }
} }

2
src/Network/DNS.cpp Normal file → Executable file
View File

@@ -7,7 +7,7 @@
/// ///
#include <string> #include <string>
#include <winsock.h> #include <winsock2.h>
#include "Logger.h" #include "Logger.h"
std::string GetAddr(const std::string&IP){ std::string GetAddr(const std::string&IP){

10
src/Network/GlobalHandler.cpp Normal file → Executable file
View File

@@ -6,17 +6,15 @@
/// Created by Anonymous275 on 7/25/2020 /// Created by Anonymous275 on 7/25/2020
/// ///
#include "Network/network.h" #include "Network/network.h"
#include "Security/Init.h" #include <winsock2.h>
#include <ws2tcpip.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include "Logger.h" #include "Logger.h"
#include <charconv> #include <charconv>
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
std::chrono::time_point<std::chrono::steady_clock> PingStart,PingEnd; std::chrono::time_point<std::chrono::high_resolution_clock> PingStart,PingEnd;
bool GConnected = false; bool GConnected = false;
bool CServer = true; bool CServer = true;
SOCKET CSocket = -1; SOCKET CSocket = -1;
@@ -77,7 +75,7 @@ void ServerSend(std::string Data, bool Rel){
int DLen = int(Data.length()); int DLen = int(Data.length());
if(DLen > 3)C = Data.at(0); if(DLen > 3)C = Data.at(0);
if (C == 'O' || C == 'T')Ack = true; if (C == 'O' || C == 'T')Ack = true;
if(C == 'W' || C == 'Y' || C == 'V' || C == 'E')Rel = true; if(C == 'W' || C == 'Y' || C == 'V' || C == 'E' || C == 'C')Rel = true;
if(Ack || Rel){ if(Ack || Rel){
if(Ack || DLen > 1000)SendLarge(Data); if(Ack || DLen > 1000)SendLarge(Data);
else TCPSend(Data,TCPSock); else TCPSend(Data,TCPSock);

243
src/Network/Http.cpp Normal file → Executable file
View File

@@ -1,115 +1,128 @@
// Copyright (c) 2019-present Anonymous275. // Copyright (c) 2019-present Anonymous275.
// BeamMP Launcher code is not in the public domain and is not free software. // 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. // 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. // Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
/// ///
/// Created by Anonymous275 on 7/18/2020 /// Created by Anonymous275 on 7/18/2020
/// ///
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "Security/Game.h"
#include <iostream>
#include <curl/curl.h> #include <Logger.h>
#include <iostream> #include <fstream>
#include <mutex> #include "http.h"
#include <mutex>
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp){ #include <cmath>
((std::string*)userp)->append((char*)contents, size * nmemb); #include <httplib.h>
return size * nmemb;
} std::string HTTP::Codes_[] =
{
std::string HTTP_REQUEST(const std::string& IP,int port){ "Success","Unknown","Connection","BindIPAddress",
static std::mutex Lock; "Read","Write","ExceedRedirectCount","Canceled",
Lock.lock(); "SSLConnection","SSLLoadingCerts","SSLServerVerification",
CURL *curl; "UnsupportedMultipartBoundaryChars","Compression"
CURLcode res; };
std::string readBuffer; bool HTTP::isDownload = false;
curl = curl_easy_init(); std::string HTTP::Get(const std::string &IP) {
if(curl) { static std::mutex Lock;
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str()); std::scoped_lock Guard(Lock);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); auto pos = IP.find('/',10);
curl_easy_setopt(curl, CURLOPT_PORT, port);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); httplib::Client cli(IP.substr(0, pos).c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); cli.set_connection_timeout(std::chrono::seconds(10));
res = curl_easy_perform(curl); auto res = cli.Get(IP.substr(pos).c_str(), ProgressBar);
curl_easy_cleanup(curl); std::string Ret;
if(res != CURLE_OK)return "-1";
} if(res.error() == 0){
Lock.unlock(); if(res->status == 200){
return readBuffer; Ret = res->body;
} }else error(res->reason);
int nb_bar; }else{
double last_progress, progress_bar_adv; if(isDownload) {
int progress_bar (void *bar, double t, double d){ std::cout << "\n";
if(last_progress != round(d/t*100)){ }
nb_bar = 25; error("HTTP Get failed on " + Codes_[res.error()]);
progress_bar_adv = round(d/t*nb_bar); }
std::cout<<"\r";
std::cout<< "Progress : [ "; return Ret;
if(t!=0)std::cout<<round(d/t*100);else std::cout<<0; }
std::cout << "% ] [";
int i; std::string HTTP::Post(const std::string& IP, const std::string& Fields) {
for(i = 0; i <= progress_bar_adv; i++)std::cout<<"#"; static std::mutex Lock;
for(i = 0; i < nb_bar - progress_bar_adv; i++)std::cout<<"."; std::scoped_lock Guard(Lock);
std::cout<<"]";
last_progress = round(d/t*100); auto pos = IP.find('/',10);
}
return 0; httplib::Client cli(IP.substr(0, pos).c_str());
} cli.set_connection_timeout(std::chrono::seconds(10));
struct File { std::string Ret;
const char *filename;
FILE *stream; if(!Fields.empty()) {
}; httplib::Result res = cli.Post(IP.substr(pos).c_str(), Fields, "application/json");
static size_t my_fwrite(void *buffer,size_t size,size_t nmemb,void *stream){
auto *out = (struct File*)stream; if(res.error() == 0) {
if(!out->stream) { if (res->status != 200) {
fopen_s(&out->stream,out->filename,"wb"); error(res->reason);
if(!out->stream)return -1; }
} Ret = res->body;
return fwrite(buffer, size, nmemb, out->stream); }else{
} error("HTTP Post failed on " + Codes_[res.error()]);
int Download(const std::string& URL,const std::string& Path,bool close){ }
CURL *curl; }else{
CURLcode res; httplib::Result res = cli.Post(IP.substr(pos).c_str());
struct File file = {Path.c_str(),nullptr}; if(res.error() == 0) {
curl = curl_easy_init(); if (res->status != 200) {
if(curl){ error(res->reason);
curl_easy_setopt(curl, CURLOPT_URL,URL.c_str()); }
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); Ret = res->body;
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); }else{
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite); error("HTTP Post failed on " + Codes_[res.error()]);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &file); }
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE); }
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_bar);
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); if(Ret.empty())return "-1";
res = curl_easy_perform(curl); else return Ret;
curl_easy_cleanup(curl); }
if(res != CURLE_OK)return res;
} bool HTTP::ProgressBar(size_t c, size_t t){
if(file.stream)fclose(file.stream); if(isDownload) {
std::cout << std::endl; static double last_progress, progress_bar_adv;
return -1; progress_bar_adv = round(c / double(t) * 25);
} std::cout << "\r";
std::string PostHTTP(const std::string& IP, const std::string& Fields) { std::cout << "Progress : [ ";
static auto *header = new curl_slist{(char*)"Content-Type: application/json"}; std::cout << round(c / double(t) * 100);
CURL* curl; std::cout << "% ] [";
CURLcode res; int i;
std::string readBuffer; for (i = 0; i <= progress_bar_adv; i++)std::cout << "#";
curl = curl_easy_init(); for (i = 0; i < 25 - progress_bar_adv; i++)std::cout << ".";
if (curl) { std::cout << "]";
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str()); last_progress = round(c / double(t) * 100);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header); }
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, Fields.size()); return true;
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Fields.c_str()); }
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); bool HTTP::Download(const std::string &IP, const std::string &Path) {
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); static std::mutex Lock;
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5); std::scoped_lock Guard(Lock);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl); isDownload = true;
if (res != CURLE_OK) std::string Ret = Get(IP);
return "-1"; isDownload = false;
}
return readBuffer; if(Ret.empty())return false;
}
std::ofstream File(Path, std::ios::binary);
if(File.is_open()) {
File << Ret;
File.close();
std::cout << "\n";
info("Download Complete!");
}else{
error("Failed to open file directory: " + Path);
return false;
}
return true;
}

25
src/Network/Resources.cpp Normal file → Executable file
View File

@@ -7,8 +7,7 @@
/// ///
#include "Network/network.h" #include "Network/network.h"
#include <ws2tcpip.h>
#include <WS2tcpip.h>
#include <filesystem> #include <filesystem>
#include "Startup.h" #include "Startup.h"
#include "Logger.h" #include "Logger.h"
@@ -20,8 +19,9 @@
#include <atomic> #include <atomic>
#include <vector> #include <vector>
#include <future> #include <future>
#include <cmath>
namespace fs = std::experimental::filesystem; namespace fs = std::filesystem;
std::string ListOfMods; std::string ListOfMods;
std::vector<std::string> Split(const std::string& String,const std::string& delimiter){ std::vector<std::string> Split(const std::string& String,const std::string& delimiter){
std::vector<std::string> Val; std::vector<std::string> Val;
@@ -37,8 +37,7 @@ std::vector<std::string> Split(const std::string& String,const std::string& deli
} }
void CheckForDir(){ void CheckForDir(){
struct stat info{}; if(!fs::exists("Resources")){
if(stat( "Resources", &info) != 0){
_wmkdir(L"Resources"); _wmkdir(L"Resources");
} }
} }
@@ -126,11 +125,10 @@ char* TCPRcvRaw(SOCKET Sock,uint64_t& GRcv, uint64_t Size){
} }
char* File = new char[Size]; char* File = new char[Size];
uint64_t Rcv = 0; uint64_t Rcv = 0;
int32_t Temp;
do{ do{
int Len = int(Size-Rcv); int Len = int(Size-Rcv);
if(Len > 1000000)Len = 1000000; if(Len > 1000000)Len = 1000000;
Temp = recv(Sock, &File[Rcv], Len, MSG_WAITALL); int32_t Temp = recv(Sock, &File[Rcv], Len, MSG_WAITALL);
if(Temp < 1){ if(Temp < 1){
info(std::to_string(Temp)); info(std::to_string(Temp));
UUl("Socket Closed Code 1"); UUl("Socket Closed Code 1");
@@ -153,6 +151,7 @@ SOCKET InitDSock(){
SOCKET DSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKET DSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
SOCKADDR_IN ServerAddr; SOCKADDR_IN ServerAddr;
if(DSock < 1){ if(DSock < 1){
KillSocket(DSock);
Terminate = true; Terminate = true;
return 0; return 0;
} }
@@ -243,6 +242,7 @@ void SyncResources(SOCKET Sock){
Amount++; Amount++;
} }
if(!FNames.empty())info("Syncing..."); if(!FNames.empty())info("Syncing...");
SOCKET DSock = InitDSock();
for(auto FN = FNames.begin(),FS = FSizes.begin(); FN != FNames.end() && !Terminate; ++FN,++FS) { for(auto FN = FNames.begin(),FS = FSizes.begin(); FN != FNames.end() && !Terminate; ++FN,++FS) {
auto pos = FN->find_last_of('/'); auto pos = FN->find_last_of('/');
if (pos != std::string::npos) { if (pos != std::string::npos) {
@@ -251,12 +251,12 @@ void SyncResources(SOCKET Sock){
Pos++; Pos++;
if (fs::exists(a)) { if (fs::exists(a)) {
if (FS->find_first_not_of("0123456789") != std::string::npos)continue; if (FS->find_first_not_of("0123456789") != std::string::npos)continue;
if (fs::file_size(a) == std::stoi(*FS)){ if (fs::file_size(a) == std::stoull(*FS)){
UpdateUl(false,std::to_string(Pos) + "/" + std::to_string(Amount) + ": " + a.substr(a.find_last_of('/'))); UpdateUl(false,std::to_string(Pos) + "/" + std::to_string(Amount) + ": " + a.substr(a.find_last_of('/')));
std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::this_thread::sleep_for(std::chrono::milliseconds(50));
try { try {
if(!fs::exists(GetGamePath() + "mods/multiplayer")){ if(!fs::exists(GetGamePath() + "mods/multiplayer")){
fs::create_directory(GetGamePath() + "mods/multiplayer"); fs::create_directories(GetGamePath() + "mods/multiplayer");
} }
fs::copy_file(a, GetGamePath() + "mods/multiplayer" + a.substr(a.find_last_of('/')), fs::copy_file(a, GetGamePath() + "mods/multiplayer" + a.substr(a.find_last_of('/')),
fs::copy_options::overwrite_existing); fs::copy_options::overwrite_existing);
@@ -271,7 +271,6 @@ void SyncResources(SOCKET Sock){
} }
CheckForDir(); CheckForDir();
std::string FName = a.substr(a.find_last_of('/')); std::string FName = a.substr(a.find_last_of('/'));
SOCKET DSock = InitDSock();
do { do {
TCPSend("f" + *FN,Sock); TCPSend("f" + *FN,Sock);
@@ -295,16 +294,16 @@ void SyncResources(SOCKET Sock){
LFS.close(); LFS.close();
} }
}while(fs::file_size(a) != std::stoi(*FS) && !Terminate); }while(fs::file_size(a) != std::stoull(*FS) && !Terminate);
KillSocket(DSock);
if(!Terminate){ if(!Terminate){
if(!fs::exists(GetGamePath() + "mods/multiplayer")){ if(!fs::exists(GetGamePath() + "mods/multiplayer")){
fs::create_directory(GetGamePath() + "mods/multiplayer"); fs::create_directories(GetGamePath() + "mods/multiplayer");
} }
fs::copy_file(a,GetGamePath() + "mods/multiplayer" + FName, fs::copy_options::overwrite_existing); fs::copy_file(a,GetGamePath() + "mods/multiplayer" + FName, fs::copy_options::overwrite_existing);
} }
WaitForConfirm(); WaitForConfirm();
} }
KillSocket(DSock);
if(!Terminate){ if(!Terminate){
TCPSend("Done",Sock); TCPSend("Done",Sock);
info("Done!"); info("Done!");

2
src/Network/VehicleData.cpp Normal file → Executable file
View File

@@ -8,7 +8,7 @@
#include "Zlib/Compressor.h" #include "Zlib/Compressor.h"
#include "Network/network.h" #include "Network/network.h"
#include <WS2tcpip.h> #include <ws2tcpip.h>
#include "Logger.h" #include "Logger.h"
#include <string> #include <string>
#include <set> #include <set>

9
src/Network/VehicleEvent.cpp Normal file → Executable file
View File

@@ -10,7 +10,7 @@
#include <vector> #include <vector>
#include "Logger.h" #include "Logger.h"
#include <iostream> #include <iostream>
#include <WS2tcpip.h> #include <ws2tcpip.h>
#include <Zlib/Compressor.h> #include <Zlib/Compressor.h>
#include "Network/network.h" #include "Network/network.h"
@@ -133,15 +133,16 @@ void TCPClientMain(const std::string& IP,int Port){
RetCode = connect(TCPSock, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr)); RetCode = connect(TCPSock, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr));
if(RetCode != 0){ if(RetCode != 0){
UlStatus = "UlConnection Failed!"; UlStatus = "UlConnection Failed!";
std::cout << "Client: connect failed! Error code: " << WSAGetLastError() << std::endl; error("Client: connect failed! Error code: " + std::to_string(WSAGetLastError()));
KillSocket(TCPSock); KillSocket(TCPSock);
WSACleanup(); WSACleanup();
Terminate = true; Terminate = true;
return; return;
} }
getsockname(TCPSock, (SOCKADDR *)&ServerAddr, (int *)sizeof(ServerAddr)); info("Connected!");
char Code = 'C'; char Code = 'C';
send(TCPSock,&Code,1,0); send(TCPSock, &Code, 1, 0);
SyncResources(TCPSock); SyncResources(TCPSock);
while(!Terminate){ while(!Terminate){
ServerParser(TCPRcv(TCPSock)); ServerParser(TCPRcv(TCPSock));

609
src/Security/BeamNG.cpp Normal file → Executable file
View File

@@ -1,292 +1,317 @@
// Copyright (c) 2019-present Anonymous275. // Copyright (c) 2019-present Anonymous275.
// BeamMP Launcher code is not in the public domain and is not free software. // 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. // 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. // Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
/// ///
/// Created by Anonymous275 on 7/18/2020 /// Created by Anonymous275 on 7/18/2020
/// ///
#include <filesystem> #include <filesystem>
#include <Windows.h> #include <windows.h>
#include "Logger.h" #include "Logger.h"
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <thread> #include <thread>
#define MAX_KEY_LENGTH 255 #define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383 #define MAX_VALUE_NAME 16383
int TraceBack = 0; int TraceBack = 0;
std::string GameDir; std::string GameDir;
void lowExit(int code){ void lowExit(int code){
TraceBack = 0; TraceBack = 0;
std::string msg = std::string msg =
"Failed to find the game please launch it. Report this if the issue persists code "; "Failed to find the game please launch it. Report this if the issue persists code ";
error(msg+std::to_string(code)); error(msg+std::to_string(code));
std::this_thread::sleep_for(std::chrono::seconds(10)); std::this_thread::sleep_for(std::chrono::seconds(10));
exit(2); exit(2);
} }
void Exit(int code){ void Exit(int code){
TraceBack = 0; TraceBack = 0;
std::string msg = std::string msg =
"Sorry. We do not support cracked copies report this if you believe this is a mistake code "; "Sorry. We do not support cracked copies report this if you believe this is a mistake code ";
error(msg+std::to_string(code)); error(msg+std::to_string(code));
std::this_thread::sleep_for(std::chrono::seconds(10)); std::this_thread::sleep_for(std::chrono::seconds(10));
exit(3); exit(3);
} }
void SteamExit(int code){ void SteamExit(int code){
TraceBack = 0; TraceBack = 0;
std::string msg = std::string msg =
"Illegal steam modifications detected report this if you believe this is a mistake code "; "Illegal steam modifications detected report this if you believe this is a mistake code ";
error(msg+std::to_string(code)); error(msg+std::to_string(code));
std::this_thread::sleep_for(std::chrono::seconds(10)); std::this_thread::sleep_for(std::chrono::seconds(10));
exit(4); exit(4);
} }
std::string GetGameDir(){ std::string GetGameDir(){
if(TraceBack != 4)Exit(0); if(TraceBack != 4)Exit(0);
return GameDir.substr(0,GameDir.find_last_of('\\')); return GameDir.substr(0,GameDir.find_last_of('\\'));
} }
LONG OpenKey(HKEY root,const char* path,PHKEY hKey){ LONG OpenKey(HKEY root,const char* path,PHKEY hKey){
return RegOpenKeyEx(root, reinterpret_cast<LPCSTR>(path), 0, KEY_READ, hKey); return RegOpenKeyEx(root, reinterpret_cast<LPCSTR>(path), 0, KEY_READ, hKey);
} }
std::string QueryKey(HKEY hKey,int ID){ std::string QueryKey(HKEY hKey,int ID){
TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
DWORD cbName; // size of name string DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string DWORD cchClassName = MAX_PATH; // size of class string
DWORD cSubKeys=0; // number of subkeys DWORD cSubKeys=0; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time FILETIME ftLastWriteTime; // last write time
DWORD i, retCode; DWORD i, retCode;
TCHAR achValue[MAX_VALUE_NAME]; TCHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME; DWORD cchValue = MAX_VALUE_NAME;
retCode = RegQueryInfoKey( retCode = RegQueryInfoKey(
hKey, // key handle hKey, // key handle
achClass, // buffer for class name achClass, // buffer for class name
&cchClassName, // size of class string &cchClassName, // size of class string
nullptr, // reserved nullptr, // reserved
&cSubKeys, // number of subkeys &cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size &cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string &cchMaxClass, // longest class string
&cValues, // number of values for this key &cValues, // number of values for this key
&cchMaxValue, // longest value name &cchMaxValue, // longest value name
&cbMaxValueData, // longest value data &cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor &cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time &ftLastWriteTime); // last write time
BYTE* buffer = new BYTE[cbMaxValueData]; BYTE* buffer = new BYTE[cbMaxValueData];
ZeroMemory(buffer, cbMaxValueData); ZeroMemory(buffer, cbMaxValueData);
if (cSubKeys){ if (cSubKeys){
for (i=0; i<cSubKeys; i++){ for (i=0; i<cSubKeys; i++){
cbName = MAX_KEY_LENGTH; cbName = MAX_KEY_LENGTH;
retCode = RegEnumKeyEx(hKey, i,achKey,&cbName,nullptr,nullptr,nullptr,&ftLastWriteTime); retCode = RegEnumKeyEx(hKey, i,achKey,&cbName,nullptr,nullptr,nullptr,&ftLastWriteTime);
if (retCode == ERROR_SUCCESS){ if (retCode == ERROR_SUCCESS){
if(strcmp(achKey,"Steam App 284160") == 0){ if(strcmp(achKey,"Steam App 284160") == 0){
return achKey; return achKey;
} }
} }
} }
} }
if (cValues){ if (cValues){
for (i=0, retCode = ERROR_SUCCESS; i<cValues; i++){ for (i=0, retCode = ERROR_SUCCESS; i<cValues; i++){
cchValue = MAX_VALUE_NAME; cchValue = MAX_VALUE_NAME;
achValue[0] = '\0'; achValue[0] = '\0';
retCode = RegEnumValue(hKey, i,achValue,&cchValue,nullptr,nullptr,nullptr,nullptr); retCode = RegEnumValue(hKey, i,achValue,&cchValue,nullptr,nullptr,nullptr,nullptr);
if (retCode == ERROR_SUCCESS ){ if (retCode == ERROR_SUCCESS ){
DWORD lpData = cbMaxValueData; DWORD lpData = cbMaxValueData;
buffer[0] = '\0'; buffer[0] = '\0';
LONG dwRes = RegQueryValueEx(hKey, achValue, nullptr, nullptr, buffer, &lpData); LONG dwRes = RegQueryValueEx(hKey, achValue, nullptr, nullptr, buffer, &lpData);
std::string data = reinterpret_cast<const char *const>(buffer); std::string data = (char *)(buffer);
std::string key = achValue; std::string key = achValue;
switch (ID){
case 1: if(key == "SteamExe"){ switch (ID){
auto p = data.find_last_of('/'); case 1: if(key == "SteamExe"){
if(p != std::string::npos)return data.substr(0,p); auto p = data.find_last_of("/\\");
}break; if(p != std::string::npos){
case 2: if(key == "Name" && data == "BeamNG.drive")return data;break; return data.substr(0,p);
case 3: if(key == "rootpath")return data;break; }
case 4: if(key == "userpath_override")return data; }
default: break; break;
} case 2: if(key == "Name" && data == "BeamNG.drive")return data;break;
} case 3: if(key == "rootpath")return data;break;
} case 4: if(key == "userpath_override")return data;
} case 5: if(key == "Local AppData")return data;
delete [] buffer; default: break;
return ""; }
} }
namespace fs = std::experimental::filesystem; }
void FileList(std::vector<std::string>&a,const std::string& Path){ }
for (const auto &entry : fs::directory_iterator(Path)) { delete [] buffer;
auto pos = entry.path().filename().string().find('.'); return "";
if (pos != std::string::npos) { }
a.emplace_back(entry.path().string()); namespace fs = std::filesystem;
}else FileList(a,entry.path().string());
} bool NameValid(const std::string& N){
} if(N == "config" || N == "librarycache"){
bool Find(const std::string& FName,const std::string& Path){ return true;
std::vector<std::string> FS; }
FileList(FS,Path+"/userdata"); if(N.find_first_not_of("0123456789") == std::string::npos){
for(std::string&a : FS){ return true;
if(a.find(FName) != std::string::npos){ }
FS.clear(); return false;
return true; }
} void FileList(std::vector<std::string>&a,const std::string& Path){
} for (const auto &entry : fs::directory_iterator(Path)) {
FS.clear(); const auto& DPath = entry.path();
return false; if (!entry.is_directory()) {
} a.emplace_back(DPath.u8string());
bool FindHack(const std::string& Path){ }else if(NameValid(DPath.filename().u8string())){
bool s = true; FileList(a, DPath.u8string());
for (const auto &entry : fs::directory_iterator(Path)) { }
std::string Name = entry.path().filename().string(); }
for(char&c : Name)c = char(tolower(c)); }
if(Name == "steam.exe")s = false; bool Find(const std::string& FName,const std::string& Path){
if(Name.find("greenluma") != -1)return true; std::vector<std::string> FS;
Name.clear(); FileList(FS,Path+"\\userdata");
} for(std::string&a : FS){
return s; if(a.find(FName) != std::string::npos){
} FS.clear();
std::vector<std::string> GetID(const std::string& log){ return true;
std::string vec,t,r; }
std::vector<std::string> Ret; }
std::ifstream f(log.c_str(), std::ios::binary); FS.clear();
f.seekg(0, std::ios_base::end); return false;
std::streampos fileSize = f.tellg(); }
vec.resize(size_t(fileSize) + 1); bool FindHack(const std::string& Path){
f.seekg(0, std::ios_base::beg); bool s = true;
f.read(&vec[0], fileSize); for (const auto &entry : fs::directory_iterator(Path)) {
f.close(); std::string Name = entry.path().filename().u8string();
std::stringstream ss(vec); for(char&c : Name)c = char(tolower(c));
bool S = false; if(Name == "steam.exe")s = false;
while (std::getline(ss, t, '{')) { if(Name.find("greenluma") != -1){
if(!S)S = true; error("Found malicious file/folder \"" + Name+"\"");
else{ return true;
for(char& c : t){ }
if(isdigit(c))r += c; Name.clear();
} }
break; return s;
} }
} std::vector<std::string> GetID(const std::string& log){
Ret.emplace_back(r); std::string vec,t,r;
r.clear(); std::vector<std::string> Ret;
S = false; std::ifstream f(log.c_str(), std::ios::binary);
bool L = true; f.seekg(0, std::ios_base::end);
while (std::getline(ss, t, '}')) { std::streampos fileSize = f.tellg();
if(L){ vec.resize(size_t(fileSize) + 1);
L = false; f.seekg(0, std::ios_base::beg);
continue; f.read(&vec[0], fileSize);
} f.close();
for(char& c : t){ std::stringstream ss(vec);
if(c == '"'){ bool S = false;
if(!S)S = true; while (std::getline(ss, t, '{')) {
else{ if(!S)S = true;
if(r.length() > 10) { else{
Ret.emplace_back(r); for(char& c : t){
} if(isdigit(c))r += c;
r.clear(); }
S = false; break;
continue; }
} }
} Ret.emplace_back(r);
if(isdigit(c))r += c; r.clear();
} S = false;
} bool L = true;
vec.clear(); while (std::getline(ss, t, '}')) {
return Ret; if(L){
} L = false;
std::string GetManifest(const std::string& Man){ continue;
std::string vec; }
std::ifstream f(Man.c_str(), std::ios::binary); for(char& c : t){
f.seekg(0, std::ios_base::end); if(c == '"'){
std::streampos fileSize = f.tellg(); if(!S)S = true;
vec.resize(size_t(fileSize) + 1); else{
f.seekg(0, std::ios_base::beg); if(r.length() > 10) {
f.read(&vec[0], fileSize); Ret.emplace_back(r);
f.close(); }
std::string ToFind = "\"LastOwner\"\t\t\""; r.clear();
int pos = int(vec.find(ToFind)); S = false;
if(pos != -1){ continue;
pos += int(ToFind.length()); }
vec = vec.substr(pos); }
return vec.substr(0,vec.find('\"')); if(isdigit(c))r += c;
}else return ""; }
} }
bool IDCheck(std::string Man, std::string steam){ vec.clear();
bool a = false,b = true; return Ret;
int pos = int(Man.rfind("steamapps")); }
if(pos == -1)Exit(5); std::string GetManifest(const std::string& Man){
Man = Man.substr(0,pos+9) + "/appmanifest_284160.acf"; std::string vec;
steam += "/config/loginusers.vdf"; std::ifstream f(Man.c_str(), std::ios::binary);
if(fs::exists(Man) && fs::exists(steam)){ f.seekg(0, std::ios_base::end);
for(const std::string&ID : GetID(steam)){ std::streampos fileSize = f.tellg();
if(ID == GetManifest(Man))b = false; vec.resize(size_t(fileSize) + 1);
} f.seekg(0, std::ios_base::beg);
if(b)Exit(6); f.read(&vec[0], fileSize);
}else a = true; f.close();
return a; std::string ToFind = "\"LastOwner\"\t\t\"";
} int pos = int(vec.find(ToFind));
void LegitimacyCheck(){ if(pos != -1){
std::string Result,T; pos += int(ToFind.length());
std::string K1 = R"(Software\Valve\Steam)"; vec = vec.substr(pos);
std::string K2 = R"(Software\Valve\Steam\Apps\284160)"; return vec.substr(0,vec.find('\"'));
std::string K3 = R"(Software\BeamNG\BeamNG.drive)"; }else return "";
HKEY hKey; }
LONG dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K1.c_str(), &hKey); bool IDCheck(std::string Man, std::string steam){
if(dwRegOPenKey == ERROR_SUCCESS) { bool a = false,b = true;
Result = QueryKey(hKey, 1); int pos = int(Man.rfind("steamapps"));
if(Result.empty())Exit(1); if(pos == -1)Exit(5);
if(fs::exists(Result)){ Man = Man.substr(0,pos+9) + "\\appmanifest_284160.acf";
if(!Find("284160.json",Result))Exit(2); steam += "\\config\\loginusers.vdf";
if(FindHack(Result))SteamExit(1); if(fs::exists(Man) && fs::exists(steam)){
}else Exit(3); for(const std::string&ID : GetID(steam)){
T = Result; if(ID == GetManifest(Man))b = false;
Result.clear(); }
TraceBack++; if(b)Exit(6);
}else Exit(4); }else a = true;
K1.clear(); return a;
RegCloseKey(hKey); }
dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K2.c_str(), &hKey); void LegitimacyCheck(){
if(dwRegOPenKey == ERROR_SUCCESS) { std::string Result,T;
Result = QueryKey(hKey, 2); std::string K1 = R"(Software\Valve\Steam)";
if(Result.empty())lowExit(1); std::string K2 = R"(Software\Valve\Steam\Apps\284160)";
TraceBack++; std::string K3 = R"(Software\BeamNG\BeamNG.drive)";
}else lowExit(2); HKEY hKey;
K2.clear();
RegCloseKey(hKey); LONG dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K1.c_str(), &hKey);
dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K3.c_str(), &hKey);
if(dwRegOPenKey == ERROR_SUCCESS) { if(dwRegOPenKey == ERROR_SUCCESS) {
Result = QueryKey(hKey, 3); Result = QueryKey(hKey, 1);
if(Result.empty())lowExit(3); if(Result.empty())Exit(1);
if(IDCheck(Result,T))lowExit(5);
GameDir = Result; if(fs::exists(Result)){
TraceBack++; if(!Find("284160.json",Result))Exit(2);
}else lowExit(4); if(FindHack(Result))SteamExit(1);
K3.clear(); }else Exit(3);
Result.clear();
RegCloseKey(hKey); T = Result;
if(TraceBack < 3)exit(-1); Result.clear();
} TraceBack++;
std::string CheckVer(const std::string &dir){ }else Exit(4);
std::string temp,Path = dir + "\\integrity.json";
std::ifstream f(Path.c_str(), std::ios::binary); K1.clear();
int Size = int(std::filesystem::file_size(Path)); RegCloseKey(hKey);
std::string vec(Size,0); dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K2.c_str(), &hKey);
f.read(&vec[0], Size); if(dwRegOPenKey == ERROR_SUCCESS) {
f.close(); Result = QueryKey(hKey, 2);
if(Result.empty())lowExit(1);
vec = vec.substr(vec.find_last_of("version"),vec.find_last_of('"')); TraceBack++;
for(const char &a : vec){ }else lowExit(2);
if(isdigit(a) || a == '.')temp+=a; K2.clear();
} RegCloseKey(hKey);
return temp; dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K3.c_str(), &hKey);
} if(dwRegOPenKey == ERROR_SUCCESS) {
Result = QueryKey(hKey, 3);
if(Result.empty())lowExit(3);
if(IDCheck(Result,T))lowExit(5);
GameDir = Result;
TraceBack++;
}else lowExit(4);
K3.clear();
Result.clear();
RegCloseKey(hKey);
if(TraceBack < 3)exit(-1);
}
std::string CheckVer(const std::string &dir){
std::string temp,Path = dir + "\\integrity.json";
std::ifstream f(Path.c_str(), std::ios::binary);
int Size = int(std::filesystem::file_size(Path));
std::string vec(Size,0);
f.read(&vec[0], Size);
f.close();
vec = vec.substr(vec.find_last_of("version"),vec.find_last_of('"'));
for(const char &a : vec){
if(isdigit(a) || a == '.')temp+=a;
}
return temp;
}

208
src/Security/Login.cpp Normal file → Executable file
View File

@@ -1,94 +1,114 @@
// Copyright (c) 2019-present Anonymous275. // Copyright (c) 2019-present Anonymous275.
// BeamMP Launcher code is not in the public domain and is not free software. // 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. // 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. // Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
/// ///
/// Created by Anonymous275 on 11/26/2020 /// Created by Anonymous275 on 11/26/2020
/// ///
#include "Curl/http.h" #include "http.h"
#include <filesystem> #include <filesystem>
#include "Logger.h" #include "Logger.h"
#include <fstream> #include <fstream>
#include "Json.h" #include "Json.h"
using namespace std::filesystem; namespace fs = std::filesystem;
std::string PublicKey; std::string PublicKey;
extern bool LoginAuth; extern bool LoginAuth;
std::string Role;
void UpdateKey(const char* newKey){
if(newKey){ void UpdateKey(const char* newKey){
std::ofstream Key("key"); if(newKey){
if(Key.is_open()){ std::ofstream Key("key");
Key << newKey; if(Key.is_open()){
Key.close(); Key << newKey;
}else fatal("Cannot write to disk!"); Key.close();
}else if(exists("key")){ }else fatal("Cannot write to disk!");
remove("key"); }else if(fs::exists("key")){
} remove("key");
} }
}
/// "username":"value","password":"value"
/// "Guest":"Name" /// "username":"value","password":"value"
/// "pk":"private_key" /// "Guest":"Name"
/// "pk":"private_key"
std::string Login(const std::string& fields){
info("Attempting to authenticate..."); std::string GetFail(const std::string& R){
std::string Buffer = PostHTTP("https://auth.beammp.com/userlogin", fields); std::string DRet = R"({"success":false,"message":)";
json::Document d; DRet += "\""+R+"\"}";
d.Parse(Buffer.c_str()); error(R);
if(Buffer == "-1"){ return DRet;
fatal("Failed to communicate with the auth system!"); }
}
if (Buffer.find('{') == -1 || d.HasParseError()) { std::string Login(const std::string& fields){
fatal("Invalid answer from authentication servers, please try again later!"); if(fields == "LO"){
} LoginAuth = false;
if(!d["success"].IsNull() && d["success"].GetBool()){ UpdateKey(nullptr);
LoginAuth = true; return "";
if(!d["private_key"].IsNull()){ }
UpdateKey(d["private_key"].GetString()); info("Attempting to authenticate...");
} std::string Buffer = HTTP::Post("https://auth.beammp.com/userlogin", fields);
if(!d["public_key"].IsNull()){ json::Document d;
PublicKey = d["public_key"].GetString(); d.Parse(Buffer.c_str());
} if(Buffer == "-1"){
info("Authentication successful!"); return GetFail("Failed to communicate with the auth system!");
}else info("Authentication failed!"); }
if(!d["message"].IsNull()){
d.RemoveMember("private_key"); if (Buffer.at(0) != '{' || d.HasParseError()) {
d.RemoveMember("public_key"); error(Buffer);
rapidjson::StringBuffer buffer; return GetFail("Invalid answer from authentication servers, please try again later!");
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); }
d.Accept(writer); if(!d["success"].IsNull() && d["success"].GetBool()){
return buffer.GetString(); LoginAuth = true;
} if(!d["private_key"].IsNull()){
return "{\"success\":false}"; UpdateKey(d["private_key"].GetString());
} }
if(!d["public_key"].IsNull()){
void CheckLocalKey(){ PublicKey = d["public_key"].GetString();
if(exists("key") && file_size("key") < 100){ }
std::ifstream Key("key"); info("Authentication successful!");
if(Key.is_open()) { }else info("Authentication failed!");
auto Size = file_size("key"); if(!d["message"].IsNull()){
std::string Buffer(Size, 0); d.RemoveMember("private_key");
Key.read(&Buffer[0], Size); d.RemoveMember("public_key");
Key.close(); rapidjson::StringBuffer buffer;
Buffer = PostHTTP("https://auth.beammp.com/userlogin", R"({"pk":")"+Buffer+"\"}"); rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
json::Document d; d.Accept(writer);
d.Parse(Buffer.c_str()); return buffer.GetString();
if (Buffer == "-1" || Buffer.find('{') == -1 || d.HasParseError()) { }
fatal("Invalid answer from authentication servers, please try again later!"); return GetFail("Invalid message parsing!");
} }
if(d["success"].GetBool()){
LoginAuth = true; void CheckLocalKey(){
UpdateKey(d["private_key"].GetString()); if(fs::exists("key") && fs::file_size("key") < 100){
PublicKey = d["public_key"].GetString(); std::ifstream Key("key");
}else{ if(Key.is_open()) {
info("Auto-Authentication unsuccessful please re-login!"); auto Size = fs::file_size("key");
UpdateKey(nullptr); std::string Buffer(Size, 0);
} Key.read(&Buffer[0], Size);
}else{ Key.close();
warn("Could not open saved key!");
UpdateKey(nullptr); Buffer = HTTP::Post("https://auth.beammp.com/userlogin", R"({"pk":")" + Buffer + "\"}");
}
}else UpdateKey(nullptr); json::Document d;
} d.Parse(Buffer.c_str());
if (Buffer == "-1" || Buffer.at(0) != '{' || d.HasParseError()) {
error(Buffer);
fatal("Invalid answer from authentication servers, please try again later!");
}
if(d["success"].GetBool()){
LoginAuth = true;
UpdateKey(d["private_key"].GetString());
PublicKey = d["public_key"].GetString();
Role = d["role"].GetString();
//info(Role);
}else{
info("Auto-Authentication unsuccessful please re-login!");
UpdateKey(nullptr);
}
}else{
warn("Could not open saved key!");
UpdateKey(nullptr);
}
}else UpdateKey(nullptr);
}

419
src/Startup.cpp Normal file → Executable file
View File

@@ -1,236 +1,185 @@
// Copyright (c) 2019-present Anonymous275. // Copyright (c) 2019-present Anonymous275.
// BeamMP Launcher code is not in the public domain and is not free software. // 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. // 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. // Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
/// ///
/// Created by Anonymous275 on 7/16/2020 /// Created by Anonymous275 on 7/16/2020
/// ///
#include "Discord/discord_info.h" #include <windows.h>
#include "Network/network.h" #include "Discord/discord_info.h"
#include "Security/Init.h" #include "Network/network.h"
#include "Security/Init.h"
#include "Curl/http.h" #include <filesystem>
#include <curl/curl.h> #include "Startup.h"
#include <filesystem> #include "Logger.h"
#include "Startup.h" #include <thread>
#include <iostream> #include "http.h"
#include "Logger.h"
#include <thread> extern int TraceBack;
bool Dev = false;
extern int TraceBack; namespace fs = std::filesystem;
bool Dev = false;
namespace fs = std::experimental::filesystem; std::string GetEN(){
std::string GetEN(){ return "BeamMP-Launcher.exe";
return "BeamMP-Launcher.exe"; }
} std::string GetVer(){
std::string GetVer(){ return "2.0";
return "1.80"; }
} std::string GetPatch(){
std::string GetPatch(){ return ".2";
return ""; }
} std::string GetEP(char*P){
void ReLaunch(int argc,char*args[]){ static std::string Ret = [&](){
std::string Arg; std::string path(P);
for(int c = 2; c <= argc; c++){ return path.substr(0, path.find_last_of("\\/") + 1);
Arg += " "; } ();
Arg += args[c-1]; return Ret;
} }
system("cls"); void ReLaunch(int argc,char*args[]){
ShellExecute(nullptr,"runas",GetEN().c_str(),Arg.c_str(),nullptr,SW_SHOWNORMAL); std::string Arg;
ShowWindow(GetConsoleWindow(),0); for(int c = 2; c <= argc; c++){
std::this_thread::sleep_for(std::chrono::seconds(1)); Arg += " ";
exit(1); Arg += args[c-1];
} }
void URelaunch(int argc,char* args[]){ system("cls");
std::string Arg; ShellExecute(nullptr,"runas",(GetEP() + GetEN()).c_str(),Arg.c_str(),nullptr,SW_SHOWNORMAL);
for(int c = 2; c <= argc; c++){ ShowWindow(GetConsoleWindow(),0);
Arg += " "; std::this_thread::sleep_for(std::chrono::seconds(1));
Arg += args[c-1]; exit(1);
} }
ShellExecute(nullptr,"open",GetEN().c_str(),Arg.c_str(),nullptr,SW_SHOWNORMAL); void URelaunch(int argc,char* args[]){
ShowWindow(GetConsoleWindow(),0); std::string Arg;
std::this_thread::sleep_for(std::chrono::seconds(1)); for(int c = 2; c <= argc; c++){
exit(1); Arg += " ";
} Arg += args[c-1];
void CheckName(int argc,char* args[]){ }
struct stat info{}; ShellExecute(nullptr,"open",(GetEP() + GetEN()).c_str(),Arg.c_str(),nullptr,SW_SHOWNORMAL);
std::string DN = GetEN(),CDir = args[0],FN = CDir.substr(CDir.find_last_of('\\')+1); ShowWindow(GetConsoleWindow(),0);
if(FN != DN){ std::this_thread::sleep_for(std::chrono::seconds(1));
if(stat(DN.c_str(),&info)==0)remove(DN.c_str()); exit(1);
if(stat(DN.c_str(),&info)==0)ReLaunch(argc,args); }
std::rename(FN.c_str(), DN.c_str()); void CheckName(int argc,char* args[]){
URelaunch(argc,args); std::string DN = GetEN(),CDir = args[0],FN = CDir.substr(CDir.find_last_of('\\')+1);
} if(FN != DN){
} if(fs::exists(DN))remove(DN.c_str());
if(fs::exists(DN))ReLaunch(argc,args);
/// Deprecated std::rename(FN.c_str(), DN.c_str());
void RequestRole(){ URelaunch(argc,args);
auto NPos = std::string::npos; }
std::string HTTP_Result = HTTP_REQUEST("https://beammp.com/entitlement?did="+GetDID()+"&t=l",443); }
if(HTTP_Result == "-1"){
HTTP_Result = HTTP_REQUEST("https://backup1.beammp.com/entitlement?did="+GetDID()+"&t=l",443); void CheckForUpdates(int argc,char*args[],const std::string& CV){
if(HTTP_Result == "-1") { std::string link;
fatal("Sorry Backend System Outage! Don't worry it will back on soon!"); std::string HTTP = HTTP::Get("https://beammp.com/builds/launcher?version=true");
} bool fallback = false;
} if(HTTP.find_first_of("0123456789") == std::string::npos){
if(HTTP_Result.find("\"MDEV\"") != NPos || HTTP_Result.find("\"CON\"") != NPos){ HTTP = HTTP::Get("https://backup1.beammp.com/builds/launcher?version=true");
Dev = true; fallback = true;
} if(HTTP.find_first_of("0123456789") == std::string::npos) {
if(HTTP_Result.find("Error") != NPos){ fatal("Primary Servers Offline! sorry for the inconvenience!");
fatal("Sorry You need to be in the official BeamMP Discord to proceed! https://discord.gg/beammp"); }
} }
info("Client Connected!"); 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 link = "https://beammp.com/builds/launcher?version=true"; std::string EP(GetEP() + GetEN()), Back(GetEP() + "BeamMP-Launcher.back");
std::string HTTP = HTTP_REQUEST(link,443);
bool fallback = false; if(fs::exists(Back))remove(Back.c_str());
if(HTTP.find_first_of("0123456789") == std::string::npos){
link = "https://backup1.beammp.com/builds/launcher?version=true"; if(HTTP > CV){
HTTP = HTTP_REQUEST(link,443); system("cls");
fallback = true; info("Update found!");
if(HTTP.find_first_of("0123456789") == std::string::npos) { info("Updating...");
fatal("Primary Servers Offline! sorry for the inconvenience!"); if(std::rename(EP.c_str(), Back.c_str()))error("failed creating a backup!");
}
} if(!HTTP::Download(link, EP)){
if(fallback){ error("Launcher Update failed! trying again...");
link = "https://backup1.beammp.com/builds/launcher?download=true"; std::this_thread::sleep_for(std::chrono::seconds(2));
}else link = "https://beammp.com/builds/launcher?download=true";
if(!HTTP::Download(link, EP)){
struct stat buffer{}; error("Launcher Update failed!");
std::string Back = "BeamMP-Launcher.back"; std::this_thread::sleep_for(std::chrono::seconds(5));
if(stat(Back.c_str(), &buffer) == 0)remove(Back.c_str()); ReLaunch(argc,args);
if(HTTP > CV){ }
system("cls"); }
info("Update found!"); URelaunch(argc,args);
info("Updating..."); }else info("Launcher version is up to date");
if(std::rename(GetEN().c_str(), Back.c_str()))error("failed creating a backup!"); TraceBack++;
int i = Download(link, GetEN(),true); }
if(i != -1){
error("Launcher Update failed! trying again... code : " + std::to_string(i)); void CustomPort(int argc, char* argv[]){
std::this_thread::sleep_for(std::chrono::seconds(2)); if(argc > 1){
int i2 = Download(link, GetEN(),true); std::string Port = argv[1];
if(i2 != -1){ if(Port.find_first_not_of("0123456789") == std::string::npos){
error("Launcher Update failed! code : " + std::to_string(i2)); if(std::stoi(Port) > 1000){
std::this_thread::sleep_for(std::chrono::seconds(5)); DEFAULT_PORT = std::stoi(Port);
ReLaunch(argc,args); warn("Running on custom port : " + std::to_string(DEFAULT_PORT));
} }
} }
URelaunch(argc,args); if(argc > 2)Dev = true;
}else{ }
info("Version is up to date"); }
} void InitLauncher(int argc, char* argv[]) {
TraceBack++; system("cls");
} SetConsoleTitleA(("BeamMP Launcher v" + std::string(GetVer()) + GetPatch()).c_str());
void CheckDir(int argc,char*args[]){ InitLog();
std::string CDir = args[0]; CheckName(argc, argv);
std::string MDir = "BeamNG\\mods"; CheckLocalKey();
if(!fs::is_directory("BeamNG")){ ConfigInit();
if(!fs::create_directory("BeamNG")){ CustomPort(argc, argv);
error("Cannot Create BeamNG Directory! Retrying..."); Discord_Main();
std::this_thread::sleep_for(std::chrono::seconds(3)); CheckForUpdates(argc, argv, std::string(GetVer()) + GetPatch());
ReLaunch(argc,args); }
} size_t DirCount(const std::filesystem::path& path){
} return (size_t)std::distance(std::filesystem::directory_iterator{path}, std::filesystem::directory_iterator{});
if(fs::is_directory(MDir) && !Dev){ }
int c = 0; void CheckMP(const std::string& Path) {
for (auto& p : fs::directory_iterator(MDir))c++; if (!fs::exists(Path))return;
if(c > 2) { size_t c = DirCount(fs::path(Path));
warn(std::to_string(c-1) + " local launcher mods will be wiped! Close this window if you don't want that!"); if (c > 3) {
std::this_thread::sleep_for(std::chrono::seconds(15)); 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{ }
fs::remove_all(MDir); try {
} catch (...) { for (auto& p : fs::directory_iterator(Path)){
error("Please close the game and try again"); if(p.exists() && !p.is_directory()){
std::this_thread::sleep_for(std::chrono::seconds(5)); std::string Name = p.path().filename().u8string();
exit(1); for(char&Ch : Name)Ch = char(tolower(Ch));
} if(Name != "beammp.zip")fs::remove(p.path());
} }
if(fs::is_directory(MDir) && !Dev)ReLaunch(argc,args); }
if(!fs::create_directory(MDir) && !Dev){ } catch (...) {
error("Cannot Create Mods Directory! Retrying..."); fatal("Please close the game, and try again!");
std::this_thread::sleep_for(std::chrono::seconds(3)); }
ReLaunch(argc,args);
} }
if(!fs::is_directory("BeamNG\\settings")){ void PreGame(const std::string& GamePath){
if(!fs::create_directory("BeamNG\\settings")){ const std::string CurrVer("0.22.1.0");
error("Cannot Create Settings Directory! Retrying..."); std::string GameVer = CheckVer(GamePath);
std::this_thread::sleep_for(std::chrono::seconds(3)); info("Game Version : " + GameVer);
ReLaunch(argc,args); 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!");
void CustomPort(int argc, char* argv[]){ }
if(argc > 1){ CheckMP(GetGamePath() + "mods/multiplayer");
std::string Port = argv[1];
if(Port.find_first_not_of("0123456789") == std::string::npos){ if(!Dev) {
if(std::stoi(Port) > 1000){ info("Downloading mod please wait...");
DEFAULT_PORT = std::stoi(Port); try {
warn("Running on custom port : " + std::to_string(DEFAULT_PORT)); if (!fs::exists(GetGamePath() + "mods/multiplayer")) {
} fs::create_directories(GetGamePath() + "mods/multiplayer");
} }
if(argc > 2)Dev = false; }catch(std::exception&e){
} fatal(e.what());
} }
void InitLauncher(int argc, char* argv[]) {
system("cls"); HTTP::Download("https://backend.beammp.com/builds/client?download=true"
curl_global_init(CURL_GLOBAL_DEFAULT); "&pk=" + PublicKey +
SetConsoleTitleA(("BeamMP Launcher v" + std::string(GetVer()) + GetPatch()).c_str()); "&branch=" + Branch, GetGamePath() + R"(mods\multiplayer\BeamMP.zip)");
InitLog();
CheckName(argc, argv); //HTTP::Download("beammp.com/builds/client", GetGamePath() + R"(mods\multiplayer\BeamMP.zip)");
CheckLocalKey(); //will replace RequestRole }
Discord_Main();
//RequestRole();
CustomPort(argc, argv);
CheckForUpdates(argc, argv, std::string(GetVer()) + GetPatch());
}
void PreGame(int argc, char* argv[],const std::string& GamePath){
info("Game Version : " + CheckVer(GamePath));
std::string DUI = R"(BeamNG\settings\uiapps-layouts.json)";
std::string GS = R"(BeamNG\settings\game-settings.ini)";
std::string link = "https://beammp.com/client-ui-data";
bool fallback = false;
int i;
if(!fs::exists(DUI)){
info("Downloading default ui data...");
i = Download(link,DUI,true);
if(i != -1){
fallback = true;
remove(DUI.c_str());
link = "https://backup1.beammp.com/client-ui-data";
i = Download(link,DUI,true);
if(i != -1) {
error("Failed to download code : " + std::to_string(i));
std::this_thread::sleep_for(std::chrono::seconds(3));
ReLaunch(argc, argv);
}
}
info("Download Complete!");
}
if(!fs::exists(GS)) {
info("Downloading default game settings...");
if(fallback)link = "https://backup1.beammp.com/client-settings-data";
else link = "https://beammp.com/client-settings-data";
Download(link, GS,true);
info("Download Complete!");
}
if(!Dev) {
info("Downloading mod...");
if(fallback)link = "https://backup1.beammp.com/builds/client";
else link ="https://beammp.com/builds/client";
if(!fs::exists(GetGamePath() + "mods")){
fs::create_directory(GetGamePath() + "mods");
}
if(!fs::exists(GetGamePath() + "mods/multiplayer")){
fs::create_directory(GetGamePath() + "mods/multiplayer");
}
Download(link, GetGamePath() + R"(mods\multiplayer\BeamMP.zip)", true);
info("Download Complete!");
}
/*debug("Name : " + GetDName());
debug("Discriminator : " + GetDTag());
debug("Unique ID : " + GetDID());*/
} }

22
src/main.cpp Normal file → Executable file
View File

@@ -8,25 +8,37 @@
#include "Network/network.h" #include "Network/network.h"
#include "Security/Init.h" #include "Security/Init.h"
#include "Startup.h" #include "Startup.h"
#include <thread>
#include <iostream> #include <iostream>
#include "Logger.h"
#include <thread>
#include "http.h"
[[noreturn]] void flush(){ [[noreturn]] void flush(){
while(true){ while(true){
std::cout.flush(); std::cout.flush();
std::this_thread::sleep_for(std::chrono::milliseconds(500)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
} }
} }
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]);
InitLauncher(argc,argv); InitLauncher(argc,argv);
CheckDir(argc,argv);
LegitimacyCheck(); try {
PreGame(argc,argv,GetGameDir()); LegitimacyCheck();
}catch (std::exception& e){
fatal("Main 1 : " + std::string(e.what()));
}
PreGame(GetGameDir());
InitGame(GetGameDir()); InitGame(GetGameDir());
CoreNetwork(); CoreNetwork();
///TODO: make sure to use argv[0] for everything that should be in the same dir (mod down ect...)
} }