diff options
| author | Shauren <shauren.trinity@gmail.com> | 2015-08-30 00:17:08 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2015-08-30 00:17:08 +0200 |
| commit | b564c10b13effed63c7b7dae25117e2e0a2c64e4 (patch) | |
| tree | ea79cf0c9b254aac517f1024602b39615eedb010 /src/server/game | |
| parent | b0107802064a19d69ce06f7bcf8b8394695e6faf (diff) | |
Core/Players: Implemented serverside validation of reserved/profane names
Closes #15357
New library dependency: Boost.Regex
Diffstat (limited to 'src/server/game')
| -rw-r--r-- | src/server/game/DataStores/DB2Stores.cpp | 41 | ||||
| -rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 4 | ||||
| -rw-r--r-- | src/server/game/DataStores/DB2Structure.h | 20 | ||||
| -rw-r--r-- | src/server/game/DataStores/DB2fmt.h | 3 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 4 | ||||
| -rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 2 | ||||
| -rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 8 | ||||
| -rw-r--r-- | src/server/game/Tools/PlayerDump.cpp | 2 |
9 files changed, 77 insertions, 9 deletions
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 88ed3989efa..66321a1c6b1 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -82,6 +82,9 @@ DB2Storage<MountCapabilityEntry> sMountCapabilityStore("MountCapa DB2Storage<MountEntry> sMountStore("Mount.db2", MountFormat, HOTFIX_SEL_MOUNT); DB2Storage<MountTypeXCapabilityEntry> sMountTypeXCapabilityStore("MountTypeXCapability.db2", MountTypeXCapabilityFormat, HOTFIX_SEL_MOUNT_TYPE_X_CAPABILITY); DB2Storage<NameGenEntry> sNameGenStore("NameGen.db2", NameGenFormat, HOTFIX_SEL_NAME_GEN); +DB2Storage<NamesProfanityEntry> sNamesProfanityStore("NamesProfanity.db2", NamesProfanityFormat, HOTFIX_SEL_NAMES_PROFANITY); +DB2Storage<NamesReservedEntry> sNamesReservedStore("NamesReserved.db2", NamesReservedFormat, HOTFIX_SEL_NAMES_RESERVED); +DB2Storage<NamesReservedLocaleEntry> sNamesReservedLocaleStore("NamesReservedLocale.db2", NamesReservedLocaleFormat, HOTFIX_SEL_NAMES_RESERVED_LOCALE); DB2Storage<OverrideSpellDataEntry> sOverrideSpellDataStore("OverrideSpellData.db2", OverrideSpellDataFormat, HOTFIX_SEL_OVERRIDE_SPELL_DATA); DB2Storage<PhaseXPhaseGroupEntry> sPhaseXPhaseGroupStore("PhaseXPhaseGroup.db2", PhaseXPhaseGroupFormat, HOTFIX_SEL_PHASE_X_PHASE_GROUP); DB2Storage<QuestMoneyRewardEntry> sQuestMoneyRewardStore("QuestMoneyReward.db2", QuestMoneyRewardFormat, HOTFIX_SEL_QUEST_MONEY_REWARD); @@ -244,6 +247,9 @@ void DB2Manager::LoadStores(std::string const& dataPath) LOAD_DB2(sMountStore); LOAD_DB2(sMountTypeXCapabilityStore); LOAD_DB2(sNameGenStore); + LOAD_DB2(sNamesProfanityStore); + LOAD_DB2(sNamesReservedStore); + LOAD_DB2(sNamesReservedLocaleStore); LOAD_DB2(sOverrideSpellDataStore); LOAD_DB2(sPhaseXPhaseGroupStore); LOAD_DB2(sQuestMoneyRewardStore); @@ -349,6 +355,27 @@ void DB2Manager::LoadStores(std::string const& dataPath) for (NameGenEntry const* entry : sNameGenStore) _nameGenData[entry->Race][entry->Sex].push_back(entry); + for (NamesProfanityEntry const* namesProfanity : sNamesProfanityStore) + { + ASSERT(namesProfanity->Language < TOTAL_LOCALES || namesProfanity->Language == -1); + if (namesProfanity->Language != -1) + _nameValidators[namesProfanity->Language].emplace_back(namesProfanity->Name, boost::regex::perl | boost::regex::icase | boost::regex::optimize); + else + for (uint32 i = 0; i < TOTAL_LOCALES; ++i) + _nameValidators[i].emplace_back(namesProfanity->Name, boost::regex::perl | boost::regex::icase | boost::regex::optimize); + } + + for (NamesReservedEntry const* namesReserved : sNamesReservedStore) + _nameValidators[TOTAL_LOCALES].emplace_back(namesReserved->Name, boost::regex::perl | boost::regex::icase | boost::regex::optimize); + + for (NamesReservedLocaleEntry const* namesReserved : sNamesReservedLocaleStore) + { + ASSERT(!(namesReserved->LocaleMask & ~((1 << TOTAL_LOCALES) - 1))); + for (uint32 i = 0; i < TOTAL_LOCALES; ++i) + if (namesReserved->LocaleMask & (1 << i)) + _nameValidators[i].emplace_back(namesReserved->Name, boost::regex::perl | boost::regex::icase | boost::regex::optimize); + } + for (PhaseXPhaseGroupEntry const* group : sPhaseXPhaseGroupStore) if (PhaseEntry const* phase = sPhaseStore.LookupEntry(group->PhaseID)) _phasesByGroup[group->PhaseGroupID].insert(phase->ID); @@ -711,6 +738,20 @@ DB2Manager::MountTypeXCapabilitySet const* DB2Manager::GetMountCapabilities(uint return nullptr; } +ResponseCodes DB2Manager::ValidateName(std::string const& name, LocaleConstant locale) const +{ + for (boost::regex const& regex : _nameValidators[locale]) + if (boost::regex_search(name, regex)) + return CHAR_NAME_PROFANE; + + // regexes at TOTAL_LOCALES are loaded from NamesReserved which is not locale specific + for (boost::regex const& regex : _nameValidators[TOTAL_LOCALES]) + if (boost::regex_search(name, regex)) + return CHAR_NAME_RESERVED; + + return CHAR_NAME_SUCCESS; +} + std::vector<QuestPackageItemEntry const*> const* DB2Manager::GetQuestPackageItems(uint32 questPackageID) const { auto itr = _questPackages.find(questPackageID); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 98c36fe4b1d..6ccf3933984 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -21,6 +21,7 @@ #include "DB2Store.h" #include "DB2Structure.h" #include "SharedDefines.h" +#include <boost/regex.hpp> #include <array> extern DB2Storage<AuctionHouseEntry> sAuctionHouseStore; @@ -142,6 +143,7 @@ public: typedef std::set<MountTypeXCapabilityEntry const*, MountTypeXCapabilityEntryComparator> MountTypeXCapabilitySet; typedef std::unordered_map<uint32, MountTypeXCapabilitySet> MountCapabilitiesByTypeContainer; typedef std::unordered_map<uint32, std::array<std::vector<NameGenEntry const*>, 2>> NameGenContainer; + typedef std::array<std::vector<boost::regex>, TOTAL_LOCALES + 1> NameValidationRegexContainer; typedef std::unordered_map<uint32, std::set<uint32>> PhaseGroupContainer; typedef std::unordered_map<uint32, std::vector<QuestPackageItemEntry const*>> QuestPackageItemContainer; typedef std::unordered_map<uint32, std::vector<SpecializationSpellsEntry const*>> SpecializationSpellsContainer; @@ -176,6 +178,7 @@ public: MountEntry const* GetMount(uint32 spellId) const; MountEntry const* GetMountById(uint32 id) const; MountTypeXCapabilitySet const* GetMountCapabilities(uint32 mountType) const; + ResponseCodes ValidateName(std::string const& name, LocaleConstant locale) const; std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItems(uint32 questPackageID) const; uint32 GetQuestUniqueBitFlag(uint32 questId); std::set<uint32> GetPhasesForGroup(uint32 group) const; @@ -200,6 +203,7 @@ private: MountContainer _mountsBySpellId; MountCapabilitiesByTypeContainer _mountCapabilitiesByType; NameGenContainer _nameGenData; + NameValidationRegexContainer _nameValidators; PhaseGroupContainer _phasesByGroup; QuestPackageItemContainer _questPackages; SpecializationSpellsContainer _specializationSpellsBySpec; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index b8bb0f2a94d..b0b99b20959 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -727,6 +727,26 @@ struct NameGenEntry uint32 Sex; // 3 }; +struct NamesProfanityEntry +{ + uint32 ID; // 0 + char const* Name; // 1 + int32 Language; // 2 +}; + +struct NamesReservedEntry +{ + uint32 ID; // 0 + char const* Name; // 1 +}; + +struct NamesReservedLocaleEntry +{ + uint32 ID; // 0 + char const* Name; // 1 + uint32 LocaleMask; // 2 +}; + #define MAX_OVERRIDE_SPELL 10 struct OverrideSpellDataEntry diff --git a/src/server/game/DataStores/DB2fmt.h b/src/server/game/DataStores/DB2fmt.h index a9da1ae646a..6088ff82ec0 100644 --- a/src/server/game/DataStores/DB2fmt.h +++ b/src/server/game/DataStores/DB2fmt.h @@ -76,6 +76,9 @@ char const MountCapabilityFormat[] = "niiiiiii"; char const MountFormat[] = "niiiisssii"; char const MountTypeXCapabilityFormat[] = "niii"; char const NameGenFormat[] = "nsii"; +char const NamesProfanityFormat[] = "nSi"; +char const NamesReservedFormat[] = "nS"; +char const NamesReservedLocaleFormat[] = "nSi"; char const OverrideSpellDataFormat[] = "niiiiiiiiiiii"; char const PhaseXPhaseGroupFormat[] = "nii"; char const QuestMoneyRewardFormat[] = "niiiiiiiiii"; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 5003cd52d74..9012be79547 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -16717,7 +16717,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) m_name = fields[2].GetString(); // check name limitations - if (ObjectMgr::CheckPlayerName(m_name) != CHAR_NAME_SUCCESS || + if (ObjectMgr::CheckPlayerName(m_name, GetSession()->GetSessionDbcLocale()) != CHAR_NAME_SUCCESS || (!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(m_name))) { diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 459de1bdcd9..463158762c2 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -7509,7 +7509,7 @@ bool isValidString(const std::wstring& wstr, uint32 strictMask, bool numericOrSp return false; } -ResponseCodes ObjectMgr::CheckPlayerName(const std::string& name, bool create) +ResponseCodes ObjectMgr::CheckPlayerName(std::string const& name, LocaleConstant locale, bool create /*= false*/) { std::wstring wname; if (!Utf8toWStr(name, wname)) @@ -7531,7 +7531,7 @@ ResponseCodes ObjectMgr::CheckPlayerName(const std::string& name, bool create) if (wname[i] == wname[i-1] && wname[i] == wname[i-2]) return CHAR_NAME_THREE_CONSECUTIVE; - return CHAR_NAME_SUCCESS; + return sDB2Manager.ValidateName(name, locale); } bool ObjectMgr::IsValidCharterName(const std::string& name) diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 1ae3e113331..8e660e3f32c 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1229,7 +1229,7 @@ class ObjectMgr bool IsReservedName(std::string const& name) const; // name with valid structure and symbols - static ResponseCodes CheckPlayerName(std::string const& name, bool create = false); + static ResponseCodes CheckPlayerName(std::string const& name, LocaleConstant locale, bool create = false); static PetNameInvalidReason CheckPetName(std::string const& name); static bool IsValidCharterName(std::string const& name); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 3dc6b72157a..dfbd48f0dec 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -458,7 +458,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharact } // check name limitations - ResponseCodes res = ObjectMgr::CheckPlayerName(charCreate.CreateInfo->Name, true); + ResponseCodes res = ObjectMgr::CheckPlayerName(charCreate.CreateInfo->Name, GetSessionDbcLocale(), true); if (res != CHAR_NAME_SUCCESS) { SendCharCreate(res); @@ -1271,7 +1271,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPackets::Character::CharacterRena return; } - ResponseCodes res = ObjectMgr::CheckPlayerName(request.RenameInfo->NewName, true); + ResponseCodes res = ObjectMgr::CheckPlayerName(request.RenameInfo->NewName, GetSessionDbcLocale(), true); if (res != CHAR_NAME_SUCCESS) { SendCharRename(res, request.RenameInfo.get()); @@ -1567,7 +1567,7 @@ void WorldSession::HandleCharCustomizeCallback(PreparedQueryResult result, World return; } - ResponseCodes res = ObjectMgr::CheckPlayerName(customizeInfo->CharName, true); + ResponseCodes res = ObjectMgr::CheckPlayerName(customizeInfo->CharName, GetSessionDbcLocale(), true); if (res != CHAR_NAME_SUCCESS) { SendCharCustomize(res, customizeInfo); @@ -1811,7 +1811,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res return; } - ResponseCodes res = ObjectMgr::CheckPlayerName(factionChangeInfo->Name, true); + ResponseCodes res = ObjectMgr::CheckPlayerName(factionChangeInfo->Name, GetSessionDbcLocale(), true); if (res != CHAR_NAME_SUCCESS) { SendCharFactionChange(res, factionChangeInfo); diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp index 71719c19b3a..900be2ba44a 100644 --- a/src/server/game/Tools/PlayerDump.cpp +++ b/src/server/game/Tools/PlayerDump.cpp @@ -435,7 +435,7 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s if (!normalizePlayerName(name)) name.clear(); - if (ObjectMgr::CheckPlayerName(name, true) == CHAR_NAME_SUCCESS) + if (ObjectMgr::CheckPlayerName(name, sWorld->GetDefaultDbcLocale(), true) == CHAR_NAME_SUCCESS) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); stmt->setString(0, name); |
