From 46cf03eb7bd2957ee115607d09fcfea4ddffe6f5 Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Thu, 1 Aug 2019 01:09:16 +0200 Subject: [PATCH] Core/Addons: Improve WorldSession::ReadAddonsInfo (ported commits: cd3d317ebf74c4bd2b9a806e4463e2d0ae730a3b 01124c6f4e6d0e6cebbaa3741634a4d662992a9b and 86b516c3f27f155f267245fc27ae634a76bb1e2f --- sql/base/characters_database.sql | 36 +++++ .../4.3.4/custom_2019_08_01_00_characters.sql | 37 +++++ src/server/game/Addons/AddonMgr.cpp | 10 +- src/server/game/Addons/AddonMgr.h | 19 +-- src/server/game/Server/WorldSession.cpp | 126 ++++++++++-------- src/server/game/Server/WorldSession.h | 24 +++- 6 files changed, 175 insertions(+), 77 deletions(-) create mode 100644 sql/updates/characters/4.3.4/custom_2019_08_01_00_characters.sql diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 1d972722271..b6d3e75fd20 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -114,6 +114,42 @@ CREATE TABLE `addons` ( LOCK TABLES `addons` WRITE; /*!40000 ALTER TABLE `addons` DISABLE KEYS */; +INSERT INTO `addons` VALUES +('Blizzard_AchievementUI', 1276933997), +('Blizzard_ArchaeologyUI', 1276933997), +('Blizzard_ArenaUI', 1276933997), +('Blizzard_AuctionUI', 1276933997), +('Blizzard_BarbershopUI', 1276933997), +('Blizzard_BattlefieldMinimap', 1276933997), +('Blizzard_BindingUI', 1276933997), +('Blizzard_Calendar', 1276933997), +('Blizzard_ClientSavedVariables', 1276933997), +('Blizzard_CombatLog', 1276933997), +('Blizzard_CombatText', 1276933997), +('Blizzard_CompactRaidFrames', 1276933997), +('Blizzard_CUFProfiles', 1276933997), +('Blizzard_DebugTools', 1276933997), +('Blizzard_EncounterJournal', 1276933997), +('Blizzard_GlyphUI', 1276933997), +('Blizzard_GMChatUI', 1276933997), +('Blizzard_GMSurveyUI', 1276933997), +('Blizzard_GuildBankUI', 1276933997), +('Blizzard_GuildControlUI', 1276933997), +('Blizzard_GuildUI', 1276933997), +('Blizzard_InspectUI', 1276933997), +('Blizzard_ItemAlterationUI', 1276933997), +('Blizzard_ItemSocketingUI', 1276933997), +('Blizzard_LookingForGuildUI', 1276933997), +('Blizzard_MacroUI', 1276933997), +('Blizzard_MovePad', 1276933997), +('Blizzard_RaidUI', 1276933997), +('Blizzard_ReforgingUI', 1276933997), +('Blizzard_TalentUI', 1276933997), +('Blizzard_TimeManager', 1276933997), +('Blizzard_TokenUI', 1276933997), +('Blizzard_TradeSkillUI', 1276933997), +('Blizzard_TrainerUI', 1276933997), +('Blizzard_VoidStorageUI', 1276933997); /*!40000 ALTER TABLE `addons` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/characters/4.3.4/custom_2019_08_01_00_characters.sql b/sql/updates/characters/4.3.4/custom_2019_08_01_00_characters.sql new file mode 100644 index 00000000000..16bce80a6f1 --- /dev/null +++ b/sql/updates/characters/4.3.4/custom_2019_08_01_00_characters.sql @@ -0,0 +1,37 @@ +TRUNCATE `addons`; +INSERT INTO `addons` VALUES +('Blizzard_AchievementUI', 1276933997), +('Blizzard_ArchaeologyUI', 1276933997), +('Blizzard_ArenaUI', 1276933997), +('Blizzard_AuctionUI', 1276933997), +('Blizzard_BarbershopUI', 1276933997), +('Blizzard_BattlefieldMinimap', 1276933997), +('Blizzard_BindingUI', 1276933997), +('Blizzard_Calendar', 1276933997), +('Blizzard_ClientSavedVariables', 1276933997), +('Blizzard_CombatLog', 1276933997), +('Blizzard_CombatText', 1276933997), +('Blizzard_CompactRaidFrames', 1276933997), +('Blizzard_CUFProfiles', 1276933997), +('Blizzard_DebugTools', 1276933997), +('Blizzard_EncounterJournal', 1276933997), +('Blizzard_GlyphUI', 1276933997), +('Blizzard_GMChatUI', 1276933997), +('Blizzard_GMSurveyUI', 1276933997), +('Blizzard_GuildBankUI', 1276933997), +('Blizzard_GuildControlUI', 1276933997), +('Blizzard_GuildUI', 1276933997), +('Blizzard_InspectUI', 1276933997), +('Blizzard_ItemAlterationUI', 1276933997), +('Blizzard_ItemSocketingUI', 1276933997), +('Blizzard_LookingForGuildUI', 1276933997), +('Blizzard_MacroUI', 1276933997), +('Blizzard_MovePad', 1276933997), +('Blizzard_RaidUI', 1276933997), +('Blizzard_ReforgingUI', 1276933997), +('Blizzard_TalentUI', 1276933997), +('Blizzard_TimeManager', 1276933997), +('Blizzard_TokenUI', 1276933997), +('Blizzard_TradeSkillUI', 1276933997), +('Blizzard_TrainerUI', 1276933997), +('Blizzard_VoidStorageUI', 1276933997); diff --git a/src/server/game/Addons/AddonMgr.cpp b/src/server/game/Addons/AddonMgr.cpp index 90eb4fa67df..3d70afdf460 100644 --- a/src/server/game/Addons/AddonMgr.cpp +++ b/src/server/game/Addons/AddonMgr.cpp @@ -66,7 +66,7 @@ void LoadFromDB() TC_LOG_INFO("server.loading", ">> Loaded 0 known addons. DB table `addons` is empty!"); oldMSTime = getMSTime(); - result = CharacterDatabase.Query("SELECT id, name, version, UNIX_TIMESTAMP(timestamp) FROM banned_addons"); + result = CharacterDatabase.Query("SELECT id, name, version, UNIX_TIMESTAMP(timestamp) FROM banned_addons ORDER BY timestamp"); if (result) { uint32 count = 0; @@ -96,18 +96,16 @@ void LoadFromDB() } } -void SaveAddon(AddonInfo const& addon) +void SaveAddon(std::string const& name, uint32 publicKeyCrc) { - std::string name = addon.Name; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ADDON); stmt->setString(0, name); - stmt->setUInt32(1, addon.CRC); + stmt->setUInt32(1, publicKeyCrc); CharacterDatabase.Execute(stmt); - m_knownAddons.push_back(SavedAddon(addon.Name, addon.CRC)); + m_knownAddons.emplace_back(name, publicKeyCrc); } SavedAddon const* GetAddonInfo(const std::string& name) diff --git a/src/server/game/Addons/AddonMgr.h b/src/server/game/Addons/AddonMgr.h index dd8b960a480..93d5bb641d5 100644 --- a/src/server/game/Addons/AddonMgr.h +++ b/src/server/game/Addons/AddonMgr.h @@ -21,20 +21,7 @@ #include "Define.h" #include -#include - -struct AddonInfo -{ - AddonInfo(const std::string& name, uint8 enabled, uint32 crc, uint8 state, bool crcOrPubKey) - : Name(name), Enabled(enabled), CRC(crc), State(state), UsePublicKeyOrCRC(crcOrPubKey) - { } - - std::string Name; - uint8 Enabled; - uint32 CRC; - uint8 State; - bool UsePublicKeyOrCRC; -}; +#include struct SavedAddon { @@ -60,10 +47,10 @@ struct BannedAddon namespace AddonMgr { void LoadFromDB(); - void SaveAddon(AddonInfo const& addon); + void SaveAddon(std::string const& name, uint32 publicKeyCrc); SavedAddon const* GetAddonInfo(const std::string& name); - typedef std::list BannedAddonList; + typedef std::vector BannedAddonList; BannedAddonList const* GetBannedAddons(); } diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 4bbc1658ea6..96ddee8af69 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -886,48 +886,60 @@ void WorldSession::ReadAddonsInfo(ByteBuffer &data) if (uncompress(addonInfo.contents(), &uSize, data.contents() + pos, data.size() - pos) == Z_OK) { - uint32 addonsCount; - addonInfo >> addonsCount; // addons count - - for (uint32 i = 0; i < addonsCount; ++i) + try { - std::string addonName; - uint8 enabled; - uint32 crc, unk1; + uint32 addonsCount = addonInfo.read(); + if (addonsCount > Addons::MaxSecureAddons) + addonsCount = Addons::MaxSecureAddons; - // check next addon data format correctness - if (addonInfo.rpos() + 1 > addonInfo.size()) - return; + _addons.SecureAddons.resize(addonsCount); - addonInfo >> addonName; - - addonInfo >> enabled >> crc >> unk1; - - TC_LOG_DEBUG("addon", "AddOn: %s (CRC: 0x%x) - enabled: 0x%x - Unknown2: 0x%x", addonName.c_str(), crc, enabled, unk1); - - AddonInfo addon(addonName, enabled, crc, 2, true); - - SavedAddon const* savedAddon = AddonMgr::GetAddonInfo(addonName); - if (savedAddon) + for (uint32 i = 0; i < addonsCount; ++i) { - if (addon.CRC != savedAddon->CRC) - TC_LOG_WARN("addon", " Addon: %s: modified (CRC: 0x%x) - accountID %d)", addon.Name.c_str(), savedAddon->CRC, GetAccountId()); + Addons::SecureAddonInfo& addon = _addons.SecureAddons[i]; + uint32 publicKeyCrc, urlCrc; + + addonInfo >> addon.Name >> addon.HasKey; + addonInfo >> publicKeyCrc >> urlCrc; + + TC_LOG_DEBUG("addon", "AddOn: %s (CRC: 0x%x) - has key: 0x%x - URL CRC: 0x%x", addon.Name.c_str(), publicKeyCrc, addon.HasKey, urlCrc); + + SavedAddon const* savedAddon = AddonMgr::GetAddonInfo(addon.Name); + if (savedAddon) + { + if (publicKeyCrc != savedAddon->CRC) + { + if (addon.HasKey) + { + addon.Status = Addons::SecureAddonInfo::BANNED; + TC_LOG_WARN("addon", " Addon: %s: modified (CRC: 0x%x) - accountID %d)", addon.Name.c_str(), savedAddon->CRC, GetAccountId()); + } + else + addon.Status = Addons::SecureAddonInfo::SECURE_HIDDEN; + } + else + { + addon.Status = Addons::SecureAddonInfo::SECURE_HIDDEN; + TC_LOG_DEBUG("addon", "Addon: %s: validated (CRC: 0x%x) - accountID %d", addon.Name.c_str(), savedAddon->CRC, GetAccountId()); + } + } else - TC_LOG_DEBUG("addon", "Addon: %s: validated (CRC: 0x%x) - accountID %d", addon.Name.c_str(), savedAddon->CRC, GetAccountId()); - } - else - { - AddonMgr::SaveAddon(addon); - TC_LOG_WARN("addon", "Addon: %s: unknown (CRC: 0x%x) - accountId %d (storing addon name and checksum to database)", addon.Name.c_str(), addon.CRC, GetAccountId()); + { + addon.Status = Addons::SecureAddonInfo::BANNED; + TC_LOG_WARN("addon", "Addon: %s: not registered as known secure addon - accountId %d", addon.Name.c_str(), GetAccountId()); + } } - /// @todo Find out when to not use CRC/pubkey, and other possible states. - m_addonsList.push_back(addon); + addonInfo.rpos(addonInfo.size() - 4); + + uint32 lastBannedAddOnTimestamp; + addonInfo >> lastBannedAddOnTimestamp; + TC_LOG_DEBUG("addon", "AddOn: Newest banned addon timestamp: %u", lastBannedAddOnTimestamp); + } + catch (ByteBufferException const& e) + { + TC_LOG_DEBUG("addon", "AddOn: Addon packet read error! %s", e.what()); } - - uint32 currentTime; - addonInfo >> currentTime; - TC_LOG_DEBUG("addon", "AddOn: CurrentTime: %u", currentTime); } else TC_LOG_DEBUG("addon", "AddOn: Addon packet uncompress error!"); @@ -935,7 +947,7 @@ void WorldSession::ReadAddonsInfo(ByteBuffer &data) void WorldSession::SendAddonsInfo() { - uint8 addonPublicKey[256] = + uint8 constexpr addonPublicKey[256] = { 0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54, 0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75, @@ -957,37 +969,45 @@ void WorldSession::SendAddonsInfo() WorldPacket data(SMSG_ADDON_INFO, 4); - for (AddonsList::iterator itr = m_addonsList.begin(); itr != m_addonsList.end(); ++itr) + for (Addons::SecureAddonInfo const& addonInfo : _addons.SecureAddons) { - data << uint8(itr->State); + // fresh install, not yet created Interface\Addons\addon_name\addon_name.pub files + uint8 infoProvided = addonInfo.Status != Addons::SecureAddonInfo::BANNED || addonInfo.HasKey; - uint8 crcpub = itr->UsePublicKeyOrCRC; - data << uint8(crcpub); - if (crcpub) + data << uint8(addonInfo.Status); // Status + data << uint8(infoProvided); // InfoProvided + if (infoProvided) { - uint8 usepk = (itr->CRC != STANDARD_ADDON_CRC); // If addon is Standard addon CRC - data << uint8(usepk); - if (usepk) // if CRC is wrong, add public key (client need it) + data << uint8(!addonInfo.HasKey); // KeyProvided + if (!addonInfo.HasKey) // if CRC is wrong, add public key (client need it) { - TC_LOG_DEBUG("addon", "AddOn: %s: CRC checksum mismatch: got 0x%x - expected 0x%x - sending pubkey to accountID %d", - itr->Name.c_str(), itr->CRC, STANDARD_ADDON_CRC, GetAccountId()); + TC_LOG_DEBUG("addon", "AddOn: %s: key missing: sending pubkey to accountID %d", addonInfo.Name.c_str(), GetAccountId()); data.append(addonPublicKey, sizeof(addonPublicKey)); } - data << uint32(0); /// @todo Find out the meaning of this. + data << uint32(0); // Revision (from .toc), can be used by SECURE_VISIBLE to display "update available" in client addon controls } - data << uint8(0); // uses URL + data << uint8(0); // UrlProvided //if (usesURL) - // data << uint8(0); // URL + // data << uint8(0); // URL, client will create internet shortcut with this destination in Interface\Addons\addon_name\addon_name.url } - m_addonsList.clear(); - + // Send new uncached banned addons AddonMgr::BannedAddonList const* bannedAddons = AddonMgr::GetBannedAddons(); - data << uint32(bannedAddons->size()); - for (AddonMgr::BannedAddonList::const_iterator itr = bannedAddons->begin(); itr != bannedAddons->end(); ++itr) + uint32 lastBannedAddOnTimestamp = _addons.LastBannedAddOnTimestamp; + if (!bannedAddons->empty() && bannedAddons->back().Timestamp < lastBannedAddOnTimestamp) // cheating attempt OR connecting to a realm with different configured banned addons, send everything + lastBannedAddOnTimestamp = 0; + + std::size_t sizePos = data.wpos(); + uint32 bannedAddonCount = 0; + data << uint32(0); + auto itr = std::lower_bound(bannedAddons->begin(), bannedAddons->end(), _addons.LastBannedAddOnTimestamp, [](BannedAddon const& bannedAddon, uint32 timestamp) + { + return bannedAddon.Timestamp < timestamp; + }); + for (; itr != bannedAddons->end(); ++itr) { data << uint32(itr->Id); data.append(itr->NameMD5, sizeof(itr->NameMD5)); @@ -996,6 +1016,8 @@ void WorldSession::SendAddonsInfo() data << uint32(1); // IsBanned } + data.put(sizePos, bannedAddonCount); + SendPacket(&data); } diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index ee4b152865f..ae8acedb5d6 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -1179,8 +1179,6 @@ class TC_GAME_API WorldSession uint32 _battlenetAccountId; uint8 m_expansion; - typedef std::list AddonsList; - // Warden Warden* _warden; // Remains nullptr if Warden system is not enabled by config @@ -1196,7 +1194,27 @@ class TC_GAME_API WorldSession AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES]; uint32 m_Tutorials[MAX_ACCOUNT_TUTORIAL_VALUES]; uint8 m_TutorialsChanged; - AddonsList m_addonsList; + struct Addons + { + struct SecureAddonInfo + { + enum SecureAddonStatus : uint8 + { + BANNED = 0, + SECURE_VISIBLE = 1, + SECURE_HIDDEN = 2 + }; + + std::string Name; + SecureAddonStatus Status = BANNED; + bool HasKey = false; + }; + + static uint32 constexpr MaxSecureAddons = 35; + + std::vector SecureAddons; + uint32 LastBannedAddOnTimestamp = 0; + } _addons; std::vector _registeredAddonPrefixes; bool _filterAddonMessages; uint32 recruiterId;