diff options
| author | Treeston <treeston.mmoc@gmail.com> | 2018-09-13 00:11:27 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2021-10-31 01:39:04 +0200 |
| commit | e506c80a64571530cf7edd947a5b7dc2f35f9d1d (patch) | |
| tree | e78a0d480537525c9db0b8ebb9d08f6ce8bdcc6e /src/server/game/Chat/ChatCommands | |
| parent | fa7e46a4f3f807b0682aba26c7993d142f842648 (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')
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 |
