2021-11-01 09:54:58 -04:00
# include "squarelauncher.h"
# include <QFile>
# include <QUrlQuery>
# include <QNetworkReply>
# include <QRegularExpressionMatch>
# include <QMessageBox>
# include "xivlauncher.h"
SquareLauncher : : SquareLauncher ( LauncherWindow & window ) : window ( window ) {
}
QString getFileHash ( QString file ) {
auto f = QFile ( file ) ;
if ( ! f . open ( QIODevice : : ReadOnly ) )
return " " ;
QCryptographicHash hash ( QCryptographicHash : : Sha1 ) ;
hash . addData ( & f ) ;
return QString ( " %1/%2 " ) . arg ( QString : : number ( f . size ( ) ) , hash . result ( ) . toHex ( ) ) ;
}
void SquareLauncher : : getStored ( const LoginInformation & info ) {
QUrlQuery query ;
query . addQueryItem ( " lng " , " en " ) ;
query . addQueryItem ( " rgn " , " 3 " ) ;
query . addQueryItem ( " isft " , " 0 " ) ;
query . addQueryItem ( " cssmode " , " 1 " ) ;
query . addQueryItem ( " isnew " , " 1 " ) ;
query . addQueryItem ( " issteam " , " 0 " ) ;
QUrl url ( " https://ffxiv-login.square-enix.com/oauth/ffxivarr/login/top " ) ;
url . setQuery ( query ) ;
auto request = QNetworkRequest ( url ) ;
window . buildRequest ( request ) ;
QNetworkReply * reply = window . mgr - > get ( request ) ;
connect ( reply , & QNetworkReply : : finished , [ = ] {
auto str = QString ( reply - > readAll ( ) ) ;
QRegularExpression re ( R " lit( \t < \ s*input .* name= " _STORED_ " value= " ( ? < stored > . * ) " >)lit " ) ;
QRegularExpressionMatch match = re . match ( str ) ;
if ( match . hasMatch ( ) ) {
stored = match . captured ( 1 ) ;
login ( info , url ) ;
} else {
auto messageBox = new QMessageBox ( QMessageBox : : Icon : : Critical , " Failed to Login " , " Failed to contact SE servers. They may be in maintenance. " ) ;
messageBox - > show ( ) ;
}
} ) ;
}
void SquareLauncher : : login ( const LoginInformation & info , const QUrl referer ) {
QUrlQuery postData ;
postData . addQueryItem ( " _STORED_ " , stored ) ;
postData . addQueryItem ( " sqexid " , info . username ) ;
postData . addQueryItem ( " password " , info . password ) ;
postData . addQueryItem ( " otppw " , info . oneTimePassword ) ;
QNetworkRequest request ( QUrl ( " https://ffxiv-login.square-enix.com/oauth/ffxivarr/login/login.send " ) ) ;
window . buildRequest ( request ) ;
request . setHeader ( QNetworkRequest : : ContentTypeHeader , " application/x-www-form-urlencoded " ) ;
request . setRawHeader ( " Referer " , referer . toEncoded ( ) ) ;
request . setRawHeader ( " Cache-Control " , " no-cache " ) ;
auto reply = window . mgr - > post ( request , postData . toString ( QUrl : : FullyEncoded ) . toUtf8 ( ) ) ;
connect ( reply , & QNetworkReply : : finished , [ = ] {
auto str = QString ( reply - > readAll ( ) ) ;
QRegularExpression re ( R " lit(window.external.user \ ( " login = auth , ok , ( ? < launchParams > . * ) \ ) ; ) lit " );
QRegularExpressionMatch match = re . match ( str ) ;
if ( match . hasMatch ( ) ) {
const auto parts = match . captured ( 1 ) . split ( ' , ' ) ;
const bool terms = parts [ 3 ] = = " 1 " ;
const bool playable = parts [ 9 ] = = " 1 " ;
if ( ! terms | | ! playable ) {
auto messageBox = new QMessageBox ( QMessageBox : : Icon : : Critical , " Failed to Login " , " Your game is unplayable. You may need to accept the terms from the official launcher. " ) ;
messageBox - > show ( ) ;
} else {
SID = parts [ 1 ] ;
auth . region = parts [ 5 ] . toInt ( ) ;
auth . maxExpansion = parts [ 13 ] . toInt ( ) ;
readExpansionVersions ( auth . maxExpansion ) ;
registerSession ( info ) ;
}
} else {
auto messageBox = new QMessageBox ( QMessageBox : : Icon : : Critical , " Failed to Login " , " Invalid username/password. " ) ;
messageBox - > show ( ) ;
}
} ) ;
}
void SquareLauncher : : registerSession ( const LoginInformation & info ) {
QUrl url ;
url . setScheme ( " https " ) ;
url . setHost ( " patch-gamever.ffxiv.com " ) ;
2021-11-09 11:03:44 -05:00
url . setPath ( QString ( " /http/win32/ffxivneo_release_game/%1/%2 " ) . arg ( window . currentProfile ( ) . gameVersion , SID ) ) ;
2021-11-01 09:54:58 -04:00
auto request = QNetworkRequest ( url ) ;
window . setSSL ( request ) ;
request . setRawHeader ( " X-Hash-Check " , " enabled " ) ;
request . setRawHeader ( " User-Agent " , " FFXIV PATCH CLIENT " ) ;
request . setHeader ( QNetworkRequest : : ContentTypeHeader , " application/x-www-form-urlencoded " ) ;
2021-11-09 11:03:44 -05:00
QString report = window . currentProfile ( ) . bootVersion + " = " + getBootHash ( ) ;
2021-11-01 09:54:58 -04:00
for ( int i = 0 ; i < expansionVersions . size ( ) ; i + + )
report + = QString ( " \n ex%1 \t %2 " ) . arg ( QString : : number ( i + 1 ) , expansionVersions [ i ] ) ;
auto reply = window . mgr - > post ( request , report . toUtf8 ( ) ) ;
connect ( reply , & QNetworkReply : : finished , [ = ] {
if ( reply - > rawHeaderList ( ) . contains ( " X-Patch-Unique-Id " ) ) {
auth . SID = reply - > rawHeader ( " X-Patch-Unique-Id " ) ;
2021-11-02 08:36:30 -04:00
window . launchGame ( auth ) ;
2021-11-01 09:54:58 -04:00
} else {
auto messageBox = new QMessageBox ( QMessageBox : : Icon : : Critical , " Failed to Login " , " Failed the anti-tamper check. Please restore your game to the original state or update the game. " ) ;
messageBox - > show ( ) ;
}
} ) ;
}
QString SquareLauncher : : getBootHash ( ) {
const QList < QString > fileList =
{
" ffxivboot.exe " ,
" ffxivboot64.exe " ,
" ffxivlauncher.exe " ,
" ffxivlauncher64.exe " ,
" ffxivupdater.exe " ,
" ffxivupdater64.exe "
} ;
QString result ;
for ( int i = 0 ; i < fileList . count ( ) ; i + + ) {
2021-11-09 11:03:44 -05:00
result + = fileList [ i ] + " / " + getFileHash ( window . currentProfile ( ) . gamePath + " /boot/ " + fileList [ i ] ) ;
2021-11-01 09:54:58 -04:00
if ( i ! = fileList . length ( ) - 1 )
result + = " , " ;
}
return result ;
}
void SquareLauncher : : readExpansionVersions ( int max ) {
2021-11-18 07:20:19 -05:00
expansionVersions . clear ( ) ;
2021-11-01 09:54:58 -04:00
for ( int i = 0 ; i < max ; i + + )
2021-11-09 11:03:44 -05:00
expansionVersions . push_back ( window . readVersion ( QString ( " %1/game/sqpack/ex%2/ex%2.ver " ) . arg ( window . currentProfile ( ) . gamePath , QString : : number ( i + 1 ) ) ) ) ;
2021-11-01 09:54:58 -04:00
}