diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/bnetserver/Server/Session.cpp | 6 | ||||
-rw-r--r-- | src/server/bnetserver/Server/Session.h | 2 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 5 | ||||
-rw-r--r-- | src/server/game/Server/WorldSocket.cpp | 58 | ||||
-rw-r--r-- | src/server/game/Server/WorldSocket.h | 8 | ||||
-rw-r--r-- | src/server/game/Services/WorldserverGameUtilitiesService.cpp | 5 | ||||
-rw-r--r-- | src/server/proto/RealmList/RealmList.pb.cc | 113 | ||||
-rw-r--r-- | src/server/proto/RealmList/RealmList.pb.h | 254 | ||||
-rw-r--r-- | src/server/proto/RealmList/RealmList.proto | 7 | ||||
-rw-r--r-- | src/server/shared/Realm/ClientBuildInfo.cpp | 72 | ||||
-rw-r--r-- | src/server/shared/Realm/ClientBuildInfo.h | 110 | ||||
-rw-r--r-- | src/server/shared/Realm/RealmList.cpp | 59 | ||||
-rw-r--r-- | src/server/shared/Realm/RealmList.h | 25 |
14 files changed, 659 insertions, 68 deletions
diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index d95e99e34a6..a4f760a905a 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -219,7 +219,7 @@ uint32 Battlenet::Session::HandleLogon(authentication::v1::LogonRequest const* l return ERROR_BAD_PROGRAM; } - if (logonRequest->platform() != "Win" && logonRequest->platform() != "Wn64" && logonRequest->platform() != "Mc64" && logonRequest->platform() != "MacA") + if (!ClientBuild::Platform::IsValid(logonRequest->platform())) { TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] {} attempted to log in from an unsupported platform (using {})!", GetClientInfo(), logonRequest->platform()); return ERROR_BAD_PLATFORM; @@ -591,6 +591,8 @@ uint32 Battlenet::Session::GetRealmListTicket(std::unordered_map<std::string, Va clientInfoOk = true; memcpy(_clientSecret.data(), data.info().secret().data(), _clientSecret.size()); } + + _clientInfo = { .Platform = data.info().platformtype(), .Arch = data.info().clientarch(), .Type = data.info().type() }; } } @@ -691,7 +693,7 @@ uint32 Battlenet::Session::GetRealmList(std::unordered_map<std::string, Variant uint32 Battlenet::Session::JoinRealm(std::unordered_map<std::string, Variant const*> const& params, game_utilities::v1::ClientResponse* response) { if (Variant const* realmAddress = Trinity::Containers::MapGetValuePtr(params, "Param_RealmAddress")) - return sRealmList->JoinRealm(realmAddress->uint_value(), _build, GetRemoteIpAddress(), _clientSecret, GetLocaleByName(_locale), + return sRealmList->JoinRealm(realmAddress->uint_value(), _build, _clientInfo, GetRemoteIpAddress(), _clientSecret, GetLocaleByName(_locale), _os, _timezoneOffset, _gameAccountInfo->Name, _gameAccountInfo->SecurityLevel, response); return ERROR_WOW_SERVICES_INVALID_JOIN_TICKET; diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index 33a058f940c..8a8b1f0a15b 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -19,6 +19,7 @@ #define Session_h__ #include "AsyncCallbackProcessor.h" +#include "ClientBuildInfo.h" #include "Duration.h" #include "QueryResult.h" #include "Realm.h" @@ -173,6 +174,7 @@ namespace Battlenet std::string _locale; std::string _os; uint32 _build; + ClientBuild::VariantId _clientInfo; Minutes _timezoneOffset; std::string _ipCountry; diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index ba3bb98d958..1d3e5eb4cd7 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -106,7 +106,7 @@ bool WorldSessionFilter::Process(WorldPacket* packet) /// WorldSession constructor WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, - std::string os, Minutes timezoneOffset, uint32 build, LocaleConstant locale, uint32 recruiter, bool isARecruiter): + std::string os, Minutes timezoneOffset, uint32 build, ClientBuild::VariantId clientBuildVariant, LocaleConstant locale, uint32 recruiter, bool isARecruiter): m_muteTime(mute_time), m_timeOutTime(0), AntiDOS(this), @@ -120,6 +120,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccoun m_expansion(std::min<uint8>(expansion, sWorld->getIntConfig(CONFIG_EXPANSION))), _os(std::move(os)), _clientBuild(build), + _clientBuildVariant(clientBuildVariant), _battlenetRequestToken(0), _logoutTime(0), m_inQueue(false), diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 49cc7721504..c7a405a9a10 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -25,6 +25,7 @@ #include "Common.h" #include "AsyncCallbackProcessor.h" #include "AuthDefines.h" +#include "ClientBuildInfo.h" #include "DatabaseEnvFwd.h" #include "Duration.h" #include "IteratorPair.h" @@ -938,7 +939,7 @@ class TC_GAME_API WorldSession { public: WorldSession(uint32 id, std::string&& name, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, - std::string os, Minutes timezoneOffset, uint32 build, LocaleConstant locale, uint32 recruiter, bool isARecruiter); + std::string os, Minutes timezoneOffset, uint32 build, ClientBuild::VariantId clientBuildVariant, LocaleConstant locale, uint32 recruiter, bool isARecruiter); ~WorldSession(); bool PlayerLoading() const { return !m_playerLoading.IsEmpty(); } @@ -988,6 +989,7 @@ class TC_GAME_API WorldSession uint8 GetExpansion() const { return m_expansion; } std::string const& GetOS() const { return _os; } uint32 GetClientBuild() const { return _clientBuild; } + ClientBuild::VariantId const& GetClientBuildVariant() const { return _clientBuildVariant; } bool CanAccessAlliedRaces() const; Warden* GetWarden() { return _warden.get(); } @@ -1886,6 +1888,7 @@ class TC_GAME_API WorldSession uint8 m_expansion; std::string _os; uint32 _clientBuild; + ClientBuild::VariantId _clientBuildVariant; std::array<uint8, 32> _realmListSecret; std::unordered_map<uint32 /*realmAddress*/, uint8> _realmCharacterCounts; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index f583c488367..1fde981ad53 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -27,8 +27,10 @@ #include "HMAC.h" #include "IPLocation.h" #include "PacketLog.h" +#include "ProtobufJSON.h" #include "RealmList.h" #include "RBAC.h" +#include "RealmList.pb.h" #include "ScriptMgr.h" #include "SessionKeyGenerator.h" #include "World.h" @@ -671,18 +673,27 @@ struct AccountInfo void WorldSocket::HandleAuthSession(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession) { + std::shared_ptr<JSON::RealmList::RealmJoinTicket> joinTicket = std::make_shared<JSON::RealmList::RealmJoinTicket>(); + if (!JSON::Deserialize(authSession->RealmJoinTicket, joinTicket.get())) + { + SendAuthResponseError(ERROR_WOW_SERVICES_INVALID_JOIN_TICKET); + DelayedCloseSocket(); + return; + } + // Get the account information from the auth database LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); stmt->setInt32(0, int32(sRealmList->GetCurrentRealmId().Realm)); - stmt->setString(1, authSession->RealmJoinTicket); + stmt->setString(1, joinTicket->gameaccount()); - _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback([this, authSession = std::move(authSession)](PreparedQueryResult result) mutable + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback([this, authSession = std::move(authSession), joinTicket = std::move(joinTicket)](PreparedQueryResult result) mutable { - HandleAuthSessionCallback(std::move(authSession), std::move(result)); + HandleAuthSessionCallback(std::move(authSession), std::move(joinTicket), std::move(result)); })); } -void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession, PreparedQueryResult result) +void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession, + std::shared_ptr<JSON::RealmList::RealmJoinTicket> joinTicket, PreparedQueryResult result) { // Stop if the account is not found if (!result) @@ -695,11 +706,23 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth:: AccountInfo account(result->Fetch()); - RealmBuildInfo const* buildInfo = sRealmList->GetBuildInfo(account.Game.Build); + ClientBuild::Info const* buildInfo = sRealmList->GetBuildInfo(account.Game.Build); if (!buildInfo) { SendAuthResponseError(ERROR_BAD_VERSION); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Missing auth seed for realm build {} ({}).", account.Game.Build, GetRemoteIpAddress().to_string()); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Missing client build info for build {} ({}).", account.Game.Build, GetRemoteIpAddress().to_string()); + DelayedCloseSocket(); + return; + } + + ClientBuild::VariantId buildVariant = { .Platform = joinTicket->platform(), .Arch = joinTicket->clientarch(), .Type = joinTicket->type() }; + auto clientBuildAuthKey = std::ranges::find(buildInfo->AuthKeys, buildVariant, &ClientBuild::AuthKey::Variant); + if (clientBuildAuthKey == buildInfo->AuthKeys.end()) + { + SendAuthResponseError(ERROR_BAD_VERSION); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Missing client build auth key for build {} variant {}-{}-{} ({}).", account.Game.Build, + ClientBuild::ToCharArray(buildVariant.Platform).data(), ClientBuild::ToCharArray(buildVariant.Arch).data(), + ClientBuild::ToCharArray(buildVariant.Type).data(), GetRemoteIpAddress().to_string()); DelayedCloseSocket(); return; } @@ -709,13 +732,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth:: Trinity::Crypto::SHA256 digestKeyHash; digestKeyHash.UpdateData(account.Game.KeyData.data(), account.Game.KeyData.size()); - if (account.Game.OS == "Wn64") - digestKeyHash.UpdateData(buildInfo->Win64AuthSeed.data(), buildInfo->Win64AuthSeed.size()); - else if (account.Game.OS == "Mc64") - digestKeyHash.UpdateData(buildInfo->Mac64AuthSeed.data(), buildInfo->Mac64AuthSeed.size()); - else if (account.Game.OS == "MacA") - digestKeyHash.UpdateData(buildInfo->MacArmAuthSeed.data(), buildInfo->MacArmAuthSeed.size()); - + digestKeyHash.UpdateData(clientBuildAuthKey->Key.data(), clientBuildAuthKey->Key.size()); digestKeyHash.Finalize(); Trinity::Crypto::HMAC_SHA256 hmac(digestKeyHash.GetDigest()); @@ -728,7 +745,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth:: if (memcmp(hmac.GetDigest().data(), authSession->Digest.data(), authSession->Digest.size()) != 0) { SendAuthResponseError(ERROR_DENIED); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: {} ('{}') address: {}", account.Game.Id, authSession->RealmJoinTicket, address); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: {} ('{}') address: {}", account.Game.Id, joinTicket->gameaccount(), address); DelayedCloseSocket(); return; } @@ -762,7 +779,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth:: // As we don't know if attempted login process by ip works, we update last_attempt_ip right away stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP); stmt->setString(0, address); - stmt->setString(1, authSession->RealmJoinTicket); + stmt->setString(1, joinTicket->gameaccount()); LoginDatabase.Execute(stmt); // This also allows to check for possible "hack" attempts on account } @@ -792,7 +809,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth:: // Must be done before WorldSession is created bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED); - if (wardenActive && account.Game.OS != "Win" && account.Game.OS != "Wn64" && account.Game.OS != "Mc64" && account.Game.OS != "MacA") + if (wardenActive && !ClientBuild::Platform::IsValid(account.Game.OS)) { SendAuthResponseError(ERROR_DENIED); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} attempted to log in using invalid client OS ({}).", address, account.Game.OS); @@ -862,7 +879,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth:: return; } - TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '{}' authenticated successfully from {}.", authSession->RealmJoinTicket, address); + TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '{}' authenticated successfully from {}.", joinTicket->gameaccount(), address); if (sWorld->getBoolConfig(CONFIG_ALLOW_LOGGING_IP_ADDRESSES_IN_DATABASE)) { @@ -870,7 +887,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth:: stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP); stmt->setString(0, address); - stmt->setString(1, authSession->RealmJoinTicket); + stmt->setString(1, joinTicket->gameaccount()); LoginDatabase.Execute(stmt); } @@ -879,8 +896,9 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth:: sScriptMgr->OnAccountLogin(account.Game.Id); _authed = true; - _worldSession = new WorldSession(account.Game.Id, std::move(authSession->RealmJoinTicket), account.BattleNet.Id, shared_from_this(), account.Game.Security, - account.Game.Expansion, mutetime, account.Game.OS, account.Game.TimezoneOffset, account.Game.Build, account.Game.Locale, account.Game.Recruiter, account.Game.IsRectuiter); + _worldSession = new WorldSession(account.Game.Id, std::move(*joinTicket->mutable_gameaccount()), account.BattleNet.Id, shared_from_this(), account.Game.Security, + account.Game.Expansion, mutetime, account.Game.OS, account.Game.TimezoneOffset, account.Game.Build, buildVariant, account.Game.Locale, + account.Game.Recruiter, account.Game.IsRectuiter); // Initialize Warden system only if it is enabled by config if (wardenActive) diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 2cf288bbd7b..35f58161b53 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -30,6 +30,11 @@ #include <boost/asio/ip/tcp.hpp> #include <mutex> +namespace JSON::RealmList +{ +class RealmJoinTicket; +} + typedef struct z_stream_s z_stream; class EncryptablePacket; class WorldPacket; @@ -140,7 +145,8 @@ private: void HandleSendAuthSession(); void HandleAuthSession(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession); - void HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession, PreparedQueryResult result); + void HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession, + std::shared_ptr<JSON::RealmList::RealmJoinTicket> joinTicket, PreparedQueryResult result); void HandleAuthContinuedSession(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession); void HandleAuthContinuedSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession, PreparedQueryResult result); void LoadSessionPermissionsCallback(PreparedQueryResult result); diff --git a/src/server/game/Services/WorldserverGameUtilitiesService.cpp b/src/server/game/Services/WorldserverGameUtilitiesService.cpp index 083b827c19e..20af196fe7b 100644 --- a/src/server/game/Services/WorldserverGameUtilitiesService.cpp +++ b/src/server/game/Services/WorldserverGameUtilitiesService.cpp @@ -118,8 +118,9 @@ uint32 Battlenet::Services::GameUtilitiesService::HandleRealmListRequest(std::un uint32 Battlenet::Services::GameUtilitiesService::HandleRealmJoinRequest(std::unordered_map<std::string, Variant const*> const& params, game_utilities::v1::ClientResponse* response) { if (Variant const* realmAddress = Trinity::Containers::MapGetValuePtr(params, "Param_RealmAddress")) - return sRealmList->JoinRealm(uint32(realmAddress->uint_value()), _session->GetClientBuild(), Trinity::Net::make_address(_session->GetRemoteAddress()), _session->GetRealmListSecret(), - _session->GetSessionDbcLocale(), _session->GetOS(), _session->GetTimezoneOffset(), _session->GetAccountName(), _session->GetSecurity(), response); + return sRealmList->JoinRealm(uint32(realmAddress->uint_value()), _session->GetClientBuild(), _session->GetClientBuildVariant(), + Trinity::Net::make_address(_session->GetRemoteAddress()), _session->GetRealmListSecret(), _session->GetSessionDbcLocale(), + _session->GetOS(), _session->GetTimezoneOffset(), _session->GetAccountName(), _session->GetSecurity(), response); return ERROR_WOW_SERVICES_INVALID_JOIN_TICKET; } diff --git a/src/server/proto/RealmList/RealmList.pb.cc b/src/server/proto/RealmList/RealmList.pb.cc index 44c27eadcd8..41050ae0824 100644 --- a/src/server/proto/RealmList/RealmList.pb.cc +++ b/src/server/proto/RealmList/RealmList.pb.cc @@ -60,6 +60,9 @@ const ::google::protobuf::internal::GeneratedMessageReflection* const ::google::protobuf::Descriptor* RealmListServerIPAddresses_descriptor_ = NULL; const ::google::protobuf::internal::GeneratedMessageReflection* RealmListServerIPAddresses_reflection_ = NULL; +const ::google::protobuf::Descriptor* RealmJoinTicket_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + RealmJoinTicket_reflection_ = NULL; } // namespace @@ -296,6 +299,24 @@ void protobuf_AssignDesc_RealmList_2eproto() { ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), sizeof(RealmListServerIPAddresses)); + RealmJoinTicket_descriptor_ = file->message_type(13); + static const int RealmJoinTicket_offsets_[4] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(RealmJoinTicket, gameaccount_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(RealmJoinTicket, platform_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(RealmJoinTicket, type_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(RealmJoinTicket, clientarch_), + }; + RealmJoinTicket_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + RealmJoinTicket_descriptor_, + RealmJoinTicket::default_instance_, + RealmJoinTicket_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(RealmJoinTicket, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(RealmJoinTicket, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(RealmJoinTicket)); } namespace { @@ -334,6 +355,8 @@ void protobuf_RegisterTypes(const ::std::string&) { RealmIPAddressFamily_descriptor_, &RealmIPAddressFamily::default_instance()); ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( RealmListServerIPAddresses_descriptor_, &RealmListServerIPAddresses::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + RealmJoinTicket_descriptor_, &RealmJoinTicket::default_instance()); } } // namespace @@ -365,6 +388,8 @@ void protobuf_ShutdownFile_RealmList_2eproto() { delete RealmIPAddressFamily_reflection_; delete RealmListServerIPAddresses::default_instance_; delete RealmListServerIPAddresses_reflection_; + delete RealmJoinTicket::default_instance_; + delete RealmJoinTicket_reflection_; } void protobuf_AddDesc_RealmList_2eproto() { @@ -411,7 +436,9 @@ void protobuf_AddDesc_RealmList_2eproto() { "mily\030\001 \002(\r\022,\n\taddresses\030\002 \003(\0132\031.JSON.Rea" "lmList.IPAddress\"T\n\032RealmListServerIPAdd" "resses\0226\n\010families\030\001 \003(\0132$.JSON.RealmLis" - "t.RealmIPAddressFamilyB\002H\002", 1506); + "t.RealmIPAddressFamily\"Z\n\017RealmJoinTicke" + "t\022\023\n\013gameAccount\030\001 \002(\t\022\020\n\010platform\030\002 \002(\007" + "\022\014\n\004type\030\003 \002(\007\022\022\n\nclientArch\030\004 \002(\007B\002H\002", 1598); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "RealmList.proto", &protobuf_RegisterTypes); RealmListTicketIdentity::default_instance_ = new RealmListTicketIdentity(); @@ -427,6 +454,7 @@ void protobuf_AddDesc_RealmList_2eproto() { IPAddress::default_instance_ = new IPAddress(); RealmIPAddressFamily::default_instance_ = new RealmIPAddressFamily(); RealmListServerIPAddresses::default_instance_ = new RealmListServerIPAddresses(); + RealmJoinTicket::default_instance_ = new RealmJoinTicket(); RealmListTicketIdentity::default_instance_->InitAsDefaultInstance(); ClientVersion::default_instance_->InitAsDefaultInstance(); ClientInformation::default_instance_->InitAsDefaultInstance(); @@ -440,6 +468,7 @@ void protobuf_AddDesc_RealmList_2eproto() { IPAddress::default_instance_->InitAsDefaultInstance(); RealmIPAddressFamily::default_instance_->InitAsDefaultInstance(); RealmListServerIPAddresses::default_instance_->InitAsDefaultInstance(); + RealmJoinTicket::default_instance_->InitAsDefaultInstance(); ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_RealmList_2eproto); } @@ -1474,6 +1503,88 @@ void RealmListServerIPAddresses::Swap(RealmListServerIPAddresses* other) { return metadata; } +// =================================================================== + +#ifndef _MSC_VER +const int RealmJoinTicket::kGameAccountFieldNumber; +const int RealmJoinTicket::kPlatformFieldNumber; +const int RealmJoinTicket::kTypeFieldNumber; +const int RealmJoinTicket::kClientArchFieldNumber; +#endif // !_MSC_VER + +RealmJoinTicket::RealmJoinTicket() + : ::google::protobuf::Message() { + SharedCtor(); + // @@protoc_insertion_point(constructor:JSON.RealmList.RealmJoinTicket) +} + +void RealmJoinTicket::InitAsDefaultInstance() { +} + +RealmJoinTicket::RealmJoinTicket(const RealmJoinTicket& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); + // @@protoc_insertion_point(copy_constructor:JSON.RealmList.RealmJoinTicket) +} + +void RealmJoinTicket::SharedCtor() { + ::google::protobuf::internal::GetEmptyString(); + _cached_size_ = 0; + gameaccount_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + platform_ = 0u; + type_ = 0u; + clientarch_ = 0u; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +RealmJoinTicket::~RealmJoinTicket() { + // @@protoc_insertion_point(destructor:JSON.RealmList.RealmJoinTicket) + SharedDtor(); +} + +void RealmJoinTicket::SharedDtor() { + if (gameaccount_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + delete gameaccount_; + } + if (this != default_instance_) { + } +} + +void RealmJoinTicket::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* RealmJoinTicket::descriptor() { + protobuf_AssignDescriptorsOnce(); + return RealmJoinTicket_descriptor_; +} + +const RealmJoinTicket& RealmJoinTicket::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_RealmList_2eproto(); + return *default_instance_; +} + +RealmJoinTicket* RealmJoinTicket::default_instance_ = NULL; + +RealmJoinTicket* RealmJoinTicket::New() const { + return new RealmJoinTicket; +} + +void RealmJoinTicket::Swap(RealmJoinTicket* other) { + if (other != this) { + GetReflection()->Swap(this, other);} +} + +::google::protobuf::Metadata RealmJoinTicket::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = RealmJoinTicket_descriptor_; + metadata.reflection = RealmJoinTicket_reflection_; + return metadata; +} + // @@protoc_insertion_point(namespace_scope) } // namespace RealmList diff --git a/src/server/proto/RealmList/RealmList.pb.h b/src/server/proto/RealmList/RealmList.pb.h index 56e61f22ae1..44cc4520d3b 100644 --- a/src/server/proto/RealmList/RealmList.pb.h +++ b/src/server/proto/RealmList/RealmList.pb.h @@ -48,6 +48,7 @@ class RealmListUpdates; class IPAddress; class RealmIPAddressFamily; class RealmListServerIPAddresses; +class RealmJoinTicket; // =================================================================== @@ -1277,6 +1278,107 @@ class TC_PROTO_API RealmListServerIPAddresses : public ::google::protobuf::Messa void InitAsDefaultInstance(); static RealmListServerIPAddresses* default_instance_; }; +// ------------------------------------------------------------------- + +class TC_PROTO_API RealmJoinTicket : public ::google::protobuf::Message { + public: + RealmJoinTicket(); + virtual ~RealmJoinTicket(); + + RealmJoinTicket(const RealmJoinTicket& from); + + inline RealmJoinTicket& operator=(const RealmJoinTicket& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const RealmJoinTicket& default_instance(); + + void Swap(RealmJoinTicket* other); + + // implements Message ---------------------------------------------- + + RealmJoinTicket* New() const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // required string gameAccount = 1; + inline bool has_gameaccount() const; + inline void clear_gameaccount(); + static const int kGameAccountFieldNumber = 1; + inline const ::std::string& gameaccount() const; + inline void set_gameaccount(const ::std::string& value); + inline void set_gameaccount(const char* value); + inline void set_gameaccount(const char* value, size_t size); + inline ::std::string* mutable_gameaccount(); + inline ::std::string* release_gameaccount(); + inline void set_allocated_gameaccount(::std::string* gameaccount); + + // required fixed32 platform = 2; + inline bool has_platform() const; + inline void clear_platform(); + static const int kPlatformFieldNumber = 2; + inline ::google::protobuf::uint32 platform() const; + inline void set_platform(::google::protobuf::uint32 value); + + // required fixed32 type = 3; + inline bool has_type() const; + inline void clear_type(); + static const int kTypeFieldNumber = 3; + inline ::google::protobuf::uint32 type() const; + inline void set_type(::google::protobuf::uint32 value); + + // required fixed32 clientArch = 4; + inline bool has_clientarch() const; + inline void clear_clientarch(); + static const int kClientArchFieldNumber = 4; + inline ::google::protobuf::uint32 clientarch() const; + inline void set_clientarch(::google::protobuf::uint32 value); + + // @@protoc_insertion_point(class_scope:JSON.RealmList.RealmJoinTicket) + private: + inline void set_has_gameaccount(); + inline void clear_has_gameaccount(); + inline void set_has_platform(); + inline void clear_has_platform(); + inline void set_has_type(); + inline void clear_has_type(); + inline void set_has_clientarch(); + inline void clear_has_clientarch(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::uint32 _has_bits_[1]; + mutable int _cached_size_; + ::std::string* gameaccount_; + ::google::protobuf::uint32 platform_; + ::google::protobuf::uint32 type_; + ::google::protobuf::uint32 clientarch_; + friend void TC_PROTO_API protobuf_AddDesc_RealmList_2eproto(); + friend void protobuf_AssignDesc_RealmList_2eproto(); + friend void protobuf_ShutdownFile_RealmList_2eproto(); + + void InitAsDefaultInstance(); + static RealmJoinTicket* default_instance_; +}; // =================================================================== // =================================================================== @@ -2817,6 +2919,158 @@ RealmListServerIPAddresses::mutable_families() { return &families_; } +// ------------------------------------------------------------------- + +// RealmJoinTicket + +// required string gameAccount = 1; +inline bool RealmJoinTicket::has_gameaccount() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void RealmJoinTicket::set_has_gameaccount() { + _has_bits_[0] |= 0x00000001u; +} +inline void RealmJoinTicket::clear_has_gameaccount() { + _has_bits_[0] &= ~0x00000001u; +} +inline void RealmJoinTicket::clear_gameaccount() { + if (gameaccount_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + gameaccount_->clear(); + } + clear_has_gameaccount(); +} +inline const ::std::string& RealmJoinTicket::gameaccount() const { + // @@protoc_insertion_point(field_get:JSON.RealmList.RealmJoinTicket.gameAccount) + return *gameaccount_; +} +inline void RealmJoinTicket::set_gameaccount(const ::std::string& value) { + set_has_gameaccount(); + if (gameaccount_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + gameaccount_ = new ::std::string; + } + gameaccount_->assign(value); + // @@protoc_insertion_point(field_set:JSON.RealmList.RealmJoinTicket.gameAccount) +} +inline void RealmJoinTicket::set_gameaccount(const char* value) { + set_has_gameaccount(); + if (gameaccount_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + gameaccount_ = new ::std::string; + } + gameaccount_->assign(value); + // @@protoc_insertion_point(field_set_char:JSON.RealmList.RealmJoinTicket.gameAccount) +} +inline void RealmJoinTicket::set_gameaccount(const char* value, size_t size) { + set_has_gameaccount(); + if (gameaccount_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + gameaccount_ = new ::std::string; + } + gameaccount_->assign(reinterpret_cast<const char*>(value), size); + // @@protoc_insertion_point(field_set_pointer:JSON.RealmList.RealmJoinTicket.gameAccount) +} +inline ::std::string* RealmJoinTicket::mutable_gameaccount() { + set_has_gameaccount(); + if (gameaccount_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + gameaccount_ = new ::std::string; + } + // @@protoc_insertion_point(field_mutable:JSON.RealmList.RealmJoinTicket.gameAccount) + return gameaccount_; +} +inline ::std::string* RealmJoinTicket::release_gameaccount() { + clear_has_gameaccount(); + if (gameaccount_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + return NULL; + } else { + ::std::string* temp = gameaccount_; + gameaccount_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + return temp; + } +} +inline void RealmJoinTicket::set_allocated_gameaccount(::std::string* gameaccount) { + if (gameaccount_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { + delete gameaccount_; + } + if (gameaccount) { + set_has_gameaccount(); + gameaccount_ = gameaccount; + } else { + clear_has_gameaccount(); + gameaccount_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + } + // @@protoc_insertion_point(field_set_allocated:JSON.RealmList.RealmJoinTicket.gameAccount) +} + +// required fixed32 platform = 2; +inline bool RealmJoinTicket::has_platform() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void RealmJoinTicket::set_has_platform() { + _has_bits_[0] |= 0x00000002u; +} +inline void RealmJoinTicket::clear_has_platform() { + _has_bits_[0] &= ~0x00000002u; +} +inline void RealmJoinTicket::clear_platform() { + platform_ = 0u; + clear_has_platform(); +} +inline ::google::protobuf::uint32 RealmJoinTicket::platform() const { + // @@protoc_insertion_point(field_get:JSON.RealmList.RealmJoinTicket.platform) + return platform_; +} +inline void RealmJoinTicket::set_platform(::google::protobuf::uint32 value) { + set_has_platform(); + platform_ = value; + // @@protoc_insertion_point(field_set:JSON.RealmList.RealmJoinTicket.platform) +} + +// required fixed32 type = 3; +inline bool RealmJoinTicket::has_type() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void RealmJoinTicket::set_has_type() { + _has_bits_[0] |= 0x00000004u; +} +inline void RealmJoinTicket::clear_has_type() { + _has_bits_[0] &= ~0x00000004u; +} +inline void RealmJoinTicket::clear_type() { + type_ = 0u; + clear_has_type(); +} +inline ::google::protobuf::uint32 RealmJoinTicket::type() const { + // @@protoc_insertion_point(field_get:JSON.RealmList.RealmJoinTicket.type) + return type_; +} +inline void RealmJoinTicket::set_type(::google::protobuf::uint32 value) { + set_has_type(); + type_ = value; + // @@protoc_insertion_point(field_set:JSON.RealmList.RealmJoinTicket.type) +} + +// required fixed32 clientArch = 4; +inline bool RealmJoinTicket::has_clientarch() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void RealmJoinTicket::set_has_clientarch() { + _has_bits_[0] |= 0x00000008u; +} +inline void RealmJoinTicket::clear_has_clientarch() { + _has_bits_[0] &= ~0x00000008u; +} +inline void RealmJoinTicket::clear_clientarch() { + clientarch_ = 0u; + clear_has_clientarch(); +} +inline ::google::protobuf::uint32 RealmJoinTicket::clientarch() const { + // @@protoc_insertion_point(field_get:JSON.RealmList.RealmJoinTicket.clientArch) + return clientarch_; +} +inline void RealmJoinTicket::set_clientarch(::google::protobuf::uint32 value) { + set_has_clientarch(); + clientarch_ = value; + // @@protoc_insertion_point(field_set:JSON.RealmList.RealmJoinTicket.clientArch) +} + // @@protoc_insertion_point(namespace_scope) } // namespace RealmList diff --git a/src/server/proto/RealmList/RealmList.proto b/src/server/proto/RealmList/RealmList.proto index aa184d46f8c..7fca92b8413 100644 --- a/src/server/proto/RealmList/RealmList.proto +++ b/src/server/proto/RealmList/RealmList.proto @@ -87,3 +87,10 @@ message RealmIPAddressFamily { message RealmListServerIPAddresses { repeated RealmIPAddressFamily families = 1; } + +message RealmJoinTicket { + required string gameAccount = 1; + required fixed32 platform = 2; + required fixed32 type = 3; + required fixed32 clientArch = 4; +} diff --git a/src/server/shared/Realm/ClientBuildInfo.cpp b/src/server/shared/Realm/ClientBuildInfo.cpp new file mode 100644 index 00000000000..12a4b9ec5a0 --- /dev/null +++ b/src/server/shared/Realm/ClientBuildInfo.cpp @@ -0,0 +1,72 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ClientBuildInfo.h" +#include <algorithm> +#include <cctype> + +std::array<char, 5> ClientBuild::ToCharArray(uint32 value) +{ + auto normalize = [](uint8 c) -> char + { + if (!c || std::isprint(c)) + return char(c); + return ' '; + }; + + std::array<char, 5> chars = { char((value >> 24) & 0xFF), char((value >> 16) & 0xFF), char((value >> 8) & 0xFF), char(value & 0xFF), '\0' }; + + auto firstNonZero = std::ranges::find_if(chars, [](char c) { return c != '\0'; }); + if (firstNonZero != chars.end()) + { + // move leading zeros to end + std::ranges::rotate(chars, firstNonZero); + + // ensure we only have printable characters remaining + std::ranges::transform(chars, chars.begin(), normalize); + } + + return chars; +} + +bool ClientBuild::Platform::IsValid(std::string_view platform) +{ + if (platform.length() > sizeof(uint32)) + return false; + + uint32 platformInt = 0; + for (uint8 c : platform) + { + platformInt <<= 8; + platformInt |= c; + } + + switch (platformInt) + { + case Win_x86: + case Win_x64: + case Win_arm64: + case Mac_x86: + case Mac_x64: + case Mac_arm64: + return true; + default: + break; + } + + return false; +} diff --git a/src/server/shared/Realm/ClientBuildInfo.h b/src/server/shared/Realm/ClientBuildInfo.h new file mode 100644 index 00000000000..e52b585b5b0 --- /dev/null +++ b/src/server/shared/Realm/ClientBuildInfo.h @@ -0,0 +1,110 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITYCORE_CLIENT_BUILD_INFO_H +#define TRINITYCORE_CLIENT_BUILD_INFO_H + +#include "Define.h" +#include <array> +#include <string_view> +#include <vector> + +namespace ClientBuild +{ +consteval uint32 operator""_fourcc(char const* chars, std::size_t length) +{ + if (length > sizeof(uint32)) + throw "Text can only be max 4 characters long"; + + uint32 uintValue = 0; + for (uint8 c : std::string_view(chars, length)) + { + uintValue <<= 8; + uintValue |= c; + } + + return uintValue; +} + +TC_SHARED_API std::array<char, 5> ToCharArray(uint32 value); + +namespace Platform +{ + inline constexpr uint32 Win_x86 = "Win"_fourcc; + inline constexpr uint32 Win_x64 = "Wn64"_fourcc; + inline constexpr uint32 Win_arm64 = "WinA"_fourcc; + inline constexpr uint32 Mac_x86 = "Mac"_fourcc; + inline constexpr uint32 Mac_x64 = "Mc64"_fourcc; + inline constexpr uint32 Mac_arm64 = "MacA"_fourcc; + + TC_SHARED_API bool IsValid(std::string_view platform); +} + +namespace PlatformType +{ + inline constexpr uint32 Windows = "Win"_fourcc; + inline constexpr uint32 macOS = "Mac"_fourcc; +} + +namespace Arch +{ + inline constexpr uint32 x86 = "x86"_fourcc; + inline constexpr uint32 x64 = "x64"_fourcc; + inline constexpr uint32 Arm32 = "A32"_fourcc; + inline constexpr uint32 Arm64 = "A64"_fourcc; + inline constexpr uint32 WA32 = "WA32"_fourcc; +} + +namespace Type +{ + inline constexpr uint32 Retail = "WoW"_fourcc; + inline constexpr uint32 RetailChina = "WoWC"_fourcc; + inline constexpr uint32 Beta = "WoWB"_fourcc; + inline constexpr uint32 BetaRelease = "WoWE"_fourcc; + inline constexpr uint32 Ptr = "WoWT"_fourcc; + inline constexpr uint32 PtrRelease = "WoWR"_fourcc; +} + +struct VariantId +{ + uint32 Platform; + uint32 Arch; + uint32 Type; + + friend bool operator==(VariantId const& left, VariantId const& right) = default; +}; + +struct AuthKey +{ + static constexpr std::size_t Size = 16; + + VariantId Variant; + std::array<uint8, Size> Key; +}; + +struct Info +{ + uint32 Build; + uint32 MajorVersion; + uint32 MinorVersion; + uint32 BugfixVersion; + std::array<char, 4> HotfixVersion; + std::vector<AuthKey> AuthKeys; +}; +} + +#endif // TRINITYCORE_CLIENT_BUILD_INFO_H diff --git a/src/server/shared/Realm/RealmList.cpp b/src/server/shared/Realm/RealmList.cpp index fd1e6e3a165..095640f949b 100644 --- a/src/server/shared/Realm/RealmList.cpp +++ b/src/server/shared/Realm/RealmList.cpp @@ -81,14 +81,17 @@ void RealmList::Close() void RealmList::LoadBuildInfo() { + _builds.clear(); + // 0 1 2 3 4 5 6 if (QueryResult result = LoginDatabase.Query("SELECT majorVersion, minorVersion, bugfixVersion, hotfixVersion, build, win64AuthSeed, mac64AuthSeed, macArmAuthSeed FROM build_info ORDER BY build ASC")) { do { + using namespace ClientBuild; + Field* fields = result->Fetch(); - _builds.emplace_back(); - RealmBuildInfo& build = _builds.back(); + Info& build = _builds.emplace_back(); build.MajorVersion = fields[0].GetUInt32(); build.MinorVersion = fields[1].GetUInt32(); build.BugfixVersion = fields[2].GetUInt32(); @@ -100,22 +103,28 @@ void RealmList::LoadBuildInfo() build.Build = fields[4].GetUInt32(); std::string win64AuthSeedHexStr = fields[5].GetString(); - if (win64AuthSeedHexStr.length() == build.Win64AuthSeed.size() * 2) - HexStrToByteArray(win64AuthSeedHexStr, build.Win64AuthSeed); - else - build.Win64AuthSeed = { }; + if (win64AuthSeedHexStr.length() == AuthKey::Size * 2) + { + AuthKey& buildKey = build.AuthKeys.emplace_back(); + buildKey.Variant = { .Platform = PlatformType::Windows, .Arch = Arch::x64, .Type = Type::Retail }; + HexStrToByteArray(win64AuthSeedHexStr, buildKey.Key); + } std::string mac64AuthSeedHexStr = fields[6].GetString(); - if (mac64AuthSeedHexStr.length() == build.Mac64AuthSeed.size() * 2) - HexStrToByteArray(mac64AuthSeedHexStr, build.Mac64AuthSeed); - else - build.Mac64AuthSeed = { }; + if (mac64AuthSeedHexStr.length() == AuthKey::Size * 2) + { + AuthKey& buildKey = build.AuthKeys.emplace_back(); + buildKey.Variant = { .Platform = PlatformType::macOS, .Arch = Arch::x64, .Type = Type::Retail }; + HexStrToByteArray(mac64AuthSeedHexStr, buildKey.Key); + } std::string macArmAuthSeedHexStr = fields[7].GetString(); - if (macArmAuthSeedHexStr.length() == build.MacArmAuthSeed.size() * 2) - HexStrToByteArray(macArmAuthSeedHexStr, build.MacArmAuthSeed); - else - build.MacArmAuthSeed = { }; + if (macArmAuthSeedHexStr.length() == AuthKey::Size * 2) + { + AuthKey& buildKey = build.AuthKeys.emplace_back(); + buildKey.Variant = { .Platform = PlatformType::macOS, .Arch = Arch::Arm64, .Type = Type::Retail }; + HexStrToByteArray(macArmAuthSeedHexStr, buildKey.Key); + } } while (result->NextRow()); } @@ -260,15 +269,15 @@ std::shared_ptr<Realm const> RealmList::GetCurrentRealm() const return nullptr; } -RealmBuildInfo const* RealmList::GetBuildInfo(uint32 build) const +ClientBuild::Info const* RealmList::GetBuildInfo(uint32 build) const { - auto buildInfo = std::ranges::find(_builds, build, &RealmBuildInfo::Build); + auto buildInfo = std::ranges::find(_builds, build, &ClientBuild::Info::Build); return buildInfo != _builds.end() ? &*buildInfo : nullptr; } uint32 RealmList::GetMinorMajorBugfixVersionForBuild(uint32 build) const { - auto buildInfo = std::ranges::lower_bound(_builds, build, {}, &RealmBuildInfo::Build); + auto buildInfo = std::ranges::lower_bound(_builds, build, {}, &ClientBuild::Info::Build); return buildInfo != _builds.end() ? (buildInfo->MajorVersion * 10000 + buildInfo->MinorVersion * 100 + buildInfo->BugfixVersion) : 0; } @@ -291,7 +300,7 @@ void RealmList::FillRealmEntry(Realm const& realm, uint32 clientBuild, AccountTy realmEntry->set_cfgcategoriesid(realm.Timezone); JSON::RealmList::ClientVersion* version = realmEntry->mutable_version(); - if (RealmBuildInfo const* buildInfo = GetBuildInfo(realm.Build)) + if (ClientBuild::Info const* buildInfo = GetBuildInfo(realm.Build)) { version->set_versionmajor(buildInfo->MajorVersion); version->set_versionminor(buildInfo->MinorVersion); @@ -367,9 +376,9 @@ std::vector<uint8> RealmList::GetRealmList(uint32 build, AccountTypes accountSec return compressed; } -uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip::address const& clientAddress, std::array<uint8, 32> const& clientSecret, - LocaleConstant locale, std::string const& os, Minutes timezoneOffset, std::string const& accountName, AccountTypes accountSecurityLevel, - bgs::protocol::game_utilities::v1::ClientResponse* response) const +uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, ClientBuild::VariantId const& buildVariant, boost::asio::ip::address const& clientAddress, + std::array<uint8, 32> const& clientSecret, LocaleConstant locale, std::string const& os, Minutes timezoneOffset, std::string const& accountName, + AccountTypes accountSecurityLevel, bgs::protocol::game_utilities::v1::ClientResponse* response) const { if (std::shared_ptr<Realm const> realm = GetRealm(realmAddress)) { @@ -407,9 +416,15 @@ uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip:: stmt->setString(6, accountName); LoginDatabase.DirectExecute(stmt); + JSON::RealmList::RealmJoinTicket joinTicket; + joinTicket.set_gameaccount(accountName); + joinTicket.set_platform(buildVariant.Platform); + joinTicket.set_clientarch(buildVariant.Arch); + joinTicket.set_type(buildVariant.Type); + bgs::protocol::Attribute* attribute = response->add_attribute(); attribute->set_name("Param_RealmJoinTicket"); - attribute->mutable_value()->set_blob_value(accountName); + attribute->mutable_value()->set_blob_value(JSON::Serialize(joinTicket)); attribute = response->add_attribute(); attribute->set_name("Param_ServerAddresses"); diff --git a/src/server/shared/Realm/RealmList.h b/src/server/shared/Realm/RealmList.h index b61ad502877..ac408feada2 100644 --- a/src/server/shared/Realm/RealmList.h +++ b/src/server/shared/Realm/RealmList.h @@ -18,6 +18,7 @@ #ifndef _REALMLIST_H #define _REALMLIST_H +#include "ClientBuildInfo.h" #include "Define.h" #include "Duration.h" #include "Optional.h" @@ -29,18 +30,6 @@ #include <unordered_set> #include <vector> -struct RealmBuildInfo -{ - uint32 Build; - uint32 MajorVersion; - uint32 MinorVersion; - uint32 BugfixVersion; - std::array<char, 4> HotfixVersion; - std::array<uint8, 16> Win64AuthSeed; - std::array<uint8, 16> Mac64AuthSeed; - std::array<uint8, 16> MacArmAuthSeed; -}; - namespace bgs::protocol::game_utilities::v1 { class ClientResponse; @@ -68,6 +57,7 @@ public: ~RealmList(); void Initialize(Trinity::Asio::IoContext& ioContext, uint32 updateInterval); + void LoadBuildInfo(); void Close(); std::shared_ptr<Realm const> GetRealm(Battlenet::RealmHandle const& id) const; @@ -75,26 +65,25 @@ public: void SetCurrentRealmId(Battlenet::RealmHandle const& id); std::shared_ptr<Realm const> GetCurrentRealm() const; - RealmBuildInfo const* GetBuildInfo(uint32 build) const; + ClientBuild::Info const* GetBuildInfo(uint32 build) const; uint32 GetMinorMajorBugfixVersionForBuild(uint32 build) const; void WriteSubRegions(bgs::protocol::game_utilities::v1::GetAllValuesForAttributeResponse* response) const; std::vector<uint8> GetRealmEntryJSON(Battlenet::RealmHandle const& id, uint32 build, AccountTypes accountSecurityLevel) const; std::vector<uint8> GetRealmList(uint32 build, AccountTypes accountSecurityLevel, std::string const& subRegion) const; - uint32 JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip::address const& clientAddress, std::array<uint8, 32> const& clientSecret, - LocaleConstant locale, std::string const& os, Minutes timezoneOffset, std::string const& accountName, AccountTypes accountSecurityLevel, - bgs::protocol::game_utilities::v1::ClientResponse* response) const; + uint32 JoinRealm(uint32 realmAddress, uint32 build, ClientBuild::VariantId const& buildVariant, boost::asio::ip::address const& clientAddress, + std::array<uint8, 32> const& clientSecret, LocaleConstant locale, std::string const& os, Minutes timezoneOffset, std::string const& accountName, + AccountTypes accountSecurityLevel, bgs::protocol::game_utilities::v1::ClientResponse* response) const; private: RealmList(); - void LoadBuildInfo(); void UpdateRealms(); static void UpdateRealm(Realm& realm, Battlenet::RealmHandle const& id, uint32 build, std::string const& name, boost::asio::ip::address&& address, boost::asio::ip::address&& localAddr, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, RealmPopulationState population); void FillRealmEntry(Realm const& realm, uint32 clientBuild, AccountTypes accountSecurityLevel, JSON::RealmList::RealmEntry* realmEntry) const; - std::vector<RealmBuildInfo> _builds; + std::vector<ClientBuild::Info> _builds; mutable std::shared_mutex _realmsMutex; RealmMap _realms; std::map<Battlenet::RealmHandle, std::string> _removedRealms; |