diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index 1905fa73..fa0df0c5 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -20,6 +20,7 @@ //Auth includes: #include "AuthPackets.h" +#include "CommonPackets.h" #include "ServiceType.h" #include "MessageType/Server.h" #include "MessageType/Auth.h" @@ -166,15 +167,14 @@ int main(int argc, char** argv) { void HandlePacket(Packet* packet) { if (packet->length < 4) return; - if (packet->data[0] == ID_USER_PACKET_ENUM) { - if (static_cast(packet->data[1]) == ServiceType::COMMON) { - if (static_cast(packet->data[3]) == MessageType::Server::VERSION_CONFIRM) { - AuthPackets::HandleHandshake(Game::server, packet); - } - } else if (static_cast(packet->data[1]) == ServiceType::AUTH) { - if (static_cast(packet->data[3]) == MessageType::Auth::LOGIN_REQUEST) { - AuthPackets::HandleLoginRequest(Game::server, packet); - } - } + CINSTREAM; + LUBitStream luBitStream; + if (!luBitStream.ReadHeader(inStream)) return; + LOG_DEBUG("got packet for service %i", luBitStream.connectionType); + + if (luBitStream.connectionType == ServiceType::COMMON) { + CommonPackets::Handle(inStream, packet->systemAddress); + } else if (luBitStream.connectionType == ServiceType::AUTH) { + AuthPackets::Handle(inStream, packet->systemAddress); } } diff --git a/dCommon/dEnums/eLoginResponse.h b/dCommon/dEnums/eLoginResponse.h deleted file mode 100644 index 01bba3d5..00000000 --- a/dCommon/dEnums/eLoginResponse.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __ELOGINRESPONSE__H__ -#define __ELOGINRESPONSE__H__ - -#include - -enum class eLoginResponse : uint8_t { - GENERAL_FAILED = 0, - SUCCESS, - BANNED, - // Unused 3 - // Unused 4 - PERMISSIONS_NOT_HIGH_ENOUGH = 5, - INVALID_USER, - ACCOUNT_LOCKED, - WRONG_PASS, - ACCOUNT_ACTIVATION_PENDING, - ACCOUNT_DISABLED, - GAME_TIME_EXPIRED, - FREE_TRIAL_ENDED, - PLAY_SCHEDULE_TIME_UP, - ACCOUNT_NOT_ACTIVATED -}; - -#endif //!__ELOGINRESPONSE__H__ diff --git a/dCommon/dEnums/eServerDisconnectIdentifiers.h b/dCommon/dEnums/eServerDisconnectIdentifiers.h deleted file mode 100644 index 99d2cd44..00000000 --- a/dCommon/dEnums/eServerDisconnectIdentifiers.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __ESERVERDISCONNECTIDENTIFIERS__H__ -#define __ESERVERDISCONNECTIDENTIFIERS__H__ - -#include - -enum class eServerDisconnectIdentifiers : uint32_t { - UNKNOWN_SERVER_ERROR = 0, - WRONG_GAME_VERSION, - WRONG_SERVER_VERSION, - CONNECTION_ON_INVALID_PORT, - DUPLICATE_LOGIN, - SERVER_SHUTDOWN, - SERVER_MAP_LOAD_FAILURE, - INVALID_SESSION_KEY, - ACCOUNT_NOT_IN_PENDING_LIST, - CHARACTER_NOT_FOUND, - CHARACTER_CORRUPTED, - KICK, - SAVE_FAILURE, - FREE_TRIAL_EXPIRED, - PLAY_SCHEDULE_TIME_DONE -}; - -#endif //!__ESERVERDISCONNECTIDENTIFIERS__H__ diff --git a/dGame/User.cpp b/dGame/User.cpp index 806d4611..9424e6e4 100644 --- a/dGame/User.cpp +++ b/dGame/User.cpp @@ -5,8 +5,8 @@ #include "Logger.h" #include "Game.h" #include "dZoneManager.h" -#include "eServerDisconnectIdentifiers.h" #include "eGameMasterLevel.h" +#include "CommonPackets.h" User::User(const SystemAddress& sysAddr, const std::string& username, const std::string& sessionKey) { m_AccountID = 0; @@ -108,7 +108,10 @@ void User::UserOutOfSync() { if (m_AmountOfTimesOutOfSync > m_MaxDesyncAllowed) { //YEET LOG("User %s was out of sync %i times out of %i, disconnecting for suspected speedhacking.", m_Username.c_str(), m_AmountOfTimesOutOfSync, m_MaxDesyncAllowed); - Game::server->Disconnect(this->m_SystemAddress, eServerDisconnectIdentifiers::PLAY_SCHEDULE_TIME_DONE); + CommonPackets::DisconnectNotify notification; + notification.disconnectID = eServerDisconnectIdentifiers::PLAY_SCHEDULE_TIME_DONE; + notification.Send(this->m_SystemAddress); + Game::server->Disconnect(this->m_SystemAddress); } } diff --git a/dGame/dUtilities/Mail.h b/dGame/dUtilities/Mail.h index 9c83025f..1735ef43 100644 --- a/dGame/dUtilities/Mail.h +++ b/dGame/dUtilities/Mail.h @@ -105,7 +105,6 @@ namespace Mail { struct MailLUBitStream : public LUBitStream { eMessageID messageID = eMessageID::UnknownError; - SystemAddress sysAddr = UNASSIGNED_SYSTEM_ADDRESS; Entity* player = nullptr; MailLUBitStream() = default; diff --git a/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp b/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp index b31291fe..a131b804 100644 --- a/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp +++ b/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp @@ -3,6 +3,7 @@ // Classes #include "Character.h" #include "ChatPackets.h" +#include "CommonPackets.h" #include "dServer.h" #include "PlayerManager.h" #include "User.h" @@ -16,7 +17,6 @@ // Enums #include "MessageType/Chat.h" -#include "eServerDisconnectIdentifiers.h" #include "eObjectBits.h" namespace GMGreaterThanZeroCommands { @@ -31,8 +31,10 @@ namespace GMGreaterThanZeroCommands { ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + username); return; } - - Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::KICK); + CommonPackets::DisconnectNotify notification; + notification.disconnectID = eServerDisconnectIdentifiers::KICK; + notification.Send(player->GetSystemAddress()); + Game::server->Disconnect(player->GetSystemAddress()); ChatPackets::SendSystemMessage(sysAddr, u"Kicked: " + username); } else { @@ -69,7 +71,10 @@ namespace GMGreaterThanZeroCommands { if (accountId != 0) Database::Get()->UpdateAccountBan(accountId, true); if (player != nullptr) { - Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED); + CommonPackets::DisconnectNotify notification; + notification.disconnectID = eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED; + notification.Send(player->GetSystemAddress()); + Game::server->Disconnect(player->GetSystemAddress()); } ChatPackets::SendSystemMessage(sysAddr, u"Banned: " + GeneralUtils::ASCIIToUTF16(splitArgs[0])); diff --git a/dNet/AuthPackets.cpp b/dNet/AuthPackets.cpp index 4a9edc9e..87a445cd 100644 --- a/dNet/AuthPackets.cpp +++ b/dNet/AuthPackets.cpp @@ -17,84 +17,25 @@ #include "Game.h" #include "dConfig.h" -#include "eServerDisconnectIdentifiers.h" -#include "eLoginResponse.h" #include "ServiceType.h" #include "MessageType/Server.h" #include "MessageType/Master.h" #include "eGameMasterLevel.h" #include "StringifiedEnum.h" +#include "CommonPackets.h" +#include "ClientPackets.h" namespace { std::vector claimCodes; } -void Stamp::Serialize(RakNet::BitStream& outBitStream) { - outBitStream.Write(type); - outBitStream.Write(value); - outBitStream.Write(timestamp); -}; - namespace AuthPackets { - std::map()>> g_Handlers = { - {eMessageID::HandshakeRequest, []() { - return std::make_unique(); - }}, - {eMessageID::LoginRequest, []() { + std::map()>> g_Handlers = { + {MessageType::Auth::LOGIN_REQUEST, []() { return std::make_unique(); - }}, + }} }; - void AuthLUBitStream::Serialize(RakNet::BitStream& bitStream) const { - bitStream.Write(messageID); - } - - bool AuthLUBitStream::Deserialize(RakNet::BitStream& bitstream) { - VALIDATE_READ(bitstream.Read(messageID)); - return true; - } - - bool HandshakeRequest::Deserialize(RakNet::BitStream& bitStream) { - VALIDATE_READ(bitStream.Read(clientVersion)); - bitStream.IgnoreBytes(4); - VALIDATE_READ(bitStream.Read(serviceType)); - if (serviceType != ServiceType::CLIENT) LOG("WARNING: Service is not a Client!"); - bitStream.IgnoreBytes(2); - VALIDATE_READ(bitStream.Read(processID)); - VALIDATE_READ(bitStream.Read(port)); - if (port != sysAddr.port) LOG("WARNING: Port written in packet does not match the port the client is connecting over!"); - bitStream.IgnoreBytes(33); - return true; - } - - void HandshakeRequest::Handle() { - LOG_DEBUG("Client Data [Version: %i, Service: %s, Process: %u, Port: %u, Sysaddr Port: %u]", - clientVersion, StringifiedEnum::ToString(serviceType).data(), processID, port, sysAddr.port); - - HandshakeResponse response(server->GetIP(), server->GetPort(), server->GetServerType()); - response.server = server; - response.Send(sysAddr); - } - - void HandshakeResponse::Serialize(RakNet::BitStream& bitStream) const { - BitStreamUtils::WriteHeader(bitStream, ServiceType::COMMON, MessageType::Server::VERSION_CONFIRM); - - const auto& clientNetVersionString = Game::config->GetValue("client_net_version"); - const uint32_t clientNetVersion = GeneralUtils::TryParse(clientNetVersionString).value_or(171022); - - bitStream.Write(clientNetVersion); - bitStream.Write(861228100); - bitStream.Write(static_cast(serverType)); - bitStream.Write(219818307120); - } - - std::string CleanReceivedString(const std::string& str) { - std::string toReturn = str; - const auto removed = std::ranges::find_if(toReturn, [](unsigned char c) { return isprint(c) == 0 && isblank(c) == 0; }); - toReturn.erase(removed, toReturn.end()); - return toReturn; - } - bool LoginRequest::Deserialize(RakNet::BitStream& bitStream) { LUWString usernameLUString; VALIDATE_READ(bitStream.Read(usernameLUString)); @@ -103,64 +44,86 @@ namespace AuthPackets { LUWString passwordLUString(41); VALIDATE_READ(bitStream.Read(passwordLUString)); password = passwordLUString.GetAsString(); - VALIDATE_READ(bitStream.Read(locale_id)); - LOG_DEBUG("Locale ID: %s", StringifiedEnum::ToString(locale_id).data()); - VALIDATE_READ(bitStream.Read(clientOS)); - LOG_DEBUG("Operating System: %s", StringifiedEnum::ToString(clientOS).data()); - LUWString memoryStatsLU(256); VALIDATE_READ(bitStream.Read(memoryStatsLU)); - computerInfo.memoryStats = CleanReceivedString(memoryStatsLU.GetAsString()); - LOG_DEBUG("Memory Stats [%s]", computerInfo.memoryStats.c_str()); + computerInfo.memoryStats = memoryStatsLU.GetAsString(); LUWString videoCardLU(128); VALIDATE_READ(bitStream.Read(videoCardLU)); - computerInfo.videoCard = CleanReceivedString(videoCardLU.GetAsString()); - LOG_DEBUG("VideoCard Info: [%s]", computerInfo.videoCard.c_str()); + computerInfo.videoCard = videoCardLU.GetAsString(); // Processor/CPU info VALIDATE_READ(bitStream.Read(computerInfo.processorInfo.count)); VALIDATE_READ(bitStream.Read(computerInfo.processorInfo.type)); VALIDATE_READ(bitStream.Read(computerInfo.processorInfo.level)); VALIDATE_READ(bitStream.Read(computerInfo.processorInfo.revision)); - LOG_DEBUG("CPU Info: [#Processors: %i, Processor Type: %s, Processor Level: %s, Processor Revision: %s]", - computerInfo.processorInfo.count, - StringifiedEnum::ToString(computerInfo.processorInfo.type).data(), - StringifiedEnum::ToString(computerInfo.processorInfo.level).data(), - StringifiedEnum::ToString(computerInfo.processorInfo.revision).data() - ); // OS Info VALIDATE_READ(bitStream.Read(computerInfo.osVersionInfo.infoSize)); - VALIDATE_READ(bitStream.Read(computerInfo.osVersionInfo.version)); + VALIDATE_READ(bitStream.Read(computerInfo.osVersionInfo.majorVersion)); + VALIDATE_READ(bitStream.Read(computerInfo.osVersionInfo.minorVersion)); VALIDATE_READ(bitStream.Read(computerInfo.osVersionInfo.buildNumber)); VALIDATE_READ(bitStream.Read(computerInfo.osVersionInfo.platformID)); - LOG_DEBUG("OS Info: [Size: %i, Version: %s, Buid#: %s, platformID: %s]", - computerInfo.osVersionInfo.infoSize, - StringifiedEnum::ToString(computerInfo.osVersionInfo.version).data(), - StringifiedEnum::ToString(computerInfo.osVersionInfo.buildNumber).data(), - StringifiedEnum::ToString(computerInfo.osVersionInfo.platformID).data() - ); return true; } void LoginRequest::Handle() { - std::vector stamps; - stamps.emplace_back(eStamps::PASSPORT_AUTH_START, 0); - stamps.emplace_back(eStamps::PASSPORT_AUTH_CLIENT_OS, 0); + LOG_DEBUG("Login Request from %s", username.c_str()); + LOG_DEBUG("Password: %s", password.c_str()); + + LOG_DEBUG("Locale ID: %s", StringifiedEnum::ToString(locale_id).data()); + + LOG_DEBUG("Operating System: %s", StringifiedEnum::ToString(clientOS).data()); + + LOG_DEBUG("Memory Stats [%s]", computerInfo.memoryStats.c_str()); + + LOG_DEBUG("VideoCard Info: [%s]", computerInfo.videoCard.c_str()); + + LOG_DEBUG("CPU Info: [#Processors: %i, Processor Type: %i, Processor Level: %i, Processor Revision: %i]", + computerInfo.processorInfo.count, + computerInfo.processorInfo.type, + computerInfo.processorInfo.level, + computerInfo.processorInfo.revision + ); + + LOG_DEBUG("OS Info: [Size: %i, Version: %i.%i, Buid#: %i, platformID: %i]", + computerInfo.osVersionInfo.infoSize, + computerInfo.osVersionInfo.majorVersion, + computerInfo.osVersionInfo.minorVersion, + computerInfo.osVersionInfo.buildNumber, + computerInfo.osVersionInfo.platformID + ); + + ClientPackets::LoginResponse response; + response.sysAddr = this->sysAddr; + response.stamps.emplace_back(eStamps::PASSPORT_AUTH_START, 0); + response.stamps.emplace_back(eStamps::PASSPORT_AUTH_CLIENT_OS, 0); + response.events.push_back(LUString(Game::config->GetValue("event_1"))); + response.events.push_back(LUString(Game::config->GetValue("event_2"))); + response.events.push_back(LUString(Game::config->GetValue("event_3"))); + response.events.push_back(LUString(Game::config->GetValue("event_4"))); + response.events.push_back(LUString(Game::config->GetValue("event_5"))); + response.events.push_back(LUString(Game::config->GetValue("event_6"))); + response.events.push_back(LUString(Game::config->GetValue("event_7"))); + response.events.push_back(LUString(Game::config->GetValue("event_8"))); + response.version_major = GeneralUtils::TryParse(Game::config->GetValue("version_major")).value_or(ClientVersion::major); + response.version_current = GeneralUtils::TryParse(Game::config->GetValue("version_current")).value_or(ClientVersion::current); + response.version_minor = GeneralUtils::TryParse(Game::config->GetValue("version_minor")).value_or(ClientVersion::minor); + + uint32_t sessionKey = GeneralUtils::GenerateRandomNumber(); + std::string userHash = std::to_string(sessionKey); + response.userKey = md5(userHash); // Fetch account details auto accountInfo = Database::Get()->GetAccountInfo(username); if (!accountInfo) { LOG("No user by name %s found!", username.c_str()); - stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); - LoginResponse response(eLoginResponse::INVALID_USER, "", "", 2001, username, stamps); - response.server = server; + response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); response.Send(sysAddr); return; } @@ -168,9 +131,7 @@ namespace AuthPackets { //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"); if (closedToNonDevs.size() > 0 && bool(std::stoi(closedToNonDevs)) && accountInfo->maxGmLevel == eGameMasterLevel::CIVILIAN) { - stamps.emplace_back(eStamps::GM_REQUIRED, 1); - LoginResponse response(eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "The server is currently only open to developers.", "", 2001, username, stamps); - response.server = server; + response.stamps.emplace_back(eStamps::GM_REQUIRED, 1); response.Send(sysAddr); return; } @@ -178,9 +139,9 @@ namespace AuthPackets { if (Game::config->GetValue("dont_use_keys") != "1" && accountInfo->maxGmLevel == eGameMasterLevel::CIVILIAN) { //Check to see if we have a play key: if (accountInfo->playKeyId == 0) { - stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); - LoginResponse response(eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "Your account doesn't have a play key associated with it!", "", 2001, username, stamps); - response.server = server; + response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); + response.responseCode = eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH; + response.errorMessage = "Your account doesn't have a play key associated with it!"; response.Send(sysAddr); LOG("User %s tried to log in, but they don't have a play key.", username.c_str()); return; @@ -190,37 +151,37 @@ namespace AuthPackets { auto playKeyStatus = Database::Get()->IsPlaykeyActive(accountInfo->playKeyId); if (!playKeyStatus) { - stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); - LoginResponse response(eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "Your account doesn't have a valid play key associated with it!", "", 2001, username, stamps); - response.server = server; + response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); + response.responseCode = eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH; + response.errorMessage = "Your account doesn't have a valid play key associated with it!"; response.Send(sysAddr); return; } if (!playKeyStatus.value()) { - stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); - LoginResponse response(eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "Your play key has been disabled.", "", 2001, username, stamps); - response.server = server; + response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); + response.responseCode = eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH; + response.errorMessage = "Your play key has been disabled."; response.Send(sysAddr); LOG("User %s tried to log in, but their play key was disabled", username.c_str()); return; } } else if (Game::config->GetValue("dont_use_keys") == "1" || accountInfo->maxGmLevel > eGameMasterLevel::CIVILIAN) { - stamps.emplace_back(eStamps::PASSPORT_AUTH_BYPASS, 1); + response.stamps.emplace_back(eStamps::PASSPORT_AUTH_BYPASS, 1); } if (accountInfo->banned) { - stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); - LoginResponse response(eLoginResponse::BANNED, "", "", 2001, username, stamps); - response.server = server; + response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); + response.responseCode = eLoginResponse::BANNED; + response.errorMessage = "Your account has been banned."; response.Send(sysAddr); return; } if (accountInfo->locked) { - stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); - LoginResponse response(eLoginResponse::ACCOUNT_LOCKED, "", "", 2001, username, stamps); - response.server = server; + response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); + response.responseCode = eLoginResponse::ACCOUNT_LOCKED; + response.errorMessage = "Your account is locked."; response.Send(sysAddr); return; } @@ -228,189 +189,61 @@ namespace AuthPackets { bool loginSuccess = ::bcrypt_checkpw(password.c_str(), accountInfo->bcryptPassword.c_str()) == 0; if (!loginSuccess) { - stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); - LoginResponse response(eLoginResponse::WRONG_PASS, "", "", 2001, username, stamps); - response.server = server; + response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1); + response.responseCode = eLoginResponse::WRONG_PASS; response.Send(sysAddr); - LOG("Wrong password used"); } else { - SystemAddress system = sysAddr; //Copy the sysAddr - auto serverPtr = server; - auto usernameCopy = username; - ZoneInstanceManager::Instance()->RequestZoneTransfer(server, 0, 0, false, [system, serverPtr, usernameCopy, stamps](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string zoneIP, uint16_t zonePort) mutable { - LoginResponse response(eLoginResponse::SUCCESS, "", zoneIP, zonePort, usernameCopy, stamps); - response.server = serverPtr; - response.Send(system); - return; - } - ); + ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, 0, 0, false, [this, response, sessionKey](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string zoneIP, uint16_t zonePort) mutable { + response.responseCode = eLoginResponse::SUCCESS; + response.worldServerIP = LUString(zoneIP); + response.worldServerPort = zonePort; + response.Send(); + + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, ServiceType::MASTER, MessageType::Master::SET_SESSION_KEY); + bitStream.Write(sessionKey); + LOG_DEBUG("Sending session key for %s to master server", this->username.c_str()); + bitStream.Write(LUString(this->username)); + Game::server->SendToMaster(bitStream); + }); for (auto const code : claimCodes) { Database::Get()->InsertRewardCode(accountInfo->id, code); } } } +} - void LoginResponse::Serialize(RakNet::BitStream& bitStream) const { - std::vector mutableStamps = stamps; - mutableStamps.emplace_back(eStamps::PASSPORT_AUTH_IM_LOGIN_START, 1); - - BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, MessageType::Client::LOGIN_RESPONSE); +// Non Stuct Functions +void AuthPackets::LoadClaimCodes() { + if (!claimCodes.empty()) return; + auto rcstring = Game::config->GetValue("rewardcodes"); + auto codestrings = GeneralUtils::SplitString(rcstring, ','); + for (auto const& codestring : codestrings) { + const auto code = GeneralUtils::TryParse(codestring); - bitStream.Write(responseCode); - - // Event Gating - bitStream.Write(LUString(Game::config->GetValue("event_1"))); - bitStream.Write(LUString(Game::config->GetValue("event_2"))); - bitStream.Write(LUString(Game::config->GetValue("event_3"))); - bitStream.Write(LUString(Game::config->GetValue("event_4"))); - bitStream.Write(LUString(Game::config->GetValue("event_5"))); - bitStream.Write(LUString(Game::config->GetValue("event_6"))); - bitStream.Write(LUString(Game::config->GetValue("event_7"))); - bitStream.Write(LUString(Game::config->GetValue("event_8"))); - - const uint16_t version_major = - GeneralUtils::TryParse(Game::config->GetValue("version_major")).value_or(ClientVersion::major); - const uint16_t version_current = - GeneralUtils::TryParse(Game::config->GetValue("version_current")).value_or(ClientVersion::current); - const uint16_t version_minor = - GeneralUtils::TryParse(Game::config->GetValue("version_minor")).value_or(ClientVersion::minor); - - bitStream.Write(version_major); - bitStream.Write(version_current); - bitStream.Write(version_minor); - - // Writes the user key - uint32_t sessionKey = GeneralUtils::GenerateRandomNumber(); - std::string userHash = std::to_string(sessionKey); - userHash = md5(userHash); - bitStream.Write(LUWString(userHash)); - - // World Server IP - bitStream.Write(LUString(wServerIP)); - // Chat Server IP (unused) - bitStream.Write(LUString("")); - - // World Server Redirect port - bitStream.Write(wServerPort); - // Char Server Redirect port (unused) - bitStream.Write(static_cast(0)); - - // CDN Key - bitStream.Write(LUString("")); - - // CDN Ticket - bitStream.Write(LUString("00000000-0000-0000-0000-000000000000", 37)); - - // Language - bitStream.Write(Language::en_US); - - // Write the localization - bitStream.Write(LUString("US", 3)); - - bitStream.Write(false); // Just upgraded from F2P - bitStream.Write(false); // User is F2P - bitStream.Write(0); // Time Remaining in F2P - - // Write custom error message - bitStream.Write(errorMsg.length()); - bitStream.Write(LUWString(errorMsg, static_cast(errorMsg.length()))); - - mutableStamps.emplace_back(eStamps::PASSPORT_AUTH_WORLD_COMMUNICATION_FINISH, 1); - - bitStream.Write((sizeof(Stamp) * mutableStamps.size()) + sizeof(uint32_t)); - for (auto& stamp : mutableStamps) stamp.Serialize(bitStream); - - //Inform the master server that we've created a session for this user: - if (responseCode == eLoginResponse::SUCCESS && server) { - uint32_t masterSessionKey = GeneralUtils::GenerateRandomNumber(); - RakNet::BitStream masterBitStream; - BitStreamUtils::WriteHeader(masterBitStream, ServiceType::MASTER, MessageType::Master::SET_SESSION_KEY); - masterBitStream.Write(masterSessionKey); - masterBitStream.Write(LUString(username)); - server->SendToMaster(masterBitStream); - - LOG("Set sessionKey: %i for user %s", masterSessionKey, username.c_str()); - } - } - - - - void LoadClaimCodes() { - if(!claimCodes.empty()) return; - auto rcstring = Game::config->GetValue("rewardcodes"); - auto codestrings = GeneralUtils::SplitString(rcstring, ','); - for(auto const &codestring: codestrings){ - const auto code = GeneralUtils::TryParse(codestring); - - if (code && code.value() != -1) claimCodes.push_back(code.value()); - } + if (code && code.value() != -1) claimCodes.push_back(code.value()); } } -// Legacy wrapper functions for backward compatibility -void AuthPackets::HandleHandshake(dServer* server, Packet* packet) { - CINSTREAM_SKIP_HEADER; - - HandshakeRequest request; - request.sysAddr = packet->systemAddress; - request.server = server; - - if (request.Deserialize(inStream)) { - request.Handle(); - } else { - LOG_DEBUG("Error Reading Handshake Request"); - } -} +// Non Stuct Functions +void AuthPackets::Handle(RakNet::BitStream& inStream, const SystemAddress& sysAddr) { + inStream.ResetReadPointer(); + LUBitStream lubitstream; + if (!lubitstream.ReadHeader(inStream)) return; -void AuthPackets::SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort, const ServiceType serverType) { - HandshakeResponse response(nextServerIP, nextServerPort, serverType); - response.server = server; - response.Send(sysAddr); -} - -void AuthPackets::HandleLoginRequest(dServer* server, Packet* packet) { - CINSTREAM_SKIP_HEADER; - - LoginRequest request; - request.sysAddr = packet->systemAddress; - request.server = server; - - if (request.Deserialize(inStream)) { - request.Handle(); - } else { - LOG_DEBUG("Error Reading Login Request"); - } -} - -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& stamps) { - LoginResponse response(responseCode, errorMsg, wServerIP, wServerPort, username, stamps); - response.server = server; - response.Send(sysAddr); -} - -// Non Struct Functions -void AuthPackets::HandleAuth(RakNet::BitStream& inStream, const SystemAddress& sysAddr, dServer* server) { - AuthLUBitStream data; - if (!data.Deserialize(inStream)) { - LOG_DEBUG("Error Reading Auth header"); - return; - } - - auto it = g_Handlers.find(data.messageID); + auto it = g_Handlers.find(static_cast(lubitstream.internalPacketID)); if (it != g_Handlers.end()) { auto request = it->second(); request->sysAddr = sysAddr; - request->server = server; if (!request->Deserialize(inStream)) { - LOG_DEBUG("Error Reading Auth Request: %s", StringifiedEnum::ToString(data.messageID).data()); + LOG_DEBUG("Error Reading Auth Packet: %s", StringifiedEnum::ToString(static_cast(lubitstream.internalPacketID)).data()); return; } - LOG("Received auth message %s", StringifiedEnum::ToString(data.messageID).data()); + LOG_DEBUG("Received Auth Packet: %s", StringifiedEnum::ToString(static_cast(lubitstream.internalPacketID)).data()); request->Handle(); } else { - LOG_DEBUG("Unhandled Auth Request with ID: %i", data.messageID); + LOG_DEBUG("Unhandled Auth Packet with ID: %i", lubitstream.internalPacketID); } } - diff --git a/dNet/AuthPackets.h b/dNet/AuthPackets.h index d574ec67..190a8e24 100644 --- a/dNet/AuthPackets.h +++ b/dNet/AuthPackets.h @@ -8,77 +8,12 @@ #include "BitStream.h" #include "RakNetTypes.h" #include "BitStreamUtils.h" -#include -#include +#include "MessageType/Auth.h" enum class eLoginResponse : uint8_t; enum class ServiceType : uint16_t; class dServer; -enum class eMessageID : uint32_t { - HandshakeRequest = 0, - HandshakeResponse, - LoginRequest, - LoginResponse, - UnknownError -}; - -enum class eStamps : uint32_t { - PASSPORT_AUTH_START, - PASSPORT_AUTH_BYPASS, - PASSPORT_AUTH_ERROR, - PASSPORT_AUTH_DB_SELECT_START, - PASSPORT_AUTH_DB_SELECT_FINISH, - PASSPORT_AUTH_DB_INSERT_START, - PASSPORT_AUTH_DB_INSERT_FINISH, - PASSPORT_AUTH_LEGOINT_COMMUNICATION_START, - PASSPORT_AUTH_LEGOINT_RECEIVED, - PASSPORT_AUTH_LEGOINT_THREAD_SPAWN, - PASSPORT_AUTH_LEGOINT_WEBSERVICE_START, - PASSPORT_AUTH_LEGOINT_WEBSERVICE_FINISH, - PASSPORT_AUTH_LEGOINT_LEGOCLUB_START, - PASSPORT_AUTH_LEGOINT_LEGOCLUB_FINISH, - PASSPORT_AUTH_LEGOINT_THREAD_FINISH, - PASSPORT_AUTH_LEGOINT_REPLY, - PASSPORT_AUTH_LEGOINT_ERROR, - PASSPORT_AUTH_LEGOINT_COMMUNICATION_END, - PASSPORT_AUTH_LEGOINT_DISCONNECT, - PASSPORT_AUTH_WORLD_COMMUNICATION_START, - PASSPORT_AUTH_CLIENT_OS, - PASSPORT_AUTH_WORLD_PACKET_RECEIVED, - PASSPORT_AUTH_IM_COMMUNICATION_START, - PASSPORT_AUTH_IM_LOGIN_START, - PASSPORT_AUTH_IM_LOGIN_ALREADY_LOGGED_IN, - PASSPORT_AUTH_IM_OTHER_LOGIN_REMOVED, - PASSPORT_AUTH_IM_LOGIN_QUEUED, - PASSPORT_AUTH_IM_LOGIN_RESPONSE, - PASSPORT_AUTH_IM_COMMUNICATION_END, - PASSPORT_AUTH_WORLD_SESSION_CONFIRM_TO_AUTH, - PASSPORT_AUTH_WORLD_COMMUNICATION_FINISH, - PASSPORT_AUTH_WORLD_DISCONNECT, - NO_LEGO_INTERFACE, - DB_ERROR, - GM_REQUIRED, - NO_LEGO_WEBSERVICE_XML, - LEGO_WEBSERVICE_TIMEOUT, - LEGO_WEBSERVICE_ERROR, - NO_WORLD_SERVER -}; - -struct Stamp { - eStamps type; - uint32_t value; - uint64_t timestamp; - - Stamp(eStamps type, uint32_t value, uint64_t timestamp = time(nullptr)){ - this->type = type; - this->value = value; - this->timestamp = timestamp; - } - - void Serialize(RakNet::BitStream& outBitStream); -}; - enum class ClientOS : uint8_t { UNKNOWN, WINDOWS, @@ -91,171 +26,15 @@ enum class LanguageCodeID : uint16_t { en_GB = 0x0809 }; -// For more info on these values, go to this link -// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info -enum class ProcessorType : uint32_t { - UNKNOWN = 0, - INTEL_386 = 386, // Intel 80386 - INTEL_486 = 486, // Intel 80486 - PENTIUM = 586, // Intel Pentium - MIPS = 4000, // MIPS R4000 - ALPHA = 21064, // Alpha 21064 - PPC = 601, // PowerPC 601 - SHX = 103, // SuperH SHX - INTEL_IA64 = 2200, // Intel Itanium - AMD_X8664 = 8664, // x64 (AMD or Intel EM64T) - ARM = 448, // ARM (0x01C0 in hex, 448 in decimal) - ARM64 = 43620 // ARM64 (0xAA64 in hex, 43620 in decimal) -}; - -enum class ProcessorLevel : uint16_t { - INTEL_386 = 3, - INTEL_486 = 4, - PENTIUM = 5, - INTEL_P6 = 6, // Pentium Pro/II/III/4 or later - ITANIUM = 0xA, - X64 = 0xE, - ARM = 0x14, - ARM64 = 0x15, - UNKNOWN = 0xFFFF -}; - -// ProcessorRevision is typically a 16-bit value, but we can define some common values for reference -// For x86: high byte = model, low byte = stepping -// For other architectures, refer to documentation -enum class ProcessorRevision : uint16_t { - // Intel 80386 - INTEL_386_MODEL_0_STEPPING_0 = 0x0000, - INTEL_386_MODEL_0_STEPPING_1 = 0x0001, - // Intel 80486 - INTEL_486_MODEL_0_STEPPING_0 = 0x0000, - INTEL_486_MODEL_0_STEPPING_1 = 0x0001, - // Intel Pentium - PENTIUM_MODEL_1_STEPPING_1 = 0x0101, - PENTIUM_MODEL_2_STEPPING_3 = 0x0203, - // Intel Pentium Pro/II/III/4 - P6_MODEL_3_STEPPING_3 = 0x0303, - P6_MODEL_5_STEPPING_7 = 0x0507, - // Intel Itanium - ITANIUM_MODEL_1_STEPPING_0 = 0x0100, - // AMD x64 - AMD_X64_MODEL_15_STEPPING_65 = 0x0F41, - AMD_X64_MODEL_23_STEPPING_1 = 0x1701, - // Intel x64 - INTEL_X64_MODEL_6_STEPPING_10 = 0x060A, - INTEL_X64_MODEL_15_STEPPING_11 = 0x0F0B, - // ARM/ARM64 (values are typically implementation-specific) - ARM_MODEL_0_STEPPING_0 = 0x0000, - ARM64_MODEL_0_STEPPING_0 = 0x0000, - // Unknown - UNKNOWN = 0xFFFF -}; - -// Windows version enum based on OSVERSIONINFOEXA major/minor values -// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexa -enum class WindowsVersion : uint32_t { - UNKNOWN = 0, - WIN_2000 = 0x0500, // Major: 5, Minor: 0 - WIN_XP = 0x0501, // Major: 5, Minor: 1 - WIN_SERVER_2003 = 0x0502, // Major: 5, Minor: 2 - WIN_VISTA = 0x0600, // Major: 6, Minor: 0 - WIN_7 = 0x0601, // Major: 6, Minor: 1 - WIN_8 = 0x0602, // Major: 6, Minor: 2 - WIN_8_1 = 0x0603, // Major: 6, Minor: 3 - WIN_10 = 0x0A00, // Major: 10, Minor: 0 - WIN_11 = 0x0A00 // Major: 10, Minor: 0 (distinguish by build number) -}; - -// Windows Platform ID enum based on OSVERSIONINFOEXA documentation -// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexa -enum class WindowsPlatformID : uint32_t { - UNKNOWN = 0, - WIN32s = 0, // Windows 3.x - WIN32_WINDOWS = 1, // Windows 95/98/ME - WIN32_NT = 2, // Windows NT and later - WIN32_CE = 3 // Windows CE -}; - -// Windows Build Number enum (common values) -enum class WindowsBuildNumber : uint32_t { - UNKNOWN = 0, - WIN_2000 = 2195, - WIN_XP = 2600, - WIN_SERVER_2003 = 3790, - WIN_VISTA = 6000, - WIN_7 = 7600, - WIN_7_SP1 = 7601, - WIN_8 = 9200, - WIN_8_1 = 9600, - WIN_10_1507 = 10240, - WIN_10_1511 = 10586, - WIN_10_1607 = 14393, - WIN_10_1703 = 15063, - WIN_10_1709 = 16299, - WIN_10_1803 = 17134, - WIN_10_1809 = 17763, - WIN_10_1903 = 18362, - WIN_10_1909 = 18363, - WIN_10_2004 = 19041, - WIN_10_20H2 = 19042, - WIN_10_21H1 = 19043, - WIN_10_21H2 = 19044, - WIN_10_22H2 = 19045, - WIN_11_21H2 = 22000, - WIN_11_22H2 = 22621, - WIN_11_23H2 = 22631 -}; - template <> struct magic_enum::customize::enum_range { static constexpr int min = 1031; static constexpr int max = 2057; }; -enum class Language : uint32_t { - en_US, - pl_US, - de_DE, - en_GB, -}; - namespace AuthPackets { - struct AuthLUBitStream : public LUBitStream { - eMessageID messageID = eMessageID::UnknownError; - SystemAddress sysAddr = UNASSIGNED_SYSTEM_ADDRESS; - dServer* server = nullptr; - AuthLUBitStream() = default; - AuthLUBitStream(eMessageID _messageID) : messageID{_messageID} {}; - - virtual void Serialize(RakNet::BitStream& bitStream) const override; - virtual bool Deserialize(RakNet::BitStream& bitStream) override; - virtual void Handle() override {}; - }; - - struct HandshakeRequest : public AuthLUBitStream { - uint32_t clientVersion = 0; - ServiceType serviceType; - uint32_t processID = 0; - uint16_t port = 0; - - HandshakeRequest() : AuthLUBitStream(eMessageID::HandshakeRequest) {} - bool Deserialize(RakNet::BitStream& bitStream) override; - void Handle() override; - }; - - struct HandshakeResponse : public AuthLUBitStream { - std::string nextServerIP; - uint16_t nextServerPort = 0; - ServiceType serverType; - - HandshakeResponse() : AuthLUBitStream(eMessageID::HandshakeResponse) {} - HandshakeResponse(const std::string& ip, uint16_t port, ServiceType type) - : AuthLUBitStream(eMessageID::HandshakeResponse), nextServerIP(ip), nextServerPort(port), serverType(type) {} - void Serialize(RakNet::BitStream& bitStream) const override; - }; - - struct LoginRequest : public AuthLUBitStream { + struct LoginRequest : public LUBitStream { std::string username; std::string password; LanguageCodeID locale_id; @@ -265,46 +44,28 @@ namespace AuthPackets { std::string videoCard; struct ProcessorInfo { uint32_t count = 0; - ProcessorType type = ProcessorType::UNKNOWN; - ProcessorLevel level = ProcessorLevel::UNKNOWN; - ProcessorRevision revision = ProcessorRevision::UNKNOWN; + uint32_t type = 0; + uint16_t level = 0; + uint16_t revision = 0; } processorInfo; struct OSVersionInfo { uint32_t infoSize = 0; - WindowsVersion version = WindowsVersion::UNKNOWN; - WindowsBuildNumber buildNumber = WindowsBuildNumber::UNKNOWN; - WindowsPlatformID platformID = WindowsPlatformID::UNKNOWN; + uint32_t majorVersion = 0; + uint32_t minorVersion = 0; + uint32_t buildNumber = 0; + uint32_t platformID = 0; } osVersionInfo; } computerInfo; - LoginRequest() : AuthLUBitStream(eMessageID::LoginRequest) {} + LoginRequest() : LUBitStream(ServiceType::AUTH, MessageType::Auth::LOGIN_REQUEST) {} bool Deserialize(RakNet::BitStream& bitStream) override; void Handle() override; }; - struct LoginResponse : public AuthLUBitStream { - eLoginResponse responseCode; - std::string errorMsg; - std::string wServerIP; - uint16_t wServerPort = 0; - std::string username; - std::vector stamps; - - LoginResponse() : AuthLUBitStream(eMessageID::LoginResponse) {} - LoginResponse(eLoginResponse code, const std::string& error, const std::string& ip, uint16_t port, const std::string& user, std::vector& s) - : AuthLUBitStream(eMessageID::LoginResponse), responseCode(code), errorMsg(error), wServerIP(ip), wServerPort(port), username(user), stamps(s) {} - void Serialize(RakNet::BitStream& bitStream) const override; - }; - - // Legacy function signatures maintained for backward compatibility - void HandleHandshake(dServer* server, Packet* packet); - void SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort, const ServiceType serverType); - - void HandleLoginRequest(dServer* server, Packet* packet); - void SendLoginResponse(dServer* server, const SystemAddress& sysAddr, eLoginResponse responseCode, const std::string& errorMsg, const std::string& wServerIP, uint16_t wServerPort, std::string username, std::vector& stamps); - - void HandleAuth(RakNet::BitStream& inStream, const SystemAddress& sysAddr, dServer* server); + // Non struct functions void LoadClaimCodes(); + void Handle(RakNet::BitStream& inStream, const SystemAddress& sysAddr); + } #endif // AUTHPACKETS_H diff --git a/dNet/BitStreamUtils.h b/dNet/BitStreamUtils.h index 24d8c4dc..9560d16c 100644 --- a/dNet/BitStreamUtils.h +++ b/dNet/BitStreamUtils.h @@ -49,6 +49,7 @@ struct LUWString { struct LUBitStream { ServiceType connectionType = ServiceType::UNKNOWN; uint32_t internalPacketID = 0xFFFFFFFF; + SystemAddress sysAddr = UNASSIGNED_SYSTEM_ADDRESS; LUBitStream() = default; @@ -61,6 +62,7 @@ struct LUBitStream { void WriteHeader(RakNet::BitStream& bitStream) const; bool ReadHeader(RakNet::BitStream& bitStream); void Send(const SystemAddress& sysAddr) const; + void Send() const { Send(this->sysAddr); }; void Broadcast() const { Send(UNASSIGNED_SYSTEM_ADDRESS); }; virtual void Serialize(RakNet::BitStream& bitStream) const {} diff --git a/dNet/CMakeLists.txt b/dNet/CMakeLists.txt index 9b780b84..53b2729e 100644 --- a/dNet/CMakeLists.txt +++ b/dNet/CMakeLists.txt @@ -2,12 +2,14 @@ set(DNET_SOURCES "AuthPackets.cpp" "BitStreamUtils.cpp" "ChatPackets.cpp" "ClientPackets.cpp" + "CommonPackets.cpp" "dServer.cpp" "MailInfo.cpp" "MasterPackets.cpp" "PacketUtils.cpp" "WorldPackets.cpp" - "ZoneInstanceManager.cpp") + "ZoneInstanceManager.cpp" + ) add_library(dNet STATIC ${DNET_SOURCES}) target_link_libraries(dNet PRIVATE bcrypt MD5 glm::glm) diff --git a/dNet/ClientPackets.cpp b/dNet/ClientPackets.cpp index a6b9f8c6..886f9c53 100644 --- a/dNet/ClientPackets.cpp +++ b/dNet/ClientPackets.cpp @@ -6,6 +6,47 @@ #include "ClientPackets.h" #include "dCommonVars.h" #include "PositionUpdate.h" +#include "StringifiedEnum.h" + + +namespace ClientPackets { + void Stamp::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(type); + bitStream.Write(value); + bitStream.Write(timestamp); + }; + + void LoginResponse::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(responseCode); + bitStream.Write(events[0]); + bitStream.Write(events[1]); + bitStream.Write(events[2]); + bitStream.Write(events[3]); + bitStream.Write(events[4]); + bitStream.Write(events[5]); + bitStream.Write(events[6]); + bitStream.Write(events[7]); + bitStream.Write(version_major); + bitStream.Write(version_current); + bitStream.Write(version_minor); + bitStream.Write(userKey); + bitStream.Write(worldServerIP); + bitStream.Write(chatServerIP); + bitStream.Write(worldServerPort); + bitStream.Write(chatServerPort); + bitStream.Write(cdnKey); + bitStream.Write(cdnTicket); + bitStream.Write(language); + bitStream.Write(localization); + bitStream.Write(static_cast(justUpgradedFromF2P)); + bitStream.Write(static_cast(isF2P)); + bitStream.Write(membershipTimeLeft); + bitStream.Write(errorMessage.length()); + bitStream.Write(LUWString(errorMessage, static_cast(errorMessage.length()))); + bitStream.Write((sizeof(Stamp) * stamps.size()) + sizeof(uint32_t)); + for (const auto& stampData : stamps) stampData.Serialize(bitStream); + }; +} ChatMessage ClientPackets::HandleChatMessage(Packet* packet) { CINSTREAM_SKIP_HEADER; diff --git a/dNet/ClientPackets.h b/dNet/ClientPackets.h index a7d2941b..4029f9b3 100644 --- a/dNet/ClientPackets.h +++ b/dNet/ClientPackets.h @@ -8,6 +8,8 @@ #include #include +#include "BitStreamUtils.h" +#include "MessageType/Client.h" class PositionUpdate; @@ -26,11 +28,120 @@ struct ChatModerationRequest { std::string message; }; + +enum class eLoginResponse : uint8_t { + GENERAL_FAILED = 0, + SUCCESS, + BANNED, + // Unused 3 + // Unused 4 + PERMISSIONS_NOT_HIGH_ENOUGH = 5, + INVALID_USER, + ACCOUNT_LOCKED, + WRONG_PASS, + ACCOUNT_ACTIVATION_PENDING, + ACCOUNT_DISABLED, + GAME_TIME_EXPIRED, + FREE_TRIAL_ENDED, + PLAY_SCHEDULE_TIME_UP, + ACCOUNT_NOT_ACTIVATED +}; + +enum class eStamps : uint32_t { + PASSPORT_AUTH_START, + PASSPORT_AUTH_BYPASS, + PASSPORT_AUTH_ERROR, + PASSPORT_AUTH_DB_SELECT_START, + PASSPORT_AUTH_DB_SELECT_FINISH, + PASSPORT_AUTH_DB_INSERT_START, + PASSPORT_AUTH_DB_INSERT_FINISH, + PASSPORT_AUTH_LEGOINT_COMMUNICATION_START, + PASSPORT_AUTH_LEGOINT_RECEIVED, + PASSPORT_AUTH_LEGOINT_THREAD_SPAWN, + PASSPORT_AUTH_LEGOINT_WEBSERVICE_START, + PASSPORT_AUTH_LEGOINT_WEBSERVICE_FINISH, + PASSPORT_AUTH_LEGOINT_LEGOCLUB_START, + PASSPORT_AUTH_LEGOINT_LEGOCLUB_FINISH, + PASSPORT_AUTH_LEGOINT_THREAD_FINISH, + PASSPORT_AUTH_LEGOINT_REPLY, + PASSPORT_AUTH_LEGOINT_ERROR, + PASSPORT_AUTH_LEGOINT_COMMUNICATION_END, + PASSPORT_AUTH_LEGOINT_DISCONNECT, + PASSPORT_AUTH_WORLD_COMMUNICATION_START, + PASSPORT_AUTH_CLIENT_OS, + PASSPORT_AUTH_WORLD_PACKET_RECEIVED, + PASSPORT_AUTH_IM_COMMUNICATION_START, + PASSPORT_AUTH_IM_LOGIN_START, + PASSPORT_AUTH_IM_LOGIN_ALREADY_LOGGED_IN, + PASSPORT_AUTH_IM_OTHER_LOGIN_REMOVED, + PASSPORT_AUTH_IM_LOGIN_QUEUED, + PASSPORT_AUTH_IM_LOGIN_RESPONSE, + PASSPORT_AUTH_IM_COMMUNICATION_END, + PASSPORT_AUTH_WORLD_SESSION_CONFIRM_TO_AUTH, + PASSPORT_AUTH_WORLD_COMMUNICATION_FINISH, + PASSPORT_AUTH_WORLD_DISCONNECT, + NO_LEGO_INTERFACE, + DB_ERROR, + GM_REQUIRED, + NO_LEGO_WEBSERVICE_XML, + LEGO_WEBSERVICE_TIMEOUT, + LEGO_WEBSERVICE_ERROR, + NO_WORLD_SERVER +}; + +enum class Language : uint32_t { + en_US, + pl_US, + de_DE, + en_GB, +}; + namespace ClientPackets { + struct Stamp { + eStamps type; + uint32_t value; + uint64_t timestamp; + + Stamp(eStamps type, uint32_t value, uint64_t timestamp = time(nullptr)) { + this->type = type; + this->value = value; + this->timestamp = timestamp; + } + + void Serialize(RakNet::BitStream& bitStream) const; + }; + + struct LoginResponse : public LUBitStream { + eLoginResponse responseCode = eLoginResponse::GENERAL_FAILED; + std::vector events; + uint16_t version_major = 0; + uint16_t version_current = 0; + uint16_t version_minor = 0; + LUWString userKey; + LUString worldServerIP; + LUString chatServerIP = LUString(""); // unused + uint16_t worldServerPort = 0; + uint16_t chatServerPort = 0; // unused + LUString cdnKey = LUString(""); + LUString cdnTicket = LUString("00000000-0000-0000-0000-000000000000", 37); + Language language = Language::en_US; + LUString localization = LUString("US", 3); + bool justUpgradedFromF2P = false; // written as uint8_t + bool isF2P = false; // written as uint8_t + uint64_t membershipTimeLeft = 0; + std::string errorMessage; + std::vector stamps; + + LoginResponse() : LUBitStream(ServiceType::CLIENT, MessageType::Client::LOGIN_RESPONSE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + }; + + ChatMessage HandleChatMessage(Packet* packet); PositionUpdate HandleClientPositionUpdate(Packet* packet); ChatModerationRequest HandleChatModerationRequest(Packet* packet); int32_t SendTop5HelpIssues(Packet* packet); }; + #endif // CLIENTPACKETS_H diff --git a/dNet/CommonPackets.cpp b/dNet/CommonPackets.cpp new file mode 100644 index 00000000..2a04ba5c --- /dev/null +++ b/dNet/CommonPackets.cpp @@ -0,0 +1,86 @@ + +#include "CommonPackets.h" +#include "dServer.h" +#include "Logger.h" +#include "Game.h" +#include "dServer.h" +#include "dConfig.h" +#include "StringifiedEnum.h" +#include "GeneralUtils.h" + + +namespace CommonPackets { + std::map()>> g_Handlers = { + {MessageType::Server::VERSION_CONFIRM, []() { + return std::make_unique(); + }}, + {MessageType::Server::DISCONNECT_NOTIFY, []() { + return std::make_unique(); + }}, + {MessageType::Server::GENERAL_NOTIFY, []() { + return std::make_unique(); + }} + }; + + void VersionConfirm::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(netVersion); + bitStream.Write(861228100); + bitStream.Write(static_cast(serviceType)); + bitStream.Write(219818307120); + } + + bool VersionConfirm::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(netVersion)); + uint32_t unknown = 0; + VALIDATE_READ(bitStream.Read(unknown)); + VALIDATE_READ(bitStream.Read(serviceType)); + uint16_t unknown2 = 0; + VALIDATE_READ(bitStream.Read(unknown2)); + VALIDATE_READ(bitStream.Read(processID)); + VALIDATE_READ(bitStream.Read(port)); + LUString unknownString; + VALIDATE_READ(bitStream.Read(unknownString)); + return true; + } + + void VersionConfirm::Handle() { + LOG_DEBUG("Client Data [Version: %i, Service: %s, Process: %u, Port: %u, Sysaddr Port: %u]", netVersion, StringifiedEnum::ToString(serviceType).data(), processID, port, sysAddr.port); + + VersionConfirm response; + auto& serverNetVersionString = Game::config->GetValue("client_net_version"); + const uint32_t serverNetVersion = GeneralUtils::TryParse(serverNetVersionString).value_or(171022); + response.netVersion = serverNetVersion; + response.serviceType = Game::server->GetServerType(); + response.Send(sysAddr); + } + + void DisconnectNotify::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(disconnectID); + } + + void GeneralNotify::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(notifyID); + bitStream.Write(notifyUser); + } +} + +void CommonPackets::Handle(RakNet::BitStream& inStream, const SystemAddress& sysAddr) { + inStream.ResetReadPointer(); + LUBitStream lubitstream; + if (!lubitstream.ReadHeader(inStream)) return; + + auto it = g_Handlers.find(static_cast(lubitstream.internalPacketID)); + if (it != g_Handlers.end()) { + auto request = it->second(); + request->sysAddr = sysAddr; + if (!request->Deserialize(inStream)) { + LOG_DEBUG("Error Reading Common Packet: %s", StringifiedEnum::ToString(static_cast(lubitstream.internalPacketID)).data()); + return; + } + LOG_DEBUG("Received Common Packet: %s", StringifiedEnum::ToString(static_cast(lubitstream.internalPacketID)).data()); + request->Handle(); + } else { + LOG_DEBUG("Unhandled Common Packet with ID: %i", lubitstream.internalPacketID); + } +} + diff --git a/dNet/CommonPackets.h b/dNet/CommonPackets.h new file mode 100644 index 00000000..69d17253 --- /dev/null +++ b/dNet/CommonPackets.h @@ -0,0 +1,57 @@ +#include "dCommonVars.h" +#include "dNetCommon.h" +#include "BitStreamUtils.h" +#include "MessageType/Server.h" + +enum class eServerDisconnectIdentifiers : uint32_t { + UNKNOWN_SERVER_ERROR = 0, + WRONG_GAME_VERSION, + WRONG_SERVER_VERSION, + CONNECTION_ON_INVALID_PORT, + DUPLICATE_LOGIN, + SERVER_SHUTDOWN, + SERVER_MAP_LOAD_FAILURE, + INVALID_SESSION_KEY, + ACCOUNT_NOT_IN_PENDING_LIST, + CHARACTER_NOT_FOUND, + CHARACTER_CORRUPTED, + KICK, + SAVE_FAILURE, + FREE_TRIAL_EXPIRED, + PLAY_SCHEDULE_TIME_DONE +}; + +// Packet Struct Functions +namespace CommonPackets { + + struct VersionConfirm : public LUBitStream { + uint32_t netVersion = 0; + ServiceType serviceType; + uint32_t processID = 0; + uint16_t port = 0; + + VersionConfirm() : LUBitStream(ServiceType::COMMON, MessageType::Server::VERSION_CONFIRM) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle() override; + }; + + struct DisconnectNotify : public LUBitStream { + eServerDisconnectIdentifiers disconnectID = eServerDisconnectIdentifiers::UNKNOWN_SERVER_ERROR; + + DisconnectNotify() : LUBitStream(ServiceType::COMMON, MessageType::Server::DISCONNECT_NOTIFY) {} + void Serialize(RakNet::BitStream& bitStream) const override; + }; + + struct GeneralNotify : public LUBitStream { + uint32_t notifyID = 0; // only one known value: 0, which is Duplicate account login + bool notifyUser = true; + + GeneralNotify() : LUBitStream(ServiceType::COMMON, MessageType::Server::GENERAL_NOTIFY) {} + void Serialize(RakNet::BitStream& bitStream) const override; + }; + + // Non Struct functions + void Handle(RakNet::BitStream& inStream, const SystemAddress& sysAddr); +} + diff --git a/dNet/dServer.cpp b/dNet/dServer.cpp index 0a8e0ab9..0fd07a10 100644 --- a/dNet/dServer.cpp +++ b/dNet/dServer.cpp @@ -197,12 +197,7 @@ void dServer::SendToMaster(RakNet::BitStream& bitStream) { mMasterPeer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, mMasterSystemAddress, false); } -void dServer::Disconnect(const SystemAddress& sysAddr, eServerDisconnectIdentifiers disconNotifyID) { - RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, ServiceType::COMMON, MessageType::Server::DISCONNECT_NOTIFY); - bitStream.Write(disconNotifyID); - mPeer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, sysAddr, false); - +void dServer::Disconnect(const SystemAddress& sysAddr) { mPeer->CloseConnection(sysAddr, true); } diff --git a/dNet/dServer.h b/dNet/dServer.h index c1b96c1a..8ac4ddeb 100644 --- a/dNet/dServer.h +++ b/dNet/dServer.h @@ -43,7 +43,7 @@ public: virtual void Send(RakNet::BitStream& bitStream, const SystemAddress& sysAddr, bool broadcast); void SendToMaster(RakNet::BitStream& bitStream); - void Disconnect(const SystemAddress& sysAddr, eServerDisconnectIdentifiers disconNotifyID); + void Disconnect(const SystemAddress& sysAddr); bool IsConnected(const SystemAddress& sysAddr); const std::string& GetIP() const { return mIP; } diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index cb7fedd5..2e0978a4 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -40,6 +40,7 @@ #include "dChatFilter.h" #include "ClientPackets.h" #include "CharacterComponent.h" +#include "CommonPackets.h" #include "EntityManager.h" #include "EntityInfo.h" @@ -62,7 +63,6 @@ #include "eBlueprintSaveResponseType.h" #include "Amf3.h" #include "NiPoint3.h" -#include "eServerDisconnectIdentifiers.h" #include "eObjectBits.h" #include "ServiceType.h" #include "MessageType/Server.h" @@ -78,7 +78,6 @@ #include "Server.h" #include "PositionUpdate.h" #include "PlayerManager.h" -#include "eLoginResponse.h" #include "MissionComponent.h" #include "SlashCommandHandler.h" #include "InventoryComponent.h" @@ -703,7 +702,10 @@ void HandleMasterPacket(Packet* packet) { //Verify it: if (userHash != it->second.hash) { LOG("SOMEONE IS TRYING TO HACK? SESSION KEY MISMATCH: ours: %s != master: %s", userHash.c_str(), it->second.hash.c_str()); - Game::server->Disconnect(it->second.sysAddr, eServerDisconnectIdentifiers::INVALID_SESSION_KEY); + CommonPackets::DisconnectNotify notification; + notification.disconnectID = eServerDisconnectIdentifiers::INVALID_SESSION_KEY; + notification.Send(it->second.sysAddr); + Game::server->Disconnect(it->second.sysAddr); return; } else { LOG("User %s authenticated with correct key.", username.GetAsString().c_str()); @@ -786,7 +788,10 @@ void HandleMasterPacket(Packet* packet) { //Check the key: if (sessionKey != std::atoi(user->GetSessionKey().c_str())) { LOG("But the session key is invalid!", username.string.c_str()); - Game::server->Disconnect(user->GetSystemAddress(), eServerDisconnectIdentifiers::INVALID_SESSION_KEY); + CommonPackets::DisconnectNotify notification; + notification.disconnectID = eServerDisconnectIdentifiers::INVALID_SESSION_KEY; + notification.Send(user->GetSystemAddress()); + Game::server->Disconnect(user->GetSystemAddress()); return; } break; @@ -855,13 +860,10 @@ void HandlePacket(Packet* packet) { luBitStream.ReadHeader(inStream); if (luBitStream.connectionType == ServiceType::COMMON) { - if (static_cast(luBitStream.internalPacketID) == MessageType::Server::VERSION_CONFIRM) { - AuthPackets::HandleHandshake(Game::server, packet); - } + CommonPackets::Handle(inStream, packet->systemAddress); } if (luBitStream.connectionType != ServiceType::WORLD) return; - switch (static_cast(luBitStream.internalPacketID)) { case MessageType::World::VALIDATION: { CINSTREAM_SKIP_HEADER; @@ -879,7 +881,10 @@ void HandlePacket(Packet* packet) { auto accountInfo = Database::Get()->GetAccountInfo(username.GetAsString()); if (!accountInfo) { LOG("Client's account does not exist in the database, aborting connection."); - Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::CHARACTER_NOT_FOUND); + CommonPackets::DisconnectNotify notification; + notification.disconnectID = eServerDisconnectIdentifiers::CHARACTER_NOT_FOUND; + notification.Send(packet->systemAddress); + Game::server->Disconnect(packet->systemAddress); return; } @@ -888,13 +893,13 @@ void HandlePacket(Packet* packet) { if (accountInfo->maxGmLevel < eGameMasterLevel::DEVELOPER) { LOG("Client's database checksum does not match the server's, aborting connection."); - std::vector stamps; - // Using the LoginResponse here since the UI is still in the login screen state // and we have a way to send a message about the client mismatch. - AuthPackets::SendLoginResponse( - Game::server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, - Game::config->GetValue("cdclient_mismatch_message"), "", 0, "", stamps); + ClientPackets::LoginResponse response; + response.sysAddr = packet->systemAddress; + response.responseCode = eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH; + response.errorMessage= Game::config->GetValue("cdclient_mismatch_message"); + response.Send(packet->systemAddress); return; } else { AMFArrayValue args; @@ -1207,7 +1212,10 @@ void HandlePacket(Packet* packet) { } } else { LOG("Couldn't find character to log in with for user %s (%i)!", user->GetUsername().c_str(), user->GetAccountID()); - Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::CHARACTER_NOT_FOUND); + CommonPackets::DisconnectNotify notification; + notification.disconnectID = eServerDisconnectIdentifiers::CHARACTER_NOT_FOUND; + notification.Send(packet->systemAddress); + Game::server->Disconnect(packet->systemAddress); } } else { LOG("Couldn't get user for level load complete!"); @@ -1386,7 +1394,11 @@ void HandlePacket(Packet* packet) { if (user) { user->UserOutOfSync(); } else { - Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::KICK); + CommonPackets::DisconnectNotify notification; + notification.disconnectID = eServerDisconnectIdentifiers::KICK; + notification.Send(packet->systemAddress); + Game::server->Disconnect(packet->systemAddress); + } break; } @@ -1463,8 +1475,10 @@ void WorldShutdownProcess(uint32_t zoneId) { while (Game::server->GetReplicaManager()->GetParticipantCount() > 0) { const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(0); - - Game::server->Disconnect(player, eServerDisconnectIdentifiers::SERVER_SHUTDOWN); + CommonPackets::DisconnectNotify notification; + notification.disconnectID = eServerDisconnectIdentifiers::SERVER_SHUTDOWN; + notification.Send(player); + Game::server->Disconnect(player); } SendShutdownMessageToMaster(); }