2021-12-05 17:54:36 +00:00
# include "AuthPackets.h"
2023-09-21 01:06:28 +00:00
# include "BitStreamUtils.h"
2021-12-05 17:54:36 +00:00
# include "dNetCommon.h"
# include "dServer.h"
2023-10-21 23:31:55 +00:00
# include "Logger.h"
2021-12-05 17:54:36 +00:00
# include "Database.h"
# include "ZoneInstanceManager.h"
# include "MD5.h"
2023-07-23 21:59:43 +00:00
# include "GeneralUtils.h"
2024-03-04 01:06:19 +00:00
# include "dClient/ClientVersion.h"
2021-12-05 17:54:36 +00:00
# include <bcrypt/BCrypt.hpp>
2024-01-05 12:33:52 +00:00
# include "BitStream.h"
2021-12-05 17:54:36 +00:00
# include <future>
# include "Game.h"
# include "dConfig.h"
2023-02-19 12:29:14 +00:00
# include "eServerDisconnectIdentifiers.h"
2023-05-02 22:39:21 +00:00
# include "eLoginResponse.h"
2023-05-03 21:38:32 +00:00
# include "eConnectionType.h"
2024-11-18 00:39:44 +00:00
# include "MessageType/Server.h"
# include "MessageType/Master.h"
2023-11-18 00:47:18 +00:00
# include "eGameMasterLevel.h"
2024-01-06 08:16:10 +00:00
# include "StringifiedEnum.h"
2023-11-22 02:05:15 +00:00
namespace {
std : : vector < uint32_t > claimCodes ;
}
2024-02-26 14:06:02 +00:00
void Stamp : : Serialize ( RakNet : : BitStream & outBitStream ) {
outBitStream . Write ( type ) ;
outBitStream . Write ( value ) ;
outBitStream . Write ( timestamp ) ;
2024-01-06 08:16:10 +00:00
} ;
2023-11-22 02:05:15 +00:00
void AuthPackets : : LoadClaimCodes ( ) {
if ( ! claimCodes . empty ( ) ) return ;
auto rcstring = Game : : config - > GetValue ( " rewardcodes " ) ;
auto codestrings = GeneralUtils : : SplitString ( rcstring , ' , ' ) ;
for ( auto const & codestring : codestrings ) {
2024-02-10 11:05:25 +00:00
const auto code = GeneralUtils : : TryParse < uint32_t > ( codestring ) ;
if ( code & & code . value ( ) ! = - 1 ) claimCodes . push_back ( code . value ( ) ) ;
2023-11-22 02:05:15 +00:00
}
}
2021-12-05 17:54:36 +00:00
void AuthPackets : : HandleHandshake ( dServer * server , Packet * packet ) {
2024-01-06 08:16:10 +00:00
CINSTREAM_SKIP_HEADER
2021-12-05 17:54:36 +00:00
uint32_t clientVersion = 0 ;
inStream . Read ( clientVersion ) ;
2024-01-06 08:16:10 +00:00
inStream . IgnoreBytes ( 4 ) ;
ServiceId serviceId ;
inStream . Read ( serviceId ) ;
if ( serviceId ! = ServiceId : : Client ) LOG ( " WARNING: Service ID is not a Client! " ) ;
uint32_t processID ;
inStream . Read ( processID ) ;
uint16_t port ;
inStream . Read ( port ) ;
if ( port ! = packet - > systemAddress . port ) LOG ( " WARNING: Port written in packet does not match the port the client is connecting over! " ) ;
inStream . IgnoreBytes ( 33 ) ;
2024-11-18 00:39:44 +00:00
2024-01-06 08:16:10 +00:00
LOG_DEBUG ( " Client Data [Version: %i, Service: %s, Process: %u, Port: %u, Sysaddr Port: %u] " , clientVersion , StringifiedEnum : : ToString ( serviceId ) . data ( ) , processID , port , packet - > systemAddress . port ) ;
2022-07-25 02:26:51 +00:00
2022-11-07 09:27:48 +00:00
SendHandshake ( server , packet - > systemAddress , server - > GetIP ( ) , server - > GetPort ( ) , server - > GetServerType ( ) ) ;
2021-12-05 17:54:36 +00:00
}
2022-11-07 09:27:48 +00:00
void AuthPackets : : SendHandshake ( dServer * server , const SystemAddress & sysAddr , const std : : string & nextServerIP , uint16_t nextServerPort , const ServerType serverType ) {
2021-12-05 17:54:36 +00:00
RakNet : : BitStream bitStream ;
2024-11-18 00:39:44 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : SERVER , MessageType : : Server : : VERSION_CONFIRM ) ;
2024-01-05 00:21:03 +00:00
const auto clientNetVersionString = Game : : config - > GetValue ( " client_net_version " ) ;
2024-02-10 11:05:25 +00:00
const uint32_t clientNetVersion = GeneralUtils : : TryParse < uint32_t > ( clientNetVersionString ) . value_or ( 171022 ) ;
2024-01-05 00:21:03 +00:00
bitStream . Write < uint32_t > ( clientNetVersion ) ;
2024-01-06 08:16:10 +00:00
bitStream . Write < uint32_t > ( 861228100 ) ;
2022-07-25 02:26:51 +00:00
2024-01-06 08:16:10 +00:00
if ( serverType = = ServerType : : Auth ) bitStream . Write ( ServiceId : : Auth ) ;
else if ( serverType = = ServerType : : World ) bitStream . Write ( ServiceId : : World ) ;
else bitStream . Write ( ServiceId : : General ) ;
2024-12-18 00:07:07 +00:00
bitStream . Write < uint64_t > ( 219818241584 ) ;
2022-07-25 02:26:51 +00:00
2024-02-27 05:43:33 +00:00
server - > Send ( bitStream , sysAddr , false ) ;
2021-12-05 17:54:36 +00:00
}
2024-12-03 21:01:43 +00:00
std : : string CleanReceivedString ( const std : : string & str ) {
std : : string toReturn = str ;
2024-12-18 00:07:07 +00:00
const auto removed = std : : ranges : : find_if ( toReturn , [ ] ( unsigned char c ) { return isprint ( c ) = = 0 & & isblank ( c ) = = 0 ; } ) ;
2024-12-03 21:01:43 +00:00
toReturn . erase ( removed , toReturn . end ( ) ) ;
return toReturn ;
}
2021-12-05 17:54:36 +00:00
void AuthPackets : : HandleLoginRequest ( dServer * server , Packet * packet ) {
2024-01-06 08:16:10 +00:00
CINSTREAM_SKIP_HEADER ;
std : : vector < Stamp > stamps ;
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_START , 0 ) ;
2024-01-12 20:23:44 +00:00
LUWString usernameLUString ;
2024-01-06 08:16:10 +00:00
inStream . Read ( usernameLUString ) ;
const auto username = usernameLUString . GetAsString ( ) ;
LUWString password ( 41 ) ;
inStream . Read ( password ) ;
LanguageCodeID locale_id ;
inStream . Read ( locale_id ) ;
LOG_DEBUG ( " Locale ID: %s " , StringifiedEnum : : ToString ( locale_id ) . data ( ) ) ;
ClientOS clientOS ;
inStream . Read ( clientOS ) ;
LOG_DEBUG ( " Operating System: %s " , StringifiedEnum : : ToString ( clientOS ) . data ( ) ) ;
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_CLIENT_OS , 0 ) ;
LUWString memoryStats ( 256 ) ;
inStream . Read ( memoryStats ) ;
2024-12-03 21:01:43 +00:00
LOG_DEBUG ( " Memory Stats [%s] " , CleanReceivedString ( memoryStats . GetAsString ( ) ) . c_str ( ) ) ;
2024-01-06 08:16:10 +00:00
LUWString videoCard ( 128 ) ;
inStream . Read ( videoCard ) ;
2024-12-03 21:01:43 +00:00
LOG_DEBUG ( " VideoCard Info: [%s] " , CleanReceivedString ( videoCard . GetAsString ( ) ) . c_str ( ) ) ;
2024-01-06 08:16:10 +00:00
// Processor/CPU info
uint32_t numOfProcessors ;
inStream . Read ( numOfProcessors ) ;
uint32_t processorType ;
inStream . Read ( processorType ) ;
uint16_t processorLevel ;
inStream . Read ( processorLevel ) ;
uint16_t processorRevision ;
inStream . Read ( processorRevision ) ;
LOG_DEBUG ( " CPU Info: [#Processors: %i, Processor Type: %i, Processor Level: %i, Processor Revision: %i] " , numOfProcessors , processorType , processorLevel , processorRevision ) ;
// OS Info
uint32_t osVersionInfoSize ;
inStream . Read ( osVersionInfoSize ) ;
uint32_t majorVersion ;
inStream . Read ( majorVersion ) ;
uint32_t minorVersion ;
inStream . Read ( minorVersion ) ;
uint32_t buildNumber ;
inStream . Read ( buildNumber ) ;
uint32_t platformID ;
inStream . Read ( platformID ) ;
LOG_DEBUG ( " OS Info: [Size: %i, Major: %i, Minor %i, Buid#: %i, platformID: %i] " , osVersionInfoSize , majorVersion , minorVersion , buildNumber , platformID ) ;
2021-12-05 17:54:36 +00:00
// Fetch account details
2023-11-18 00:47:18 +00:00
auto accountInfo = Database : : Get ( ) - > GetAccountInfo ( username ) ;
2022-07-25 02:26:51 +00:00
2023-11-18 00:47:18 +00:00
if ( ! accountInfo ) {
LOG ( " No user by name %s found! " , username . c_str ( ) ) ;
2024-01-06 08:16:10 +00:00
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_ERROR , 1 ) ;
AuthPackets : : SendLoginResponse ( server , packet - > systemAddress , eLoginResponse : : INVALID_USER , " " , " " , 2001 , username , stamps ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
//If we aren't running in live mode, then only GMs are allowed to enter:
const auto & closedToNonDevs = Game : : config - > GetValue ( " closed_to_non_devs " ) ;
2023-11-18 00:47:18 +00:00
if ( closedToNonDevs . size ( ) > 0 & & bool ( std : : stoi ( closedToNonDevs ) ) & & accountInfo - > maxGmLevel = = eGameMasterLevel : : CIVILIAN ) {
2024-01-06 08:16:10 +00:00
stamps . emplace_back ( eStamps : : GM_REQUIRED , 1 ) ;
AuthPackets : : SendLoginResponse ( server , packet - > systemAddress , eLoginResponse : : PERMISSIONS_NOT_HIGH_ENOUGH , " The server is currently only open to developers. " , " " , 2001 , username , stamps ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2023-11-18 00:47:18 +00:00
if ( Game : : config - > GetValue ( " dont_use_keys " ) ! = " 1 " & & accountInfo - > maxGmLevel = = eGameMasterLevel : : CIVILIAN ) {
2021-12-05 17:54:36 +00:00
//Check to see if we have a play key:
2023-11-18 00:47:18 +00:00
if ( accountInfo - > playKeyId = = 0 ) {
2024-01-06 08:16:10 +00:00
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_ERROR , 1 ) ;
AuthPackets : : SendLoginResponse ( server , packet - > systemAddress , eLoginResponse : : PERMISSIONS_NOT_HIGH_ENOUGH , " Your account doesn't have a play key associated with it! " , " " , 2001 , username , stamps ) ;
2023-10-21 23:31:55 +00:00
LOG ( " User %s tried to log in, but they don't have a play key. " , username . c_str ( ) ) ;
2021-12-05 17:54:36 +00:00
return ;
}
//Check if the play key is _valid_:
2023-11-18 00:47:18 +00:00
auto playKeyStatus = Database : : Get ( ) - > IsPlaykeyActive ( accountInfo - > playKeyId ) ;
2022-07-25 02:26:51 +00:00
2023-11-18 00:47:18 +00:00
if ( ! playKeyStatus ) {
2024-01-06 08:16:10 +00:00
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_ERROR , 1 ) ;
AuthPackets : : SendLoginResponse ( server , packet - > systemAddress , eLoginResponse : : PERMISSIONS_NOT_HIGH_ENOUGH , " Your account doesn't have a valid play key associated with it! " , " " , 2001 , username , stamps ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2023-11-18 00:47:18 +00:00
if ( ! playKeyStatus . value ( ) ) {
2024-01-06 08:16:10 +00:00
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_ERROR , 1 ) ;
AuthPackets : : SendLoginResponse ( server , packet - > systemAddress , eLoginResponse : : PERMISSIONS_NOT_HIGH_ENOUGH , " Your play key has been disabled. " , " " , 2001 , username , stamps ) ;
2023-10-21 23:31:55 +00:00
LOG ( " User %s tried to log in, but their play key was disabled " , username . c_str ( ) ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2024-01-06 08:16:10 +00:00
} else if ( Game : : config - > GetValue ( " dont_use_keys " ) = = " 1 " | | accountInfo - > maxGmLevel > eGameMasterLevel : : CIVILIAN ) {
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_BYPASS , 1 ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-25 02:26:51 +00:00
2023-11-18 00:47:18 +00:00
if ( accountInfo - > banned ) {
2024-01-06 08:16:10 +00:00
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_ERROR , 1 ) ;
AuthPackets : : SendLoginResponse ( server , packet - > systemAddress , eLoginResponse : : BANNED , " " , " " , 2001 , username , stamps ) ;
return ;
2021-12-05 17:54:36 +00:00
}
2023-11-18 00:47:18 +00:00
if ( accountInfo - > locked ) {
2024-01-06 08:16:10 +00:00
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_ERROR , 1 ) ;
AuthPackets : : SendLoginResponse ( server , packet - > systemAddress , eLoginResponse : : ACCOUNT_LOCKED , " " , " " , 2001 , username , stamps ) ;
return ;
2021-12-05 17:54:36 +00:00
}
2024-01-06 08:16:10 +00:00
bool loginSuccess = : : bcrypt_checkpw ( password . GetAsString ( ) . c_str ( ) , accountInfo - > bcryptPassword . c_str ( ) ) = = 0 ;
2021-12-05 17:54:36 +00:00
if ( ! loginSuccess ) {
2024-01-06 08:16:10 +00:00
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_ERROR , 1 ) ;
AuthPackets : : SendLoginResponse ( server , packet - > systemAddress , eLoginResponse : : WRONG_PASS , " " , " " , 2001 , username , stamps ) ;
2023-10-21 23:31:55 +00:00
LOG ( " Wrong password used " ) ;
2021-12-05 17:54:36 +00:00
} else {
SystemAddress system = packet - > systemAddress ; //Copy the sysAddr before the Packet gets destroyed from main
if ( ! server - > GetIsConnectedToMaster ( ) ) {
2024-01-06 08:16:10 +00:00
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_WORLD_DISCONNECT , 1 ) ;
AuthPackets : : SendLoginResponse ( server , system , eLoginResponse : : GENERAL_FAILED , " " , " " , 0 , username , stamps ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2024-01-06 08:16:10 +00:00
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_WORLD_SESSION_CONFIRM_TO_AUTH , 1 ) ;
ZoneInstanceManager : : Instance ( ) - > RequestZoneTransfer ( server , 0 , 0 , false , [ system , server , username , stamps ] ( bool mythranShift , uint32_t zoneID , uint32_t zoneInstance , uint32_t zoneClone , std : : string zoneIP , uint16_t zonePort ) mutable {
AuthPackets : : SendLoginResponse ( server , system , eLoginResponse : : SUCCESS , " " , zoneIP , zonePort , username , stamps ) ;
2021-12-05 17:54:36 +00:00
} ) ;
}
2023-11-22 02:05:15 +00:00
for ( auto const code : claimCodes ) {
Database : : Get ( ) - > InsertRewardCode ( accountInfo - > id , code ) ;
}
2021-12-05 17:54:36 +00:00
}
2024-01-06 08:16:10 +00:00
void AuthPackets : : SendLoginResponse ( dServer * server , const SystemAddress & sysAddr , eLoginResponse responseCode , const std : : string & errorMsg , const std : : string & wServerIP , uint16_t wServerPort , std : : string username , std : : vector < Stamp > & stamps ) {
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_IM_LOGIN_START , 1 ) ;
RakNet : : BitStream loginResponse ;
2024-11-18 00:39:44 +00:00
BitStreamUtils : : WriteHeader ( loginResponse , eConnectionType : : CLIENT , MessageType : : Client : : LOGIN_RESPONSE ) ;
2022-07-25 02:26:51 +00:00
2024-03-07 05:45:04 +00:00
loginResponse . Write ( responseCode ) ;
2022-07-25 02:26:51 +00:00
2023-09-21 01:06:28 +00:00
// Event Gating
2024-01-06 08:16:10 +00:00
loginResponse . Write ( LUString ( Game : : config - > GetValue ( " event_1 " ) ) ) ;
loginResponse . Write ( LUString ( Game : : config - > GetValue ( " event_2 " ) ) ) ;
loginResponse . Write ( LUString ( Game : : config - > GetValue ( " event_3 " ) ) ) ;
loginResponse . Write ( LUString ( Game : : config - > GetValue ( " event_4 " ) ) ) ;
loginResponse . Write ( LUString ( Game : : config - > GetValue ( " event_5 " ) ) ) ;
loginResponse . Write ( LUString ( Game : : config - > GetValue ( " event_6 " ) ) ) ;
loginResponse . Write ( LUString ( Game : : config - > GetValue ( " event_7 " ) ) ) ;
loginResponse . Write ( LUString ( Game : : config - > GetValue ( " event_8 " ) ) ) ;
2023-11-18 09:33:23 +00:00
2024-02-10 11:05:25 +00:00
const uint16_t version_major =
GeneralUtils : : TryParse < uint16_t > ( Game : : config - > GetValue ( " version_major " ) ) . value_or ( ClientVersion : : major ) ;
const uint16_t version_current =
GeneralUtils : : TryParse < uint16_t > ( Game : : config - > GetValue ( " version_current " ) ) . value_or ( ClientVersion : : current ) ;
const uint16_t version_minor =
GeneralUtils : : TryParse < uint16_t > ( Game : : config - > GetValue ( " version_minor " ) ) . value_or ( ClientVersion : : minor ) ;
2023-11-18 09:33:23 +00:00
2024-01-06 08:16:10 +00:00
loginResponse . Write ( version_major ) ;
loginResponse . Write ( version_current ) ;
loginResponse . Write ( version_minor ) ;
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
// Writes the user key
2023-07-23 21:59:43 +00:00
uint32_t sessionKey = GeneralUtils : : GenerateRandomNumber < uint32_t > ( ) ;
2021-12-05 17:54:36 +00:00
std : : string userHash = std : : to_string ( sessionKey ) ;
userHash = md5 ( userHash ) ;
2024-01-06 08:16:10 +00:00
loginResponse . Write ( LUWString ( userHash ) ) ;
2022-07-25 02:26:51 +00:00
2024-01-06 08:16:10 +00:00
// World Server IP
loginResponse . Write ( LUString ( wServerIP ) ) ;
// Chat Server IP (unused)
loginResponse . Write ( LUString ( " " ) ) ;
2022-07-25 02:26:51 +00:00
2024-01-06 08:16:10 +00:00
// World Server Redirect port
loginResponse . Write ( wServerPort ) ;
// Char Server Redirect port (unused)
loginResponse . Write ( static_cast < uint16_t > ( 0 ) ) ;
2022-07-25 02:26:51 +00:00
2023-09-21 01:06:28 +00:00
// CDN Key
2024-01-06 08:16:10 +00:00
loginResponse . Write ( LUString ( " " ) ) ;
2022-07-25 02:26:51 +00:00
2023-09-21 01:06:28 +00:00
// CDN Ticket
2024-01-06 08:16:10 +00:00
loginResponse . Write ( LUString ( " 00000000-0000-0000-0000-000000000000 " , 37 ) ) ;
2022-07-25 02:26:51 +00:00
2024-01-06 08:16:10 +00:00
// Language
loginResponse . Write ( Language : : en_US ) ;
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
// Write the localization
2024-01-06 08:16:10 +00:00
loginResponse . Write ( LUString ( " US " , 3 ) ) ;
2022-07-25 02:26:51 +00:00
2024-01-06 08:16:10 +00:00
loginResponse . Write < uint8_t > ( false ) ; // Just upgraded from F2P
loginResponse . Write < uint8_t > ( false ) ; // User is F2P
loginResponse . Write < uint64_t > ( 0 ) ; // Time Remaining in F2P
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
// Write custom error message
2024-01-06 08:16:10 +00:00
loginResponse . Write < uint16_t > ( errorMsg . length ( ) ) ;
loginResponse . Write ( LUWString ( errorMsg , static_cast < uint32_t > ( errorMsg . length ( ) ) ) ) ;
stamps . emplace_back ( eStamps : : PASSPORT_AUTH_WORLD_COMMUNICATION_FINISH , 1 ) ;
loginResponse . Write < uint32_t > ( ( sizeof ( Stamp ) * stamps . size ( ) ) + sizeof ( uint32_t ) ) ;
2024-02-26 14:06:02 +00:00
for ( auto & stamp : stamps ) stamp . Serialize ( loginResponse ) ;
2022-07-25 02:26:51 +00:00
2024-02-27 05:43:33 +00:00
server - > Send ( loginResponse , sysAddr , false ) ;
2021-12-05 17:54:36 +00:00
//Inform the master server that we've created a session for this user:
2023-12-23 07:53:21 +00:00
if ( responseCode = = eLoginResponse : : SUCCESS ) {
2021-12-05 17:54:36 +00:00
CBITSTREAM ;
2024-11-18 00:39:44 +00:00
BitStreamUtils : : WriteHeader ( bitStream , eConnectionType : : MASTER , MessageType : : Master : : SET_SESSION_KEY ) ;
2021-12-05 17:54:36 +00:00
bitStream . Write ( sessionKey ) ;
2024-01-07 08:02:27 +00:00
bitStream . Write ( LUString ( username ) ) ;
2024-02-27 05:43:33 +00:00
server - > SendToMaster ( bitStream ) ;
2021-12-05 17:54:36 +00:00
2023-10-21 23:31:55 +00:00
LOG ( " Set sessionKey: %i for user %s " , sessionKey , username . c_str ( ) ) ;
2021-12-05 17:54:36 +00:00
}
}