windows compatability

This commit is contained in:
MrBesen 2022-08-24 16:12:03 +02:00
parent 4fae1740e9
commit 5bb58008c7
10 changed files with 381 additions and 207 deletions

View File

@ -1,19 +1,15 @@
#pragma once
#include <istream>
#include <string>
#include <memory>
#include <vector>
class ClientAccess {
ClientAccess();
ClientAccess(const std::string& token, uint16_t port);
public:
ClientAccess(const std::string& token, uint16_t port);
static std::shared_ptr<ClientAccess> find(bool uselockfile = true);
private:
// returns the name and value of a argument or empty string if it could not be parsed
static std::string parseArg(const std::string& input, std::string& value);
static std::shared_ptr<ClientAccess> findUsingArgs(const std::vector<std::string>& cmdline);
static std::shared_ptr<ClientAccess> findUsingLockfile(const std::vector<std::string>& cmdline, pid_t pid);
public:
std::string getBasicAuth() const;
@ -25,4 +21,6 @@ private:
std::string authcode;
uint16_t port = 0;
};
};
std::shared_ptr<ClientAccess> createFromLockfile(std::istream& lockfile);

View File

@ -15,7 +15,7 @@ public:
POST,
PUT,
PATCH,
DELETE
// DELETE
};
struct WebException {

View File

@ -51,7 +51,9 @@ SOURCES += \
src/stagesettings.cpp \
thirdparty/Log/Log.cpp
# mainwindow.cpp
# platform specific implementations
win32:SOURCES += src/clientaccess_windows.cpp
unix:SOURCES += src/clientaccess_linux.cpp
HEADERS += \
include/arg.h \
@ -77,8 +79,6 @@ HEADERS += \
include/stagesettings.h \
thirdparty/Log/Log.h
# mainwindow.h
MOC_DIR = build/generated/
UI_DIR = ui/
OBJECTS_DIR = build/
@ -127,6 +127,11 @@ unix {
QMAKE_CLEAN += linuxdeploy-x86_64.AppImage lolautoaccept.png
}
win32 {
INCLUDEPATH += $$PWD/../curl/include/
LIBS += $$PWD/../curl/lib/libbrotlicommon.a $$PWD/../curl/lib/libbrotlidec.a $$PWD/../curl/lib/libcrypto.a $$PWD/../curl/lib/libcurl.a $$PWD/../curl/lib/libcurl.dll.a $$PWD/../curl/lib/libgsasl.a $$PWD/../curl/lib/libidn2.a $$PWD/../curl/lib/libnghttp2.a $$PWD/../curl/lib/libnghttp3.a $$PWD/../curl/lib/libngtcp2.a $$PWD/../curl/lib/libngtcp2_crypto_openssl.a $$PWD/../curl/lib/libssh2.a $$PWD/../curl/lib/libssl.a $$PWD/../curl/lib/libz.a $$PWD/../curl/lib/libzstd.a
}
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin

View File

@ -1,189 +1,47 @@
#include "clientaccess.h"
#include <cstring>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <string>
#include <vector>
#include <Log.h>
#include "defer.h"
static bool endsWith(const std::string& all, const std::string& end) {
return all.rfind(end) == all.size() - end.size();
}
// reads a procfile into a vector (strings are \0 seperated)
static std::vector<std::string> readProcFile(const std::string& path) {
std::ifstream in(path);
std::vector<std::string> out;
std::string line;
while(std::getline(in, line, '\0')) {
if(!line.empty()) {
out.push_back(line);
}
}
return out;
}
ClientAccess::ClientAccess() {}
ClientAccess::ClientAccess(const std::string& token, uint16_t port) : authcode(token), port(port) {}
std::shared_ptr<ClientAccess> ClientAccess::find(bool uselockfile) {
DIR* procdir = opendir("/proc");
if(!procdir) return nullptr;
defer( closedir(procdir) );
dirent* entry = nullptr;
while ((entry = readdir(procdir)) != NULL) {
if (entry->d_type != DT_DIR) continue;
std::string name(entry->d_name);
pid_t pid = -1;
try {
pid = std::stoi(name);
} catch(std::exception& e) {
// could not parse -> not a pid
continue;
}
// get info on the exe
std::string cmdfile = "/proc/" + std::to_string(pid) + "/cmdline";
std::vector<std::string> args = readProcFile(cmdfile);
// Log::debug << "process: " << pid << " has " << args.size() << " args";
if(args.empty()) continue;
std::string& exename = args.at(0);
if(endsWith(exename, "LeagueClientUx.exe")) {
Log::info << "LeagueClientUx.exe found";
std::shared_ptr<ClientAccess> out;
if(uselockfile) {
out = findUsingLockfile(args, pid);
} else {
out = findUsingArgs(args);
}
if(out) {
return out;
}
}
}
return nullptr;
}
std::string ClientAccess::parseArg(const std::string& input, std::string& value) {
if(input.find("--") != 0) return {};
size_t pos = input.find('=');
if(pos == std::string::npos) return {};
value = input.substr(pos+1);
return input.substr(2, pos-2);
}
std::shared_ptr<ClientAccess> ClientAccess::findUsingArgs(const std::vector<std::string>& cmdline) {
// parse args
std::shared_ptr<ClientAccess> access(new ClientAccess());
for(const std::string& arg : cmdline) {
std::string value;
std::string argname = parseArg(arg, value);
if(argname == "riotclient-auth-token") {
access->authcode = value;
} else if(argname == "riotclient-app-port") {
try {
access->port = std::stoi(value);
} catch(std::exception& e) {
Log::warn << "could not parse port: " << std::quoted(value);
}
}
}
if(access->port > 0 && !access->authcode.empty()) {
return access;
}
return nullptr;
}
std::shared_ptr<ClientAccess> ClientAccess::findUsingLockfile(const std::vector<std::string>& cmdline, pid_t pid) {
// get WINEPREFIX env
std::vector<std::string> envs = readProcFile("/proc/" + std::to_string(pid) + "/environ");
const static std::string WINEPREFIX = "WINEPREFIX=";
// find WINEPREFIX
auto found = std::find_if(envs.begin(), envs.end(), [](const std::string& s) {
return s.find(WINEPREFIX) == 0;
});
// WINEPREFIX env not present
if(found == envs.end()) {
Log::debug << "WINEPREFIX environment variable not set";
return {};
}
const std::string wineprefix = found->substr(WINEPREFIX.size());
const std::string binarypath = cmdline.at(0);
std::string gamefolder = binarypath.substr(2, binarypath.rfind('/')-1); // remove the "C:" and the name of the binary
// TODO: gamefoldre could contain '\' so replacing every occurance with '/' would be a good idea
const std::string lockfilepath = wineprefix + "/drive_c/" + gamefolder + "/lockfile";
Log::debug << "lockfilepath: " << std::quoted(lockfilepath);
// read lockfile
std::ifstream lockfile(lockfilepath);
std::vector<std::string> parts;
std::string content;
while(std::getline(lockfile, content, ':')) {
parts.push_back(content);
}
if(parts.size() != 5) {
Log::error << "lockfile contained " << parts.size() << " parts, expected 5";
return {};
}
const std::string portstr = parts.at(2);
const std::string token = parts.at(3);
// try to parse port
try {
uint16_t port = std::stoi(portstr);
return std::shared_ptr<ClientAccess>(new ClientAccess(token, port));
} catch(std::exception& e) {
Log::error << "could not parse port: " << std::quoted(portstr);
}
return {};
}
std::string ClientAccess::getBasicAuth() const {
return "riot:" + authcode;
}
uint16_t ClientAccess::getPort() const {
return port;
}
std::string ClientAccess::getURL() const {
return "https://127.0.0.1:" + std::to_string(port) + "/";
}
#include "clientaccess.h"
#include <fstream>
#include <iomanip>
#include <Log.h>
ClientAccess::ClientAccess() {}
ClientAccess::ClientAccess(const std::string& token, uint16_t port) : authcode(token), port(port) {}
std::shared_ptr<ClientAccess> createFromLockfile(std::istream& lockfile) {
std::vector<std::string> parts;
std::string content;
while(std::getline(lockfile, content, ':')) {
parts.push_back(content);
}
if(parts.size() != 5) {
Log::error << "lockfile contained " << parts.size() << " parts, expected 5";
return {};
}
const std::string portstr = parts.at(2);
const std::string token = parts.at(3);
// try to parse port
try {
uint16_t port = std::stoi(portstr);
return std::shared_ptr<ClientAccess>(new ClientAccess(token, port));
} catch(std::exception& e) {
Log::error << "could not parse port: " << std::quoted(portstr);
}
return nullptr;
}
std::string ClientAccess::getBasicAuth() const {
return "riot:" + authcode;
}
uint16_t ClientAccess::getPort() const {
return port;
}
std::string ClientAccess::getURL() const {
return "https://127.0.0.1:" + std::to_string(port) + "/";
}

157
src/clientaccess_linux.cpp Normal file
View File

@ -0,0 +1,157 @@
#include "clientaccess.h"
#include <cstring>
# include <sys/mman.h>
# include <dirent.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <string>
#include <vector>
#include <Log.h>
#include "defer.h"
static const std::string CLIENTNAME = "LeagueClientUx.exe"; // returns the name and value of a argument or empty string if it could not be parsed
static std::string parseArg(const std::string& input, std::string& value);
static std::shared_ptr<ClientAccess> findUsingArgs(const std::vector<std::string>& cmdline);
static std::shared_ptr<ClientAccess> findUsingLockfile(const std::vector<std::string>& cmdline, pid_t pid);
static bool endsWith(const std::string& all, const std::string& end) {
return all.rfind(end) == all.size() - end.size();
}
// reads a procfile into a vector (strings are \0 seperated)
static std::vector<std::string> readProcFile(const std::string& path) {
std::ifstream in(path);
std::vector<std::string> out;
std::string line;
while(std::getline(in, line, '\0')) {
if(!line.empty()) {
out.push_back(line);
}
}
return out;
}
std::shared_ptr<ClientAccess> ClientAccess::find(bool uselockfile) {
DIR* procdir = opendir("/proc");
if(!procdir) return nullptr;
defer( closedir(procdir) );
dirent* entry = nullptr;
while ((entry = readdir(procdir)) != NULL) {
if (entry->d_type != DT_DIR) continue;
std::string name(entry->d_name);
pid_t pid = -1;
try {
pid = std::stoi(name);
} catch(std::exception& e) {
// could not parse -> not a pid
continue;
}
// get info on the exe
std::string cmdfile = "/proc/" + std::to_string(pid) + "/cmdline";
std::vector<std::string> args = readProcFile(cmdfile);
// Log::debug << "process: " << pid << " has " << args.size() << " args";
if(args.empty()) continue;
std::string& exename = args.at(0);
if(endsWith(exename, CLIENTNAME)) {
Log::info << CLIENTNAME << " found";
std::shared_ptr<ClientAccess> out;
if(uselockfile) {
out = findUsingLockfile(args, pid);
} else {
out = findUsingArgs(args);
}
if(out) {
return out;
}
}
}
return nullptr;
}
std::string parseArg(const std::string& input, std::string& value) {
if(input.find("--") != 0) return {};
size_t pos = input.find('=');
if(pos == std::string::npos) return {};
value = input.substr(pos+1);
return input.substr(2, pos-2);
}
std::shared_ptr<ClientAccess> findUsingArgs(const std::vector<std::string>& cmdline) {
// parse args
std::shared_ptr<ClientAccess> access(new ClientAccess());
for(const std::string& arg : cmdline) {
std::string value;
std::string argname = parseArg(arg, value);
if(argname == "riotclient-auth-token") {
access->authcode = value;
} else if(argname == "riotclient-app-port") {
try {
access->port = std::stoi(value);
} catch(std::exception& e) {
Log::warn << "could not parse port: " << std::quoted(value);
}
}
}
if(access->port > 0 && !access->authcode.empty()) {
return access;
}
return nullptr;
}
std::shared_ptr<ClientAccess> findUsingLockfile(const std::vector<std::string>& cmdline, pid_t pid) {
// get WINEPREFIX env
std::vector<std::string> envs = readProcFile("/proc/" + std::to_string(pid) + "/environ");
const static std::string WINEPREFIX = "WINEPREFIX=";
// find WINEPREFIX
auto found = std::find_if(envs.begin(), envs.end(), [](const std::string& s) {
return s.find(WINEPREFIX) == 0;
});
// WINEPREFIX env not present
if(found == envs.end()) {
Log::debug << "WINEPREFIX environment variable not set";
return {};
}
const std::string wineprefix = found->substr(WINEPREFIX.size());
const std::string binarypath = cmdline.at(0);
std::string gamefolder = binarypath.substr(2, binarypath.rfind('/')-1); // remove the "C:" and the name of the binary
// TODO: gamefoldre could contain '\' so replacing every occurance with '/' would be a good idea
const std::string lockfilepath = wineprefix + "/drive_c/" + gamefolder + "/lockfile";
Log::debug << "lockfilepath: " << std::quoted(lockfilepath);
// read lockfile
std::ifstream lockfile(lockfilepath);
return createFromLockfile(lockfile);
}

View File

@ -0,0 +1,119 @@
#include "clientaccess.h"
#include <cstring>
# include <windows.h>
# include <tlhelp32.h>
# include <tchar.h>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <string>
#include <vector>
#include <Log.h>
#include "defer.h"
static const std::string CLIENTNAME = "LeagueClientUx.exe";
static std::string narrow(WCHAR* str, size_t len) {
std::string out;
out.reserve(len);
for(uint32_t i = 0; i < len && str[i]; ++i) {
out.append(1, (char) str[i]);
}
return out;
}
static std::string getProcessPath(DWORD dwPID) {
// Take a snapshot of all modules in the specified process.
HANDLE hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
if(hModuleSnap == INVALID_HANDLE_VALUE) {
Log::error << "CreateToolhelp32Snapshot (of modules) failed";
return {}; // empty string
}
defer( CloseHandle(hModuleSnap) );
// Set the size of the structure before using it.
MODULEENTRY32 me32;
me32.dwSize = sizeof(MODULEENTRY32);
// Retrieve information about the first module,
// and exit if unsuccessful
if( !Module32First( hModuleSnap, &me32 ) ) {
Log::error << "Module32First";
return {};
}
return narrow((WCHAR*) me32.szExePath, sizeof(me32.szExePath));
}
static std::shared_ptr<ClientAccess> findUsingLockfile(PROCESSENTRY32& proc) {
const std::string exepath = getProcessPath(proc.th32ProcessID);
Log::note << "exepath: " << exepath;
// lockfile path
const std::string lockfilepath = exepath.substr(0, exepath.rfind('\\')+1) + "lockfile"; // possible out of bounds
Log::debug << "Lockfile: " << lockfilepath;
std::ifstream lockfile(lockfilepath);
if(!lockfile) {
Log::error << "lockfile could not be opend";
return nullptr;
}
return createFromLockfile(lockfile);
}
std::shared_ptr<ClientAccess> ClientAccess::find(bool uselockfile) {
if(!uselockfile) {
Log::error << __PRETTY_FUNCTION__ << " uselockfile = false is unimplemented";
return nullptr;
}
// example code: https://docs.microsoft.com/de-de/windows/win32/toolhelp/taking-a-snapshot-and-viewing-processes
// Take a snapshot of all processes in the system.
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE) {
Log::error << "CreateToolhelp32Snapshot (of processes) failed";
return nullptr;
}
defer( CloseHandle(hProcessSnap) );
PROCESSENTRY32 pe32;
// Set the size of the structure before using it.
pe32.dwSize = sizeof(PROCESSENTRY32);
// Retrieve information about the first process,
// and exit if unsuccessful
if (!Process32First(hProcessSnap, &pe32)) {
Log::error << "Process32First failed"; // show cause of failure
return nullptr;
}
// Now walk the snapshot of processes, and
// display information about each process in turn
do {
std::string exename = narrow((WCHAR*) pe32.szExeFile, sizeof(pe32.szExeFile));
Log::note << "found process: " << exename;
if(exename == CLIENTNAME) {
Log::info << CLIENTNAME << " found";
std::shared_ptr<ClientAccess> out;
out = findUsingLockfile(pe32);
if(out) {
return out;
}
}
} while(Process32Next(hProcessSnap, &pe32));
return nullptr;
}

View File

@ -9,6 +9,12 @@
#include "json.h"
#ifdef WIN32
#define CONFPATH "lolautoacceptor/"
#else
#define CONFPATH ".config/lolautoaccept/"
#endif
Config::StageConfig::StageConfig() : enabled(false) {}
Config::StageConfig::StageConfig(const QJsonObject& j) {
@ -113,8 +119,9 @@ std::shared_ptr<Config::PositionConfig> Config::RootConfig::getPositionConfig(Po
}
Config::Config() {
configFolderPath = getHome() + ".config/lolautoaccept/";
configFolderPath = getHome() + CONFPATH;
configFilePath = configFolderPath + "config.json";
mkdirs(configFolderPath);
}
Config::~Config() {}

View File

@ -4,6 +4,28 @@
#include <Log.h>
#ifdef WIN32
#define CACHEPATH "lolautoacceptor/cache/"
#else
#define CACHEPATH ".cache/lolautoaccept/"
#endif
#ifdef WIN32
#include <QDir>
bool mkdirs(const std::string& path) {
return QDir::root().mkpath(QString::fromStdString(path));
}
std::string getHome() {
const char* homevar = getenv("appdata");
if(homevar == nullptr) {
Log::warn << "%appdata% is not set! Defaulting to ./";
return "./";
}
return std::string(homevar) + "/";
}
#else
bool mkdirs(const std::string& path) {
size_t offset = 0;
while(offset < path.size()) {
@ -18,7 +40,6 @@ bool mkdirs(const std::string& path) {
return true;
}
std::string getHome() {
const char* homevar = getenv("HOME");
if(homevar == nullptr) {
@ -27,7 +48,8 @@ std::string getHome() {
}
return std::string(homevar) + "/";
}
#endif
std::string getCache() {
return getHome() + ".cache/lolautoaccept/";
}
return getHome() + CACHEPATH;
}

View File

@ -14,6 +14,13 @@
#include "clientaccess.h"
#include "clientapi.h"
#ifdef WIN32
static std::string getBaseString(char** argv) {
// TODO
(void) argv;
return "./";
}
#else
static std::string getBaseString(char** argv) {
std::string base;
@ -27,6 +34,7 @@ static std::string getBaseString(char** argv) {
free(cresolved);
return resolved.substr(0, resolved.rfind('/')+1);
}
#endif
int main(int argc, char** argv) {
Log::init();
@ -69,4 +77,4 @@ int main(int argc, char** argv) {
Log::stop();
return ret;
}
}

View File

@ -119,8 +119,8 @@ QByteArray RestClient::requestRaw(const std::string& url, Method m, const std::s
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
headerlist = curl_slist_append(headerlist, "Content-Type: application/json");
break;
case Method::DELETE:
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); break;
//case Method::DELETE:
// curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); break;
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);