mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 04:37:00 +00:00
[8424] Added support for strict chatmessage validation
This commit is contained in:
parent
3c22e14e53
commit
43a4d1505e
13 changed files with 631 additions and 39 deletions
|
|
@ -31,6 +31,7 @@
|
|||
#include "GridNotifiersImpl.h"
|
||||
#include "CellImpl.h"
|
||||
#include "AccountMgr.h"
|
||||
#include "SpellMgr.h"
|
||||
|
||||
// Supported shift-links (client generated and server side)
|
||||
// |color|Hachievement:achievement_id:player_guid:0:0:0:0:0:0:0:0|h[name]|h|r
|
||||
|
|
@ -980,6 +981,542 @@ int ChatHandler::ParseCommands(const char* text)
|
|||
return 1;
|
||||
}
|
||||
|
||||
bool ChatHandler::isValidChatMessage(const char* message)
|
||||
{
|
||||
/*
|
||||
|
||||
valid examples:
|
||||
|cffa335ee|Hitem:812:0:0:0:0:0:0:0:70|h[Glowing Brightwood Staff]|h|r
|
||||
|cff808080|Hquest:2278:47|h[The Platinum Discs]|h|r
|
||||
|cffffd000|Htrade:4037:1:150:1:6AAAAAAAAAAAAAAAAAAAAAAOAADAAAAAAAAAAAAAAAAIAAAAAAAAA|h[Engineering]|h|r
|
||||
|cff4e96f7|Htalent:2232:-1|h[Taste for Blood]|h|r
|
||||
|cff71d5ff|Hspell:21563|h[Command]|h|r
|
||||
|cffffd000|Henchant:3919|h[Engineering: Rough Dynamite]|h|r
|
||||
|cffffff00|Hachievement:546:0000000000000001:0:0:0:-1:0:0:0:0|h[Safe Deposit]|h|r
|
||||
|cff66bbff|Hglyph:21:762|h[Glyph of Bladestorm]|h|r
|
||||
|
||||
| will be escaped to ||
|
||||
*/
|
||||
|
||||
if(strlen(message) > 255)
|
||||
return false;
|
||||
|
||||
const char validSequence[6] = "cHhhr";
|
||||
const char* validSequenceIterator = validSequence;
|
||||
|
||||
// more simple checks
|
||||
if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) < 3)
|
||||
{
|
||||
const std::string validCommands = "cHhr|";
|
||||
|
||||
while(*message)
|
||||
{
|
||||
// find next pipe command
|
||||
message = strchr(message, '|');
|
||||
|
||||
if(!message)
|
||||
return true;
|
||||
|
||||
++message;
|
||||
char commandChar = *message;
|
||||
if(validCommands.find(commandChar) == std::string::npos)
|
||||
return false;
|
||||
|
||||
++message;
|
||||
// validate sequence
|
||||
if(sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) == 2)
|
||||
{
|
||||
if(commandChar == *validSequenceIterator)
|
||||
{
|
||||
if (validSequenceIterator == validSequence+4)
|
||||
validSequenceIterator = validSequence;
|
||||
else
|
||||
++validSequenceIterator;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::istringstream reader(message);
|
||||
char buffer[256];
|
||||
|
||||
uint32 color;
|
||||
|
||||
ItemPrototype const* linkedItem;
|
||||
Quest const* linkedQuest;
|
||||
SpellEntry const *linkedSpell;
|
||||
AchievementEntry const* linkedAchievement;
|
||||
|
||||
while(!reader.eof())
|
||||
{
|
||||
if (validSequence == validSequenceIterator)
|
||||
{
|
||||
linkedItem = NULL;
|
||||
linkedQuest = NULL;
|
||||
linkedSpell = NULL;
|
||||
linkedAchievement = NULL;
|
||||
|
||||
reader.ignore(255, '|');
|
||||
}
|
||||
else if(reader.get() != '|')
|
||||
{
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage sequence aborted unexpectedly");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// pipe has always to be followed by at least one char
|
||||
if ( reader.peek() == '\0')
|
||||
{
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage pipe followed by \\0");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// no further pipe commands
|
||||
if (reader.eof())
|
||||
break;
|
||||
|
||||
char commandChar;
|
||||
reader >> commandChar;
|
||||
|
||||
// | in normal messages is escaped by ||
|
||||
if (commandChar != '|')
|
||||
{
|
||||
if(commandChar == *validSequenceIterator)
|
||||
{
|
||||
if (validSequenceIterator == validSequence+4)
|
||||
validSequenceIterator = validSequence;
|
||||
else
|
||||
++validSequenceIterator;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage invalid sequence, expected %c but got %c", *validSequenceIterator, commandChar);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(validSequence != validSequenceIterator)
|
||||
{
|
||||
// no escaped pipes in sequences
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage got escaped pipe in sequence");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (commandChar)
|
||||
{
|
||||
case 'c':
|
||||
color = 0;
|
||||
// validate color, expect 8 hex chars
|
||||
for(int i=0; i<8; i++)
|
||||
{
|
||||
char c;
|
||||
reader >> c;
|
||||
if(!c)
|
||||
{
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage got \\0 while reading color in |c command");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
color <<= 4;
|
||||
// check for hex char
|
||||
if(c >= '0' && c <='9')
|
||||
{
|
||||
color |= c-'0';
|
||||
continue;
|
||||
}
|
||||
if(c >= 'a' && c <='f')
|
||||
{
|
||||
color |= 10+c-'a';
|
||||
continue;
|
||||
}
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage got non hex char '%c' while reading color", c);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'H':
|
||||
// read chars up to colon = link type
|
||||
reader.getline(buffer, 256, ':');
|
||||
|
||||
if (strcmp(buffer, "item") == 0)
|
||||
{
|
||||
// read item entry
|
||||
reader.getline(buffer, 256, ':');
|
||||
|
||||
linkedItem= objmgr.GetItemPrototype(atoi(buffer));
|
||||
if(!linkedItem)
|
||||
{
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage got invalid itemID %u in |item command", atoi(buffer));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (color != ItemQualityColors[linkedItem->Quality])
|
||||
{
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage linked item has color %u, but user claims %u", ItemQualityColors[linkedItem->Quality],
|
||||
color);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
char c = reader.peek();
|
||||
|
||||
// ignore enchants etc.
|
||||
while(c >='0' && c <='9' || c==':')
|
||||
{
|
||||
reader.ignore(1);
|
||||
c = reader.peek();
|
||||
}
|
||||
}
|
||||
else if(strcmp(buffer, "quest") == 0)
|
||||
{
|
||||
// no color check for questlinks, each client will adapt it anyway
|
||||
uint32 questid= 0;
|
||||
// read questid
|
||||
char c = reader.peek();
|
||||
while(c >='0' && c<='9')
|
||||
{
|
||||
reader.ignore(1);
|
||||
questid *= 10;
|
||||
questid += c-'0';
|
||||
c = reader.peek();
|
||||
}
|
||||
|
||||
linkedQuest = objmgr.GetQuestTemplate(questid);
|
||||
|
||||
if(!linkedQuest)
|
||||
{
|
||||
#ifdef MANOGS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage Questtemplate %u not found", questid);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
c = reader.peek();
|
||||
// level
|
||||
while(c !='|' && c!='\0')
|
||||
{
|
||||
reader.ignore(1);
|
||||
c = reader.peek();
|
||||
}
|
||||
}
|
||||
else if(strcmp(buffer, "trade") == 0)
|
||||
{
|
||||
if(color != CHAT_LINK_COLOR_TRADE)
|
||||
return false;
|
||||
|
||||
// read spell entry
|
||||
reader.getline(buffer, 256, ':');
|
||||
linkedSpell = sSpellStore.LookupEntry(atoi(buffer));
|
||||
if(!linkedSpell)
|
||||
return false;
|
||||
|
||||
char c = reader.peek();
|
||||
// base64 encoded stuff
|
||||
while(c !='|' && c!='\0')
|
||||
{
|
||||
reader.ignore(1);
|
||||
c = reader.peek();
|
||||
}
|
||||
}
|
||||
else if(strcmp(buffer, "talent") == 0)
|
||||
{
|
||||
// talent links are always supposed to be blue
|
||||
if(color != CHAT_LINK_COLOR_TALENT)
|
||||
return false;
|
||||
|
||||
// read talent entry
|
||||
reader.getline(buffer, 256, ':');
|
||||
TalentEntry const *talentInfo = sTalentStore.LookupEntry(atoi(buffer));
|
||||
if(!talentInfo)
|
||||
return false;
|
||||
|
||||
linkedSpell = sSpellStore.LookupEntry(talentInfo->RankID[0]);
|
||||
if(!linkedSpell)
|
||||
return false;
|
||||
|
||||
char c = reader.peek();
|
||||
// skillpoints? whatever, drop it
|
||||
while(c !='|' && c!='\0')
|
||||
{
|
||||
reader.ignore(1);
|
||||
c = reader.peek();
|
||||
}
|
||||
}
|
||||
else if(strcmp(buffer, "spell") == 0)
|
||||
{
|
||||
if(color != CHAT_LINK_COLOR_SPELL)
|
||||
return false;
|
||||
|
||||
uint32 spellid = 0;
|
||||
// read spell entry
|
||||
char c = reader.peek();
|
||||
while(c >='0' && c<='9')
|
||||
{
|
||||
reader.ignore(1);
|
||||
spellid *= 10;
|
||||
spellid += c-'0';
|
||||
c = reader.peek();
|
||||
}
|
||||
linkedSpell = sSpellStore.LookupEntry(spellid);
|
||||
if(!linkedSpell)
|
||||
return false;
|
||||
}
|
||||
else if(strcmp(buffer, "enchant") == 0)
|
||||
{
|
||||
if(color != CHAT_LINK_COLOR_ENCHANT)
|
||||
return false;
|
||||
|
||||
uint32 spellid = 0;
|
||||
// read spell entry
|
||||
char c = reader.peek();
|
||||
while(c >='0' && c<='9')
|
||||
{
|
||||
reader.ignore(1);
|
||||
spellid *= 10;
|
||||
spellid += c-'0';
|
||||
c = reader.peek();
|
||||
}
|
||||
linkedSpell = sSpellStore.LookupEntry(spellid);
|
||||
if(!linkedSpell)
|
||||
return false;
|
||||
}
|
||||
else if(strcmp(buffer, "achievement") == 0)
|
||||
{
|
||||
if(color != CHAT_LINK_COLOR_ACHIEVEMENT)
|
||||
return false;
|
||||
reader.getline(buffer, 256, ':');
|
||||
uint32 achievementId = atoi(buffer);
|
||||
linkedAchievement = sAchievementStore.LookupEntry(achievementId);
|
||||
|
||||
if(!linkedAchievement)
|
||||
return false;
|
||||
|
||||
char c = reader.peek();
|
||||
// skip progress
|
||||
while(c !='|' && c!='\0')
|
||||
{
|
||||
reader.ignore(1);
|
||||
c = reader.peek();
|
||||
}
|
||||
}
|
||||
else if(strcmp(buffer, "glyph") == 0)
|
||||
{
|
||||
if(color != CHAT_LINK_COLOR_GLYPH)
|
||||
return false;
|
||||
|
||||
// first id is slot, drop it
|
||||
reader.getline(buffer, 256, ':');
|
||||
uint32 glyphId = 0;
|
||||
char c = reader.peek();
|
||||
while(c>='0' && c <='9')
|
||||
{
|
||||
glyphId *= 10;
|
||||
glyphId += c-'0';
|
||||
reader.ignore(1);
|
||||
c = reader.peek();
|
||||
}
|
||||
GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId);
|
||||
if(!glyph)
|
||||
return false;
|
||||
|
||||
linkedSpell = sSpellStore.LookupEntry(glyph->SpellId);
|
||||
|
||||
if(!linkedSpell)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage user sent unsupported link type '%s'", buffer);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
// if h is next element in sequence, this one must contain the linked text :)
|
||||
if(*validSequenceIterator == 'h')
|
||||
{
|
||||
// links start with '['
|
||||
if(reader.get() != '[')
|
||||
{
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage link caption doesn't start with '['");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
reader.getline(buffer, 256, ']');
|
||||
|
||||
// verify the link name
|
||||
if (linkedSpell)
|
||||
{
|
||||
// spells with that flag have a prefix of "$PROFESSION: "
|
||||
if(linkedSpell->Attributes & SPELL_ATTR_TRADESPELL)
|
||||
{
|
||||
// lookup skillid
|
||||
SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(linkedSpell->Id);
|
||||
SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(linkedSpell->Id);
|
||||
|
||||
if(lower == upper)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SkillLineAbilityEntry const *skillInfo = lower->second;
|
||||
|
||||
if (!skillInfo)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SkillLineEntry const *skillLine = sSkillLineStore.LookupEntry(skillInfo->skillId);
|
||||
if(!skillLine)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for(uint8 i=0; i<MAX_LOCALE; ++i)
|
||||
{
|
||||
uint32 skillLineNameLength = strlen(skillLine->name[i]);
|
||||
if(skillLineNameLength > 0 && strncmp(skillLine->name[i], buffer, skillLineNameLength) == 0)
|
||||
{
|
||||
// found the prefix, remove it to perform spellname validation below
|
||||
// -2 = strlen(": ")
|
||||
uint32 spellNameLength = strlen(buffer)-skillLineNameLength-2;
|
||||
memmove(buffer, buffer+skillLineNameLength+2, spellNameLength+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool foundName = false;
|
||||
for(uint8 i=0; i<MAX_LOCALE; ++i)
|
||||
{
|
||||
if(*linkedSpell->SpellName[i] && strcmp(linkedSpell->SpellName[i], buffer) == 0)
|
||||
{
|
||||
foundName = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!foundName)
|
||||
return false;
|
||||
}
|
||||
else if(linkedQuest)
|
||||
{
|
||||
if (linkedQuest->GetTitle() != buffer)
|
||||
{
|
||||
QuestLocale const *ql = objmgr.GetQuestLocale(linkedQuest->GetQuestId());
|
||||
|
||||
if(!ql)
|
||||
{
|
||||
#ifdef MANOGS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage default questname didn't match and there is no locale");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool foundName = false;
|
||||
for(uint8 i=0; i<ql->Title.size(); i++)
|
||||
{
|
||||
if(ql->Title[i] == buffer)
|
||||
{
|
||||
foundName = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!foundName)
|
||||
{
|
||||
#ifdef MANOGS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage no quest locale title matched")
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(linkedItem)
|
||||
{
|
||||
if(strcmp(linkedItem->Name1, buffer) != 0)
|
||||
{
|
||||
ItemLocale const *il = objmgr.GetItemLocale(linkedItem->ItemId);
|
||||
|
||||
if(!il)
|
||||
{
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage linked item name doesn't is wrong and there is no localization");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool foundName = false;
|
||||
for(uint8 i=0; i<il->Name.size(); ++i)
|
||||
{
|
||||
if(il->Name[i] == buffer)
|
||||
{
|
||||
foundName = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!foundName)
|
||||
{
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage linked item name wasn't found in any localization");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(linkedAchievement)
|
||||
{
|
||||
bool foundName = false;
|
||||
for(uint8 i=0; i<MAX_LOCALE; ++i)
|
||||
{
|
||||
if(*linkedAchievement->name[i], strcmp(linkedAchievement->name[i], buffer) == 0)
|
||||
{
|
||||
foundName = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!foundName)
|
||||
return false;
|
||||
}
|
||||
// that place should never be reached - if nothing linked has been set in |H
|
||||
// it will return false before
|
||||
else
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
case '|':
|
||||
// no further payload
|
||||
break;
|
||||
default:
|
||||
#ifdef MANGOS_DEBUG
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage got invalid command |%c", commandChar);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check if every opened sequence was also closed properly
|
||||
#ifdef MANGOS_DEBUG
|
||||
if(validSequence != validSequenceIterator)
|
||||
sLog.outBasic("ChatHandler::isValidChatMessage EOF in active sequence");
|
||||
#endif
|
||||
return validSequence == validSequenceIterator;
|
||||
}
|
||||
|
||||
bool ChatHandler::ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd)
|
||||
{
|
||||
std::string list;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ class ChatHandler
|
|||
void PSendSysMessage( int32 entry, ... );
|
||||
|
||||
int ParseCommands(const char* text);
|
||||
|
||||
bool isValidChatMessage(const char* msg);
|
||||
protected:
|
||||
explicit ChatHandler() : m_session(NULL) {} // for CLI subclass
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,28 @@
|
|||
#include "GridNotifiersImpl.h"
|
||||
#include "CellImpl.h"
|
||||
|
||||
bool WorldSession::processChatmessageFurtherAfterSecurityChecks(std::string& msg, uint32 lang)
|
||||
{
|
||||
if (lang != LANG_ADDON)
|
||||
{
|
||||
// strip invisible characters for non-addon messages
|
||||
if(sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
|
||||
if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) && GetSecurity() < SEC_MODERATOR
|
||||
&& !ChatHandler(this).isValidChatMessage(msg.c_str()))
|
||||
{
|
||||
sLog.outError("Player %s (GUID: %u) sent a chatmessage with an invalid link: %s", GetPlayer()->GetName(),
|
||||
GetPlayer()->GetGUIDLow(), msg.c_str());
|
||||
if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK))
|
||||
KickPlayer();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||
{
|
||||
uint32 type;
|
||||
|
|
@ -150,9 +172,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
|||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
||||
break;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||
return;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
|
@ -171,9 +192,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
|||
recv_data >> to;
|
||||
recv_data >> msg;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||
return;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
|
@ -224,9 +244,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
|||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
||||
break;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||
return;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
|
@ -253,9 +272,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
|||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
||||
break;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||
return;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
|
@ -280,9 +298,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
|||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
||||
break;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||
return;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
|
@ -306,9 +323,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
|||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
||||
break;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||
return;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
|
@ -334,9 +350,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
|||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
||||
break;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||
return;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
|
@ -355,9 +370,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
|||
std::string msg="";
|
||||
recv_data >> msg;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||
return;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
|
@ -377,9 +391,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
|||
std::string msg="";
|
||||
recv_data >> msg;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||
return;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
|
@ -399,9 +412,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
|||
std::string msg="";
|
||||
recv_data >> msg;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||
return;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
|
@ -423,9 +435,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
|||
|
||||
recv_data >> msg;
|
||||
|
||||
// strip invisible characters for non-addon messages
|
||||
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
|
||||
stripLineInvisibleChars(msg);
|
||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||
return;
|
||||
|
||||
if(msg.empty())
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ struct AchievementEntry
|
|||
uint32 factionFlag; // 1 -1=all, 0=horde, 1=alliance
|
||||
uint32 mapID; // 2 -1=none
|
||||
//uint32 parentAchievement; // 3 its Achievement parent (can`t start while parent uncomplete, use its Criteria if don`t have own, use its progress on begin)
|
||||
//char *name[16]; // 4-19
|
||||
char *name[16]; // 4-19
|
||||
//uint32 name_flags; // 20
|
||||
//char *description[16]; // 21-36
|
||||
//uint32 desc_flags; // 37
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
#ifndef MANGOS_DBCSFRM_H
|
||||
#define MANGOS_DBCSFRM_H
|
||||
|
||||
const char Achievementfmt[]="niixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii";
|
||||
const char Achievementfmt[]="niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii";
|
||||
const char AchievementCriteriafmt[]="niiiiiiiixxxxxxxxxxxxxxxxxiixix";
|
||||
const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxxx";
|
||||
const char AreaGroupEntryfmt[]="niiiiiii";
|
||||
|
|
|
|||
|
|
@ -1322,7 +1322,7 @@ void LoadLootTemplates_Spell()
|
|||
{
|
||||
// not report about not trainable spells (optionally supported by DB)
|
||||
// ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example
|
||||
if (!(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR_UNK5))
|
||||
if (!(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR_TRADESPELL))
|
||||
{
|
||||
LootTemplates_Spell.ReportNotExistedId(spell_id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -207,6 +207,18 @@ enum ItemQualities
|
|||
|
||||
#define MAX_ITEM_QUALITY 8
|
||||
|
||||
const uint32 ItemQualityColors[MAX_ITEM_QUALITY] = {
|
||||
0xff9d9d9d, //GREY
|
||||
0xffffffff, //WHITE
|
||||
0xff1eff00, //GREEN
|
||||
0xff0070dd, //BLUE
|
||||
0xffa335ee, //PURPLE
|
||||
0xffff8000, //ORANGE
|
||||
0xffe6cc80, //LIGHT YELLOW
|
||||
0xffe6cc80 //LIGHT YELLOW
|
||||
};
|
||||
|
||||
|
||||
// ***********************************
|
||||
// Spell Attributes definitions
|
||||
// ***********************************
|
||||
|
|
@ -216,7 +228,7 @@ enum ItemQualities
|
|||
#define SPELL_ATTR_ON_NEXT_SWING_1 0x00000004 // 2 on next swing
|
||||
#define SPELL_ATTR_UNK3 0x00000008 // 3 not set in 3.0.3
|
||||
#define SPELL_ATTR_UNK4 0x00000010 // 4
|
||||
#define SPELL_ATTR_UNK5 0x00000020 // 5 trade spells?
|
||||
#define SPELL_ATTR_TRADESPELL 0x00000020 // 5 trade spells, will be added by client to a sublist of profession spell
|
||||
#define SPELL_ATTR_PASSIVE 0x00000040 // 6 Passive spell
|
||||
#define SPELL_ATTR_UNK7 0x00000080 // 7 visible?
|
||||
#define SPELL_ATTR_UNK8 0x00000100 // 8
|
||||
|
|
@ -2309,6 +2321,16 @@ enum ChatMsg
|
|||
|
||||
#define MAX_CHAT_MSG_TYPE 0x32
|
||||
|
||||
enum ChatLinkColors
|
||||
{
|
||||
CHAT_LINK_COLOR_TRADE = 0xffffd000, // orange
|
||||
CHAT_LINK_COLOR_TALENT = 0xff4e96f7, // blue
|
||||
CHAT_LINK_COLOR_SPELL = 0xff71d5ff, // bright blue
|
||||
CHAT_LINK_COLOR_ENCHANT = 0xffffd000, // orange
|
||||
CHAT_LINK_COLOR_ACHIEVEMENT = 0xffffff00,
|
||||
CHAT_LINK_COLOR_GLYPH = 0xff66bbff
|
||||
};
|
||||
|
||||
// Values from ItemPetFood (power of (value-1) used for compare with CreatureFamilyEntry.petDietMask
|
||||
enum PetDiet
|
||||
{
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell)
|
|||
if(Player* modOwner = spell->GetCaster()->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell);
|
||||
|
||||
if( !(spellInfo->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_UNK5)) )
|
||||
if( !(spellInfo->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_TRADESPELL)) )
|
||||
castTime = int32(castTime * spell->GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED));
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -920,6 +920,8 @@ void World::LoadConfigSettings(bool reload)
|
|||
|
||||
m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true);
|
||||
m_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfig.GetBoolDefault("ChatFakeMessagePreventing", false);
|
||||
m_configs[CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY] = sConfig.GetIntDefault("ChatStrictLinkChecking.Severity", 0);
|
||||
m_configs[CONFIG_CHAT_STRICT_LINK_CHECKING_KICK] = sConfig.GetIntDefault("ChatStrictLinkChecking.Kick", 0);
|
||||
|
||||
m_configs[CONFIG_CORPSE_DECAY_NORMAL] = sConfig.GetIntDefault("Corpse.Decay.NORMAL", 60);
|
||||
m_configs[CONFIG_CORPSE_DECAY_RARE] = sConfig.GetIntDefault("Corpse.Decay.RARE", 300);
|
||||
|
|
|
|||
|
|
@ -178,6 +178,8 @@ enum WorldConfigs
|
|||
CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL,
|
||||
CONFIG_TALENTS_INSPECTING,
|
||||
CONFIG_CHAT_FAKE_MESSAGE_PREVENTING,
|
||||
CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY,
|
||||
CONFIG_CHAT_STRICT_LINK_CHECKING_KICK,
|
||||
CONFIG_CORPSE_DECAY_NORMAL,
|
||||
CONFIG_CORPSE_DECAY_RARE,
|
||||
CONFIG_CORPSE_DECAY_ELITE,
|
||||
|
|
|
|||
|
|
@ -547,6 +547,7 @@ class MANGOS_DLL_SPEC WorldSession
|
|||
void HandlePushQuestToParty(WorldPacket& recvPacket);
|
||||
void HandleQuestPushResult(WorldPacket& recvPacket);
|
||||
|
||||
bool processChatmessageFurtherAfterSecurityChecks(std::string&, uint32);
|
||||
void HandleMessagechatOpcode(WorldPacket& recvPacket);
|
||||
void HandleTextEmoteOpcode(WorldPacket& recvPacket);
|
||||
void HandleChatIgnoredOpcode(WorldPacket& recvPacket);
|
||||
|
|
|
|||
|
|
@ -826,6 +826,19 @@ ListenRange.Yell = 300
|
|||
# Default: 0 (disible fake messages preventing)
|
||||
# 1 (enabled fake messages preventing)
|
||||
#
|
||||
# ChatStrictLinkChecking.Severity
|
||||
# Check chat messages for ingame links to spells, items, quests, achievements etc.
|
||||
# Default: 0 (disable link checking)
|
||||
# 1 (check if only valid pipe commands are used. This prevents posting pictures for example)
|
||||
# 2 (verifiy that pipe commands are used in a correct order)
|
||||
# 3 (check if color, entry and name don't contradict each other. For correct work, please assure
|
||||
# that you have extracted locale DBCs of every language specific client playing on this server.)
|
||||
#
|
||||
# ChatStrictLinkChecking.Kick
|
||||
# Defines, what should be done if a message is considered to contain invalid pipe commands.
|
||||
# Default: 0 (silently ignore message)
|
||||
# 1 (kick players who sent invalid formed messages)
|
||||
#
|
||||
# ChatFlood.MessageCount
|
||||
# Chat anti-flood protection, haste message count to activate protection
|
||||
# Default: 10
|
||||
|
|
@ -852,6 +865,8 @@ ListenRange.Yell = 300
|
|||
###################################################################################################################
|
||||
|
||||
ChatFakeMessagePreventing = 0
|
||||
ChatStrictLinkChecking.Severity = 0
|
||||
ChatStrictLinkChecking.Kick = 0
|
||||
ChatFlood.MessageCount = 10
|
||||
ChatFlood.MessageDelay = 1
|
||||
ChatFlood.MuteTime = 10
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __REVISION_NR_H__
|
||||
#define __REVISION_NR_H__
|
||||
#define REVISION_NR "8423"
|
||||
#define REVISION_NR "8424"
|
||||
#endif // __REVISION_NR_H__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue