diff options
author | Shauren <shauren.trinity@gmail.com> | 2024-08-29 15:08:47 +0200 |
---|---|---|
committer | Ovahlord <dreadkiller@gmx.de> | 2024-08-30 17:35:01 +0200 |
commit | 2b8c5ad42dc886a7246b18af99c4966e9f1aba0e (patch) | |
tree | 4b3ef359bfa8bbe192984bc2b555eca338febf69 /src/server/shared | |
parent | cf86c057383bd038cbdfd292e0ca98c7e6211d5c (diff) |
Core/Auth: Refactor client auth key storage to support more future client variants and preserve more information about client version
(cherry picked from commit 8e1595265925e0840d07e943b8c9ff1e906d4719)
Diffstat (limited to 'src/server/shared')
-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 |
4 files changed, 226 insertions, 40 deletions
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; |