aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Chat/ChatCommands
diff options
context:
space:
mode:
authorTreeston <treeston.mmoc@gmail.com>2018-09-13 00:11:27 +0200
committerShauren <shauren.trinity@gmail.com>2021-10-31 01:39:04 +0200
commite506c80a64571530cf7edd947a5b7dc2f35f9d1d (patch)
treee78a0d480537525c9db0b8ebb9d08f6ce8bdcc6e /src/server/game/Chat/ChatCommands
parentfa7e46a4f3f807b0682aba26c7993d142f842648 (diff)
Core/Chat: Unify chat hyperlink parsing (PR #22417)
- Validate most link properties all the time - If enabled, also validate link text (needs locale) - Instead of blocking the entire message, sanitize it - Apply filtering to DND/AFK messages. Closes #22399 (cherry picked from commit f27284594b18000a1c098262728fb19fdc63fc6c)
Diffstat (limited to 'src/server/game/Chat/ChatCommands')
-rw-r--r--src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp3
-rw-r--r--src/server/game/Chat/ChatCommands/ChatCommandArgs.h10
-rw-r--r--src/server/game/Chat/ChatCommands/ChatCommandHelpers.h9
-rw-r--r--src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.cpp64
-rw-r--r--src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.h160
-rw-r--r--src/server/game/Chat/ChatCommands/ChatCommandTags.h53
6 files changed, 63 insertions, 236 deletions
diff --git a/src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp b/src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp
index b00b48fe0a0..20893d9df90 100644
--- a/src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp
+++ b/src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp
@@ -17,7 +17,6 @@
#include "ChatCommandArgs.h"
#include "ChatCommand.h"
-#include "ChatCommandHyperlinks.h"
#include "DB2Stores.h"
#include "ObjectMgr.h"
@@ -26,7 +25,7 @@ using namespace Trinity::ChatCommands;
struct AchievementVisitor
{
using value_type = AchievementEntry const*;
- value_type operator()(Hyperlink<achievement> achData) const { return achData->achievement; }
+ value_type operator()(Hyperlink<achievement> achData) const { return achData->Achievement; }
value_type operator()(uint32 achId) const { return sAchievementStore.LookupEntry(achId); }
};
char const* Trinity::ChatCommands::ArgInfo<AchievementEntry const*>::TryConsume(AchievementEntry const*& data, char const* args)
diff --git a/src/server/game/Chat/ChatCommands/ChatCommandArgs.h b/src/server/game/Chat/ChatCommands/ChatCommandArgs.h
index bbdb2565f25..110103ebb83 100644
--- a/src/server/game/Chat/ChatCommands/ChatCommandArgs.h
+++ b/src/server/game/Chat/ChatCommands/ChatCommandArgs.h
@@ -20,12 +20,13 @@
#include "ChatCommandHelpers.h"
#include "ChatCommandTags.h"
-#include "ChatCommandHyperlinks.h"
struct GameTele;
-namespace Trinity {
-namespace ChatCommands {
+namespace Trinity
+{
+namespace ChatCommands
+{
/************************** ARGUMENT HANDLERS *******************************************\
|* Define how to extract contents of a certain requested type from a string *|
@@ -129,6 +130,7 @@ struct TC_GAME_API ArgInfo<bool>
static char const* TryConsume(bool&, char const*);
};
-}}
+}
+}
#endif
diff --git a/src/server/game/Chat/ChatCommands/ChatCommandHelpers.h b/src/server/game/Chat/ChatCommands/ChatCommandHelpers.h
index 42c0a195041..fe6c8d709ca 100644
--- a/src/server/game/Chat/ChatCommands/ChatCommandHelpers.h
+++ b/src/server/game/Chat/ChatCommands/ChatCommandHelpers.h
@@ -21,8 +21,10 @@
#include "advstd.h"
#include <type_traits>
-namespace Trinity {
-namespace ChatCommands {
+namespace Trinity
+{
+namespace ChatCommands
+{
static constexpr char COMMAND_DELIMITER = ' ';
@@ -70,6 +72,7 @@ struct get_nth<0, T1, Ts...>
template <size_t index, typename... Ts>
using get_nth_t = typename get_nth<index, Ts...>::type;
-}}
+}
+}
#endif
diff --git a/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.cpp b/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.cpp
deleted file mode 100644
index 53035813769..00000000000
--- a/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
- *
- * 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 "ChatCommandHyperlinks.h"
-#include "DB2Stores.h"
-
-static constexpr char HYPERLINK_DELIMITER = ':';
-
-class AchievementLinkTokenizer
-{
- public:
- AchievementLinkTokenizer(char const* pos, size_t len) : _pos(pos), _len(len), _empty(false) {}
-
- template <typename T>
- bool TryConsumeTo(T& val)
- {
- if (_empty)
- return false;
-
- char const* firstPos = _pos;
- size_t thisLen = 0;
- // find next delimiter
- for (; _len && *_pos != HYPERLINK_DELIMITER; --_len, ++_pos, ++thisLen);
- if (_len)
- --_len, ++_pos; // skip the delimiter
- else
- _empty = true;
-
- return Trinity::ChatCommands::base_tag::StoreTo(val, firstPos, thisLen);
- }
-
- bool IsEmpty() { return _empty; }
-
- private:
- char const* _pos;
- size_t _len;
- bool _empty;
-};
-
-bool Trinity::ChatCommands::achievement::StoreTo(AchievementLinkData& val, char const* pos, size_t len)
-{
- AchievementLinkTokenizer t(pos, len);
- uint32 achievementId;
- if (!t.TryConsumeTo(achievementId))
- return false;
- val.achievement = sAchievementStore.LookupEntry(achievementId);
- return val.achievement && t.TryConsumeTo(val.characterId) && t.TryConsumeTo(val.isFinished) &&
- t.TryConsumeTo(val.month) && t.TryConsumeTo(val.day) && t.TryConsumeTo(val.year) && t.TryConsumeTo(val.criteria[0]) &&
- t.TryConsumeTo(val.criteria[1]) && t.TryConsumeTo(val.criteria[2]) && t.TryConsumeTo(val.criteria[3]) && t.IsEmpty();
-}
diff --git a/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.h b/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.h
deleted file mode 100644
index f88b383d578..00000000000
--- a/src/server/game/Chat/ChatCommands/ChatCommandHyperlinks.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
- *
- * 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 TRINITY_CHATCOMMANDHYPERLINKS_H
-#define TRINITY_CHATCOMMANDHYPERLINKS_H
-
-#include "ChatCommandHelpers.h"
-#include "ChatCommandTags.h"
-#include "ObjectGuid.h"
-
-struct AchievementEntry;
-
-namespace Trinity {
-namespace ChatCommands {
-
-// for details on what ContainerTag has to expose, see ChatCommandTags.h
-template <typename linktag>
-struct Hyperlink : public ContainerTag
-{
- typedef typename linktag::value_type value_type;
- typedef advstd::remove_cvref_t<value_type> storage_type;
-
- public:
- operator value_type() const { return val; }
- value_type const& operator*() const { return val; }
- value_type const* operator->() const { return &val; }
-
- char const* TryConsume(char const* pos)
- {
- //color tag
- if (*(pos++) != '|' || *(pos++) != 'c')
- return nullptr;
- for (uint8 i = 0; i < 8; ++i)
- if (!*(pos++)) // make sure we don't overrun a terminator
- return nullptr;
- // link data start tag
- if (*(pos++) != '|' || *(pos++) != 'H')
- return nullptr;
- // link tag, should match argument
- char const* tag = linktag::tag();
- while (*tag)
- if (*(pos++) != *(tag++))
- return nullptr;
- // separator
- if (*(pos++) != ':')
- return nullptr;
- // ok, link data, let's figure out how long it is
- char const* datastart = pos;
- size_t datalength = 0;
- while (*pos && *(pos++) != '|')
- ++datalength;
- // ok, next should be link data end tag...
- if (*(pos++) != 'h')
- return nullptr;
- // then visible link text, skip to next '|', should be '|h|r' terminator
- while (*pos && *(pos++) != '|');
- if (*(pos++) != 'h' || *(pos++) != '|' || *(pos++) != 'r')
- return nullptr;
- // finally, skip to end of token
- tokenize(pos);
- // store value
- if (!linktag::StoreTo(val, datastart, datalength))
- return nullptr;
-
- // return final pos
- return pos;
- }
-
- private:
- storage_type val;
-};
-
-/************************** LINK TAGS ***************************************************\
-|* Link tags must abide by the following: *|
-|* - MUST expose ::value_type typedef *|
-|* - storage type is remove_cvref_t<value_type> *|
-|* - MUST expose static ::tag method, void -> const char* *|
-|* - this method SHOULD be constexpr *|
-|* - returns identifier string for the link ("creature", "creature_entry", "item") *|
-|* - MUST expose static ::StoreTo method, (storage&, char const*, size_t) *|
-|* - assign value_type& based on content of std::string(char const*, size_t) *|
-|* - return value indicates success/failure *|
-|* - for integral/string types this can be achieved by extending base_tag *|
-\****************************************************************************************/
-struct base_tag
-{
- static bool StoreTo(std::string& val, char const* pos, size_t len)
- {
- val.assign(pos, len);
- return true;
- }
-
- static bool StoreTo(ObjectGuid& val, char const* pos, size_t len)
- {
- val = ObjectGuid::FromString(std::string(pos, len));
- return true;
- }
-
- template <typename T>
- static std::enable_if_t<advstd::is_integral_v<T> && advstd::is_unsigned_v<T>, bool> StoreTo(T& val, char const* pos, size_t len)
- {
- try { val = std::stoull(std::string(pos, len)); }
- catch (...) { return false; }
- return true;
- }
-
- template <typename T>
- static std::enable_if_t<advstd::is_integral_v<T> && advstd::is_signed_v<T>, bool> StoreTo(T& val, char const* pos, size_t len)
- {
- try { val = std::stoll(std::string(pos, len)); }
- catch (...) { return false; }
- return true;
- }
-};
-
-#define make_base_tag(ltag, type) struct ltag : public base_tag { using value_type = type; static constexpr char const* tag() { return #ltag; } }
-make_base_tag(areatrigger, uint32);
-make_base_tag(creature, ObjectGuid::LowType);
-make_base_tag(creature_entry, uint32);
-make_base_tag(gameobject, ObjectGuid::LowType);
-make_base_tag(taxinode, uint32);
-make_base_tag(tele, uint32);
-#undef make_base_tag
-
-struct AchievementLinkData
-{
- AchievementEntry const* achievement;
- ObjectGuid characterId;
- bool isFinished;
- uint16 year;
- uint8 month;
- uint8 day;
- uint32 criteria[4];
-};
-
-struct TC_GAME_API achievement
-{
- using value_type = AchievementLinkData;
- static constexpr char const* tag() { return "achievement"; }
- static bool StoreTo(AchievementLinkData& val, char const* pos, size_t len);
-};
-
-}}
-
-#endif
-
diff --git a/src/server/game/Chat/ChatCommands/ChatCommandTags.h b/src/server/game/Chat/ChatCommands/ChatCommandTags.h
index c28c4f21a8f..b8fcc0e0062 100644
--- a/src/server/game/Chat/ChatCommands/ChatCommandTags.h
+++ b/src/server/game/Chat/ChatCommands/ChatCommandTags.h
@@ -19,6 +19,7 @@
#define TRINITY_CHATCOMMANDTAGS_H
#include "ChatCommandHelpers.h"
+#include "Hyperlinks.h"
#include "Optional.h"
#include <boost/variant.hpp>
#include <cmath>
@@ -28,8 +29,10 @@
#include <type_traits>
#include <utility>
-namespace Trinity {
-namespace ChatCommands {
+namespace Trinity
+{
+namespace ChatCommands
+{
/************************** CONTAINER TAGS **********************************************\
|* Simple holder classes to differentiate between extraction methods *|
|* Should inherit from ContainerTag for template identification *|
@@ -75,6 +78,49 @@ struct ExactSequence : public ContainerTag
char const* TryConsume(char const* pos) const { return ExactSequence::_TryConsume(pos); }
};
+template <typename linktag>
+struct Hyperlink : public ContainerTag
+{
+ typedef typename linktag::value_type value_type;
+ typedef advstd::remove_cvref_t<value_type> storage_type;
+
+ public:
+ operator value_type() const { return val; }
+ value_type operator*() const { return val; }
+ storage_type const* operator->() const { return &val; }
+
+ char const* TryConsume(char const* pos)
+ {
+ Trinity::Hyperlinks::HyperlinkInfo info = Trinity::Hyperlinks::ParseHyperlink(pos);
+ // invalid hyperlinks cannot be consumed
+ if (!info)
+ return nullptr;
+
+ // check if we got the right tag
+ if (info.tag.second != strlen(linktag::tag()))
+ return nullptr;
+ if (strncmp(info.tag.first, linktag::tag(), strlen(linktag::tag())) != 0)
+ return nullptr;
+
+ // store value
+ if (!linktag::StoreTo(val, info.data.first, info.data.second))
+ return nullptr;
+
+ // finally, skip to end of token
+ pos = info.next;
+ tokenize(pos);
+
+ // return final pos
+ return pos;
+ }
+
+ private:
+ storage_type val;
+};
+
+// pull in link tags for user convenience
+using namespace ::Trinity::Hyperlinks::LinkTags;
+
/************************** VARIANT TAG LOGIC *********************************\
|* This has some special handling over in ChatCommand.h *|
\******************************************************************************/
@@ -118,6 +164,7 @@ struct Variant : public boost::variant<T1, Ts...>
decltype(auto) get() const { return boost::get<get_nth_t<index, T1, Ts...>>(*this); }
};
-}}
+}
+}
#endif