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
)
21 changes: 19 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 @@ -32,6 +37,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 @@ -57,6 +63,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 @@ -89,7 +96,17 @@ qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

win32 {
# DESTDIR=bin puts the exe in $$OUT_PWD/bin, not release/
WINDEPLOYQT = $$shell_path($$[QT_INSTALL_BINS]/windeployqt.exe)
TARGET_EXE = $$shell_path($$OUT_PWD/$$DESTDIR/$${TARGET}.exe)
DEPLOY_DIR = $$shell_path($$OUT_PWD/$$DESTDIR)
WINDEPLOYQT_CMD = \"$$WINDEPLOYQT\" --release --compiler-runtime \"$$TARGET_EXE\"
OPENSSL_COPY_SCRIPT = $$shell_path($$PWD/scripts/copy-openssl.ps1)
OPENSSL_COPY_CMD = powershell -NoProfile -ExecutionPolicy Bypass -File \"$$OPENSSL_COPY_SCRIPT\" -TargetDir \"$$DEPLOY_DIR\" -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
6 changes: 6 additions & 0 deletions Launcher/src/auth/fingerprint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,11 @@ QString Fingerprint::getServerDate() const

reply->deleteLater();

// If the Date header is missing/unparseable (proxy blip, timeout), fall back to UTC now.
// An empty serverTimeInMS produces a bad blackbox and can cause intermittent iovation 403s.
if (!dateTime.isValid()) {
dateTime = QDateTime::currentDateTimeUtc();
}

return dateTime.toString(Qt::DateFormat::ISODateWithMs);
}
13 changes: 10 additions & 3 deletions Launcher/src/auth/gflessclient.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "gflessclient.h"
#include <QMessageBox>
#include <QCoreApplication>
#include <QFile>

GflessClient::GflessClient(QObject *parent) : QObject(parent)
{
Expand Down Expand Up @@ -51,7 +53,12 @@ bool GflessClient::openClient(const QString& displayName, const QString& token,

threadId = procInfo->dwThreadId;

QString dllPath = QDir::currentPath() + "/GflessDLL.dll";
QString dllPath = QCoreApplication::applicationDirPath() + "/GflessDLL.dll";

if (!QFile::exists(dllPath)) {
QMessageBox::critical((QWidget*)this->parent(), "Error", "GflessDLL.dll not found next to GflessClient.\nMake sure your antivirus has not deleted it");
return false;
}

if (!injectDll(pid, dllPath))
qDebug() << "Dll injection failed";
Expand Down Expand Up @@ -137,12 +144,12 @@ QByteArray GflessClient::prepareResponse(const QJsonObject &request, const QStri

bool GflessClient::injectDll(DWORD pid, const QString &dllPath)
{
QString injectorPath = QDir::currentPath() + "/Injector.exe";
QString injectorPath = QCoreApplication::applicationDirPath() + "/Injector.exe";
QStringList arguments;
arguments << QString::number(pid) << dllPath;

if (!QFile::exists(injectorPath)) {
QMessageBox::critical((QWidget*)this->parent(), "Error", "Injector.exe not found in the current directory.\nMake sure your antivirus has not deleted it");
QMessageBox::critical((QWidget*)this->parent(), "Error", "Injector.exe not found next to GflessClient.\nMake sure your antivirus has not deleted it");
return false;
}

Expand Down
Loading