aboutsummaryrefslogtreecommitdiff
path: root/src/server/shared
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2024-08-29 15:08:47 +0200
committerOvahlord <dreadkiller@gmx.de>2024-08-30 17:35:01 +0200
commit2b8c5ad42dc886a7246b18af99c4966e9f1aba0e (patch)
tree4b3ef359bfa8bbe192984bc2b555eca338febf69 /src/server/shared
parentcf86c057383bd038cbdfd292e0ca98c7e6211d5c (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.cpp72
-rw-r--r--src/server/shared/Realm/ClientBuildInfo.h110
-rw-r--r--src/server/shared/Realm/RealmList.cpp59
-rw-r--r--src/server/shared/Realm/RealmList.h25
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;