Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions Launcher/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
cmake_minimum_required(VERSION 3.21)
project(GflessClientNoIP LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Network WebEngineCore WebChannel)

qt_add_executable(GflessClientNoIP WIN32
src/auth/blackboxgenerator.cpp
src/auth/gameupdater.cpp
src/gameaccount.cpp
src/gameforgeaccount.cpp
src/gui/addaccountdialog.cpp
src/gui/addprofileaccountdialog.cpp
src/gui/addprofiledialog.cpp
src/auth/blackbox.cpp
src/gui/captchadialog.cpp
src/auth/captchasolver.cpp
src/auth/fingerprint.cpp
src/auth/gflessclient.cpp
src/auth/identity.cpp
src/gui/creategameaccountdialog.cpp
src/gui/editmultipleprofileaccountsdialog.cpp
src/gui/gameupdatedialog.cpp
src/gui/identitydialog.cpp
src/auth/nostaleauth.cpp
src/profile.cpp
src/gui/settingsdialog.cpp
src/syncnetworkaccessmanager.cpp
src/main.cpp
src/gui/mainwindow.cpp

src/auth/blackboxgenerator.h
src/auth/gameupdater.h
src/gameaccount.h
src/gameforgeaccount.h
src/gui/addaccountdialog.h
src/gui/addprofileaccountdialog.h
src/gui/addprofiledialog.h
src/auth/blackbox.h
src/gui/captchadialog.h
src/auth/captchasolver.h
src/auth/fingerprint.h
src/auth/gflessclient.h
src/auth/identity.h
src/gui/creategameaccountdialog.h
src/gui/editmultipleprofileaccountsdialog.h
src/gui/gameupdatedialog.h
src/gui/identitydialog.h
src/gui/mainwindow.h
src/auth/nostaleauth.h
src/processchecker.h
src/profile.h
src/gui/settingsdialog.h
src/syncnetworkaccessmanager.h

src/gui/addaccountdialog.ui
src/gui/addprofileaccountdialog.ui
src/gui/addprofiledialog.ui
src/gui/captchadialog.ui
src/gui/creategameaccountdialog.ui
src/gui/editmultipleprofileaccountsdialog.ui
src/gui/gameupdatedialog.ui
src/gui/identitydialog.ui
src/gui/mainwindow.ui
src/gui/settingsdialog.ui

resources.qrc
)

target_include_directories(GflessClientNoIP PRIVATE
src
src/gui
src/auth
)

target_compile_definitions(GflessClientNoIP PRIVATE NO_PROXY_MODE)

target_link_libraries(GflessClientNoIP PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
Qt6::Network
Qt6::WebEngineCore
Qt6::WebChannel
)
18 changes: 16 additions & 2 deletions Launcher/GflessClient.pro
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
QT += core gui network webenginecore
QT += core gui network webenginecore webenginewidgets xml

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11
contains(DEFINES, NO_PROXY_MODE) {
TARGET = GflessClientNoIP
} else {
TARGET = GflessClient
}

RC_ICONS = resources/gfless_icon.ico

Expand Down Expand Up @@ -31,6 +36,7 @@ SOURCES += \
src/gui/addprofiledialog.cpp \
src/auth/blackbox.cpp \
src/gui/captchadialog.cpp \
src/gui/editproxydialog.cpp \
src/auth/captchasolver.cpp \
src/auth/fingerprint.cpp \
src/auth/gflessclient.cpp \
Expand All @@ -56,6 +62,7 @@ HEADERS += \
src/gui/addprofiledialog.h \
src/auth/blackbox.h \
src/gui/captchadialog.h \
src/gui/editproxydialog.h \
src/auth/captchasolver.h \
src/auth/fingerprint.h \
src/auth/gflessclient.h \
Expand Down Expand Up @@ -88,7 +95,14 @@ qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

win32 {
WINDEPLOYQT = $$shell_path($$[QT_INSTALL_BINS]/windeployqt.exe)
WINDEPLOYQT_CMD = \"$$WINDEPLOYQT\" --release --compiler-runtime \"$$OUT_PWD/release/$${TARGET}.exe\"
OPENSSL_COPY_SCRIPT = $$shell_path($$PWD/scripts/copy-openssl.ps1)
OPENSSL_COPY_CMD = powershell -NoProfile -ExecutionPolicy Bypass -File \"$$OPENSSL_COPY_SCRIPT\" -TargetDir \"$$OUT_PWD/release\" -SourceRoot \"$$PWD\"
QMAKE_POST_LINK += $$WINDEPLOYQT_CMD$$escape_expand(\n\t)
QMAKE_POST_LINK += $$OPENSSL_COPY_CMD
}

RESOURCES += \
resources.qrc

82 changes: 82 additions & 0 deletions Launcher/scripts/copy-openssl.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
param(
[Parameter(Mandatory = $true)]
[string]$TargetDir,
[Parameter(Mandatory = $false)]
[string]$SourceRoot = ""
)

$ErrorActionPreference = "Stop"

function Resolve-CandidatePath {
param([string]$PathValue)
if ([string]::IsNullOrWhiteSpace($PathValue)) { return $null }
try {
return (Resolve-Path -LiteralPath $PathValue -ErrorAction Stop).Path
} catch {
return $null
}
}

if (-not (Test-Path -LiteralPath $TargetDir)) {
New-Item -ItemType Directory -Path $TargetDir -Force | Out-Null
}

$dllNames = @("libssl-1_1-x64.dll", "libcrypto-1_1-x64.dll", "Qt5Xml.dll")

$candidateDirs = @()
if (-not [string]::IsNullOrWhiteSpace($env:OPENSSL_DLL_DIR)) {
$candidateDirs += $env:OPENSSL_DLL_DIR
}

if (-not [string]::IsNullOrWhiteSpace($SourceRoot)) {
$candidateDirs += @(
(Join-Path $SourceRoot "build-noip-proxy-fallback\release"),
(Join-Path $SourceRoot "build-proxy-tools-check\release"),
(Join-Path $SourceRoot "build-noip-msvc150-release\release"),
(Join-Path $SourceRoot "build-noip-msvc-release\release")
)
}

$qtRoot = "C:\Qt\Tools"
if (Test-Path -LiteralPath $qtRoot) {
$candidateDirs += Get-ChildItem -Path $qtRoot -Directory -ErrorAction SilentlyContinue |
ForEach-Object { Join-Path $_.FullName "opt\bin" }
}

if (-not [string]::IsNullOrWhiteSpace($env:QTDIR)) {
$candidateDirs += (Join-Path $env:QTDIR "bin")
}

$candidateDirs += @(
"C:\Qt\5.15.0\msvc2019_64\bin",
"C:\Qt\5.15.2\msvc2019\bin"
)

$resolvedDirs = $candidateDirs |
ForEach-Object { Resolve-CandidatePath $_ } |
Where-Object { $_ -and (Test-Path -LiteralPath $_) } |
Select-Object -Unique

foreach ($dllName in $dllNames) {
$targetFile = Join-Path $TargetDir $dllName
if (Test-Path -LiteralPath $targetFile) {
continue
}

$sourceFile = $null
foreach ($dir in $resolvedDirs) {
$candidate = Join-Path $dir $dllName
if (Test-Path -LiteralPath $candidate) {
$sourceFile = $candidate
break
}
}

if ($null -eq $sourceFile) {
Write-Host "[copy-openssl] Missing $dllName (no source found)."
continue
}

Copy-Item -LiteralPath $sourceFile -Destination $targetFile -Force
Write-Host "[copy-openssl] Copied $dllName from $sourceFile"
}
10 changes: 4 additions & 6 deletions Launcher/src/auth/blackboxgenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ QString BlackboxGenerator::generate(const QString &gsid, const QString &installa
QEventLoop loop;
QString result;

if (BlackboxGenerator::getInstance()->page->isLoading())
return {};

connect(getInstance(), &BlackboxGenerator::blackboxCreated, &loop, [&](const QString& blackbox) {
result = blackbox;
loop.quit();
Expand All @@ -63,7 +60,8 @@ QString BlackboxGenerator::generate(const QString &gsid, const QString &installa
}
else {
QJsonObject request = createRequest(gsid, installationId);
QString script = QString("game1(callbackHandler.callback, %1)").arg(QJsonDocument(request).toJson());
QString json = QString::fromUtf8(QJsonDocument(request).toJson(QJsonDocument::Compact));
QString script = QString("game1(callbackHandler.callback, %1)").arg(json);

connect(getInstance()->page, &QWebEnginePage::loadFinished, getInstance(), [&](bool ok) {
if (ok)
Expand All @@ -85,9 +83,9 @@ QByteArray BlackboxGenerator::encrypt(const QByteArray &blackbox, const QString

key = QCryptographicHash::hash(key, QCryptographicHash::Sha512).toHex();

for (size_t i = 0; i < blackbox.size(); ++i)
for (int i = 0; i < blackbox.size(); ++i)
{
size_t key_index = i % key.size();
int key_index = i % key.size();
encrypted[i] = blackbox[i] ^ key[key_index] ^ key[key.size() - key_index - 1];
}

Expand Down
117 changes: 95 additions & 22 deletions Launcher/src/auth/nostaleauth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,16 @@ NostaleAuth::NostaleAuth(const QString &identityPath, const QString& installatio
, proxyUsername(proxyUser)
, proxyPassword(proxyPasswd)
, useProxy(proxy)
, identityPath(identityPath)
{
if (identityPath.isEmpty()) {
identity = nullptr;
}
else {
identity = std::make_shared<Identity>(identityPath, proxyHost, proxyPort, proxyUser, proxyPasswd, proxy);
}

rebuildIdentity();

this->locale = QLocale().name().replace("_", "-");
this->browserUserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36";
this->eventsSessionId = QUuid::createUuid().toString(QUuid::StringFormat::WithoutBraces);

networkManager = new SyncNetworAccesskManager(this);

if (useProxy) {
QNetworkProxy proxy(
QNetworkProxy::ProxyType::Socks5Proxy,
proxyIp,
socksPort.toUInt()
);

if (!proxyUsername.isEmpty()) {
proxy.setUser(proxyUsername);
proxy.setPassword(proxyPassword);
}

networkManager->setProxy(proxy);
}
applyProxyConfiguration();

initGfVersion();
initCert();
Expand Down Expand Up @@ -793,3 +774,95 @@ bool NostaleAuth::getUseProxy() const
{
return useProxy;
}

bool NostaleAuth::isProxyActive() const
{
return useProxy && !forceNoProxy;
}

void NostaleAuth::setProxyConfig(
bool proxyEnabled,
const QString& proxyHost,
const QString& proxyPortValue,
const QString& proxyUser,
const QString& proxyPasswd
)
{
useProxy = proxyEnabled;
proxyIp = proxyHost;
socksPort = proxyPortValue;
proxyUsername = proxyUser;
proxyPassword = proxyPasswd;
rebuildIdentity();
applyProxyConfiguration();
}

void NostaleAuth::setForceNoProxy(bool forceNoProxyValue)
{
forceNoProxy = forceNoProxyValue;
applyProxyConfiguration();
}

void NostaleAuth::applyProxyConfiguration()
{
if (!networkManager) {
return;
}

if (!isProxyActive()) {
networkManager->setProxy(QNetworkProxy::NoProxy);
return;
}

QNetworkProxy proxy(
QNetworkProxy::ProxyType::Socks5Proxy,
proxyIp,
socksPort.toUInt()
);

if (!proxyUsername.isEmpty()) {
proxy.setUser(proxyUsername);
proxy.setPassword(proxyPassword);
}

networkManager->setProxy(proxy);
}

QString NostaleAuth::getIdentityPath() const
{
return identityPath;
}

void NostaleAuth::setIdentityPath(const QString& newIdentityPath)
{
identityPath = newIdentityPath.trimmed();
rebuildIdentity();
}

void NostaleAuth::setInstallationId(const QString& newInstallationId)
{
installationId = newInstallationId.trimmed();
if (installationId.isEmpty()) {
initInstallationId();
}
if (installationId.isEmpty()) {
installationId = QUuid::createUuid().toString(QUuid::WithoutBraces);
}
}

void NostaleAuth::rebuildIdentity()
{
if (identityPath.trimmed().isEmpty()) {
identity = nullptr;
return;
}

identity = std::make_shared<Identity>(
identityPath,
proxyIp,
socksPort,
proxyUsername,
proxyPassword,
useProxy
);
}
Loading