Skip to content

Commit

Permalink
Core/Client Builds: Sync build_info structure with master branch
Browse files Browse the repository at this point in the history
  • Loading branch information
Shauren committed Aug 30, 2024
1 parent 02ac890 commit 0b10514
Show file tree
Hide file tree
Showing 10 changed files with 872 additions and 166 deletions.
684 changes: 594 additions & 90 deletions sql/base/auth_database.sql

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions sql/updates/auth/3.3.5/2024_08_28_01_auth.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ALTER TABLE `build_info` ADD `macArmAuthSeed` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL AFTER `mac64AuthSeed`;

UPDATE `build_info` SET `macArmAuthSeed`='778F6A5DF79A4EF1B86F651F3B303CE7' WHERE `build`=56196;
UPDATE `build_info` SET `macArmAuthSeed`='41710C793EF021721F14B06EC1896D3F' WHERE `build`=56288;
UPDATE `build_info` SET `macArmAuthSeed`='412D3200715AAFDC0522DF031A941F0E' WHERE `build`=56311;
UPDATE `build_info` SET `macArmAuthSeed`='A83ED19EE659BC95CC322D1E49BDEDBB' WHERE `build`=56313;
39 changes: 39 additions & 0 deletions sql/updates/auth/3.3.5/2024_08_30_00_auth.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
--
-- Table structure for table `build_auth_key`
--
DROP TABLE IF EXISTS `build_auth_key`;
CREATE TABLE `build_auth_key` (
`build` int NOT NULL,
`platform` char(4) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`arch` char(4) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`type` char(4) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`key` binary(16) NOT NULL,
PRIMARY KEY (`build`,`platform`,`arch`,`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

--
-- Table structure for table `build_executable_hash`
--
DROP TABLE IF EXISTS `build_executable_hash`;
CREATE TABLE `build_executable_hash` (
`build` int NOT NULL,
`platform` char(4) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`executableHash` binary(20) NOT NULL,
PRIMARY KEY (`build`,`platform`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `build_auth_key` SELECT `build`,'Win','x86','WoW',UNHEX(`winAuthSeed`) FROM `build_info` WHERE LENGTH(`winAuthSeed`)=32;
INSERT INTO `build_auth_key` SELECT `build`,'Win','x64','WoW',UNHEX(`win64AuthSeed`) FROM `build_info` WHERE LENGTH(`win64AuthSeed`)=32;
INSERT INTO `build_auth_key` SELECT `build`,'Mac','x64','WoW',UNHEX(`mac64AuthSeed`) FROM `build_info` WHERE LENGTH(`mac64AuthSeed`)=32;
INSERT INTO `build_auth_key` SELECT `build`,'Mac','A64','WoW',UNHEX(`macArmAuthSeed`) FROM `build_info` WHERE LENGTH(`macArmAuthSeed`)=32;

INSERT INTO `build_executable_hash` SELECT `build`,'Win',UNHEX(`winChecksumSeed`) FROM `build_info` WHERE LENGTH(`winChecksumSeed`)=40;
INSERT INTO `build_executable_hash` SELECT `build`,'OSX',UNHEX(`macChecksumSeed`) FROM `build_info` WHERE LENGTH(`macChecksumSeed`)=40;

ALTER TABLE `build_info`
DROP `winAuthSeed`,
DROP `win64AuthSeed`,
DROP `mac64AuthSeed`,
DROP `macArmAuthSeed`,
DROP `winChecksumSeed`,
DROP `macChecksumSeed`;
8 changes: 4 additions & 4 deletions src/server/authserver/Authentication/AuthCodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,24 @@
*/

#include "AuthCodes.h"
#include "RealmList.h"
#include "ClientBuildInfo.h"

namespace AuthHelper
{
constexpr static uint32 MAX_PRE_BC_CLIENT_BUILD = 6141;

bool IsPreBCAcceptedClientBuild(uint32 build)
{
return build <= MAX_PRE_BC_CLIENT_BUILD && sRealmList->GetBuildInfo(build);
return build <= MAX_PRE_BC_CLIENT_BUILD && ClientBuild::GetBuildInfo(build);
}

bool IsPostBCAcceptedClientBuild(uint32 build)
{
return build > MAX_PRE_BC_CLIENT_BUILD && sRealmList->GetBuildInfo(build);
return build > MAX_PRE_BC_CLIENT_BUILD && ClientBuild::GetBuildInfo(build);
}

bool IsAcceptedClientBuild(uint32 build)
{
return sRealmList->GetBuildInfo(build) != nullptr;
return ClientBuild::GetBuildInfo(build) != nullptr;
}
}
18 changes: 7 additions & 11 deletions src/server/authserver/Server/AuthSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "AES.h"
#include "AuthCodes.h"
#include "ByteBuffer.h"
#include "ClientBuildInfo.h"
#include "Config.h"
#include "CryptoGenerics.h"
#include "CryptoHash.h"
Expand Down Expand Up @@ -756,7 +757,7 @@ void AuthSession::RealmListCallback(PreparedQueryResult result)

// No SQL injection. id of realm is controlled by the database.
uint32 flag = realm.Flags;
RealmBuildInfo const* buildInfo = sRealmList->GetBuildInfo(realm.Build);
ClientBuild::Info const* buildInfo = ClientBuild::GetBuildInfo(realm.Build);
if (!okBuild)
{
if (!buildInfo)
Expand Down Expand Up @@ -841,20 +842,15 @@ bool AuthSession::VerifyVersion(uint8 const* a, int32 aLength, Trinity::Crypto::
Trinity::Crypto::SHA1::Digest const* versionHash = nullptr;
if (!isReconnect)
{
RealmBuildInfo const* buildInfo = sRealmList->GetBuildInfo(_build);
ClientBuild::Info const* buildInfo = ClientBuild::GetBuildInfo(_build);
if (!buildInfo)
return false;

if (_os == "Win")
versionHash = &buildInfo->WindowsHash;
else if (_os == "OSX")
versionHash = &buildInfo->MacHash;

if (!versionHash)
return false;

if (zeros == *versionHash)
auto platformItr = std::ranges::find(buildInfo->ExecutableHashes, ClientBuild::ToFourCC(_os), &ClientBuild::ExecutableHash::Platform);
if (platformItr == buildInfo->ExecutableHashes.end())
return true; // not filled serverside

versionHash = &platformItr->Hash;
}
else
versionHash = &zeros;
Expand Down
3 changes: 2 additions & 1 deletion src/server/game/Server/WorldSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "WorldSocket.h"
#include "BigNumber.h"
#include "ClientBuildInfo.h"
#include "DatabaseEnv.h"
#include "GameTime.h"
#include "CryptoHash.h"
Expand Down Expand Up @@ -506,7 +507,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes

// Must be done before WorldSession is created
bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
if (wardenActive && account.OS != "Win" && account.OS != "OSX")
if (wardenActive && !ClientBuild::Platform::IsValid(account.OS))
{
SendAuthResponseError(AUTH_REJECT);
TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} attempted to log in using invalid client OS ({}).", address, account.OS);
Expand Down
139 changes: 139 additions & 0 deletions src/server/shared/Realm/ClientBuildInfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* 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 "DatabaseEnv.h"
#include "Log.h"
#include "Util.h"
#include <algorithm>
#include <cctype>

namespace
{
std::vector<ClientBuild::Info> Builds;
}

namespace ClientBuild
{
std::array<char, 5> 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::rotate(chars.begin(), firstNonZero, chars.end());

// ensure we only have printable characters remaining
std::ranges::transform(chars, chars.begin(), normalize);
}

return chars;
}

bool Platform::IsValid(std::string_view platform)
{
if (platform.length() > sizeof(uint32))
return false;

switch (ToFourCC(platform))
{
case Win_x86:
case Mac_x86:
return true;
default:
break;
}

return false;
}

void LoadBuildInfo()
{
Builds.clear();

// 0 1 2 3 4
if (QueryResult result = LoginDatabase.Query("SELECT majorVersion, minorVersion, bugfixVersion, hotfixVersion, build FROM build_info ORDER BY build ASC"))
{
do
{
Field* fields = result->Fetch();
Info& build = Builds.emplace_back();
build.MajorVersion = fields[0].GetUInt32();
build.MinorVersion = fields[1].GetUInt32();
build.BugfixVersion = fields[2].GetUInt32();
std::string hotfixVersion = fields[3].GetString();
if (hotfixVersion.length() < build.HotfixVersion.size())
std::ranges::copy(hotfixVersion, build.HotfixVersion.begin());
else
build.HotfixVersion = { };

build.Build = fields[4].GetUInt32();

} while (result->NextRow());
}

// 0 1 2
if (QueryResult result = LoginDatabase.Query("SELECT `build`, `platform`, `executableHash` FROM `build_executable_hash`"))
{
do
{
Field* fields = result->Fetch();

uint32 build = fields[0].GetInt32();
auto buildInfo = std::ranges::find(Builds, build, &Info::Build);
if (buildInfo == Builds.end())
{
TC_LOG_ERROR("sql.sql", "ClientBuild::LoadBuildInfo: Unknown `build` {} in `build_executable_hash` - missing from `build_info`, skipped.", build);
continue;
}

std::string_view platform = fields[1].GetStringView();
if (!Platform::IsValid(platform))
{
TC_LOG_ERROR("sql.sql", "ClientBuild::LoadBuildInfo: Invalid platform {} for `build` {} in `build_executable_hash`, skipped.", platform, build);
continue;
}

ExecutableHash& buildKey = buildInfo->ExecutableHashes.emplace_back();
buildKey.Platform = ToFourCC(platform);
buildKey.Hash = fields[2].GetBinary<ExecutableHash::Size>();

} while (result->NextRow());
}
}

Info const* GetBuildInfo(uint32 build)
{
auto buildInfo = std::ranges::find(Builds, build, &Info::Build);
return buildInfo != Builds.end() ? &*buildInfo : nullptr;
}

uint32 GetMinorMajorBugfixVersionForBuild(uint32 build)
{
auto buildInfo = std::ranges::lower_bound(Builds, build, {}, &Info::Build);
return buildInfo != Builds.end() ? (buildInfo->MajorVersion * 10000 + buildInfo->MinorVersion * 100 + buildInfo->BugfixVersion) : 0;
}
}
79 changes: 79 additions & 0 deletions src/server/shared/Realm/ClientBuildInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* 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
{
inline constexpr uint32 ToFourCC(std::string_view text)
{
uint32 uintValue = 0;
for (uint8 c : text)
{
uintValue <<= 8;
uintValue |= c;
}
return uintValue;
}

consteval uint32 operator""_fourcc(char const* chars, std::size_t length)
{
if (length > sizeof(uint32))
throw "Text can only be max 4 characters long";

return ToFourCC({ chars, length });
}

TC_SHARED_API std::array<char, 5> ToCharArray(uint32 value);

namespace Platform
{
inline constexpr uint32 Win_x86 = "Win"_fourcc;
inline constexpr uint32 Mac_x86 = "OSX"_fourcc;

TC_SHARED_API bool IsValid(std::string_view platform);
}

struct ExecutableHash
{
static constexpr std::size_t Size = 20;

uint32 Platform;
std::array<uint8, Size> Hash;
};

struct Info
{
uint32 Build;
uint32 MajorVersion;
uint32 MinorVersion;
uint32 BugfixVersion;
std::array<char, 4> HotfixVersion;
std::vector<ExecutableHash> ExecutableHashes;
};

TC_SHARED_API void LoadBuildInfo();
TC_SHARED_API Info const* GetBuildInfo(uint32 build);
}

#endif // TRINITYCORE_CLIENT_BUILD_INFO_H
Loading

0 comments on commit 0b10514

Please sign in to comment.