aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2015-08-30 00:17:08 +0200
committerShauren <shauren.trinity@gmail.com>2015-08-30 00:17:08 +0200
commitb564c10b13effed63c7b7dae25117e2e0a2c64e4 (patch)
treeea79cf0c9b254aac517f1024602b39615eedb010 /src/server/game
parentb0107802064a19d69ce06f7bcf8b8394695e6faf (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.cpp41
-rw-r--r--src/server/game/DataStores/DB2Stores.h4
-rw-r--r--src/server/game/DataStores/DB2Structure.h20
-rw-r--r--src/server/game/DataStores/DB2fmt.h3
-rw-r--r--src/server/game/Entities/Player/Player.cpp2
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp4
-rw-r--r--src/server/game/Globals/ObjectMgr.h2
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp8
-rw-r--r--src/server/game/Tools/PlayerDump.cpp2
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);