diff options
author | Shauren <shauren.trinity@gmail.com> | 2020-03-18 23:20:11 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-12-23 23:55:58 +0100 |
commit | 3ebfa8cc645e5b35c8e6985ece3ef090858a9cb2 (patch) | |
tree | 66928fc63a6fbf82d61de23bde70a3b1de889be8 /src/server/game | |
parent | def97385ccb3e81ae8e5661479118d12cf0372de (diff) |
Core/PacketIO: Add a validating string helper class for use in packet classes
(cherry picked from commit f2f47f774f3d9c5da1a38b5f20cbfe59c2ff66af)
Diffstat (limited to 'src/server/game')
-rw-r--r-- | src/server/game/Server/Packets/PacketUtilities.cpp | 39 | ||||
-rw-r--r-- | src/server/game/Server/Packets/PacketUtilities.h | 96 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.cpp | 16 |
3 files changed, 151 insertions, 0 deletions
diff --git a/src/server/game/Server/Packets/PacketUtilities.cpp b/src/server/game/Server/Packets/PacketUtilities.cpp index 99f3decd0e1..426b3be9b8f 100644 --- a/src/server/game/Server/Packets/PacketUtilities.cpp +++ b/src/server/game/Server/Packets/PacketUtilities.cpp @@ -16,9 +16,48 @@ */ #include "PacketUtilities.h" +#include "Hyperlinks.h" #include "Errors.h" +#include <utf8.h> #include <sstream> +WorldPackets::InvalidStringValueException::InvalidStringValueException(std::string const& value) : ByteBufferInvalidValueException("string", value.c_str()) +{ +} + +WorldPackets::InvalidUtf8ValueException::InvalidUtf8ValueException(std::string const& value) : InvalidStringValueException(value) +{ +} + +WorldPackets::InvalidHyperlinkException::InvalidHyperlinkException(std::string const& value) : InvalidStringValueException(value) +{ +} + +WorldPackets::IllegalHyperlinkException::IllegalHyperlinkException(std::string const& value) : InvalidStringValueException(value) +{ +} + +bool WorldPackets::Strings::Utf8::Validate(std::string const& value) +{ + if (!utf8::is_valid(value.begin(), value.end())) + throw InvalidUtf8ValueException(value); + return true; +} + +bool WorldPackets::Strings::Hyperlinks::Validate(std::string const& value) +{ + if (!Trinity::Hyperlinks::CheckAllLinks(value)) + throw InvalidHyperlinkException(value); + return true; +} + +bool WorldPackets::Strings::NoHyperlinks::Validate(std::string const& value) +{ + if (value.find('|') != std::string::npos) + throw IllegalHyperlinkException(value); + return true; +} + WorldPackets::PacketArrayMaxCapacityException::PacketArrayMaxCapacityException(std::size_t requestedSize, std::size_t sizeLimit) { std::ostringstream builder; diff --git a/src/server/game/Server/Packets/PacketUtilities.h b/src/server/game/Server/Packets/PacketUtilities.h index 8b119cf1f61..3bb3443ff06 100644 --- a/src/server/game/Server/Packets/PacketUtilities.h +++ b/src/server/game/Server/Packets/PacketUtilities.h @@ -20,11 +20,107 @@ #include "ByteBuffer.h" #include "Duration.h" +#include "Tuples.h" #include <boost/container/static_vector.hpp> #include <ctime> namespace WorldPackets { + class InvalidStringValueException : public ByteBufferInvalidValueException + { + public: + InvalidStringValueException(std::string const& value); + + std::string const& GetInvalidValue() const { return _value; } + + private: + std::string _value; + }; + + class InvalidUtf8ValueException : public InvalidStringValueException + { + public: + InvalidUtf8ValueException(std::string const& value); + }; + + class InvalidHyperlinkException : public InvalidStringValueException + { + public: + InvalidHyperlinkException(std::string const& value); + }; + + class IllegalHyperlinkException : public InvalidStringValueException + { + public: + IllegalHyperlinkException(std::string const& value); + }; + + namespace Strings + { + struct RawBytes { static bool Validate(std::string const& /*value*/) { return true; } }; + template<std::size_t MaxBytesWithoutNullTerminator> + struct ByteSize { static bool Validate(std::string const& value) { return value.size() <= MaxBytesWithoutNullTerminator; } }; + struct Utf8 { static bool Validate(std::string const& value); }; + struct Hyperlinks { static bool Validate(std::string const& value); }; + struct NoHyperlinks { static bool Validate(std::string const& value); }; + } + + /** + * Utility class for automated prevention of invalid strings in client packets + */ + template<std::size_t MaxBytesWithoutNullTerminator, typename... Validators> + class String + { + using ValidatorList = std::conditional_t<!Trinity::has_type<Strings::RawBytes, std::tuple<Validators...>>::value, + std::tuple<Strings::ByteSize<MaxBytesWithoutNullTerminator>, Strings::Utf8, Validators...>, + std::tuple<Strings::ByteSize<MaxBytesWithoutNullTerminator>, Validators...>>; + + public: + bool empty() const { return _storage.empty(); } + char const* c_str() const { return _storage.c_str(); } + + operator std::string&() { return _storage; } + operator std::string const&() const { return _storage; } + + std::string&& Move() { return std::move(_storage); } + + friend ByteBuffer& operator>>(ByteBuffer& data, String& value) + { + std::string string = data.ReadCString(false); + Validate(string); + value._storage = std::move(string); + return data; + } + + String& operator=(std::string const& value) + { + Validate(value); + _storage = value; + return *this; + } + + String& operator=(std::string&& value) + { + Validate(value); + _storage = std::move(value); + return *this; + } + + private: + static bool Validate(std::string const& value) + { + return ValidateNth(value, std::make_index_sequence<std::tuple_size_v<ValidatorList>>{}); + } + + template<std::size_t... indexes> + static bool ValidateNth(std::string const& value, std::index_sequence<indexes...>) + { + return (std::tuple_element_t<indexes, ValidatorList>::Validate(value) && ...); + } + + std::string _storage; + }; + class PacketArrayMaxCapacityException : public ByteBufferException { public: diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 3a14cf48785..942b29be1dc 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -425,6 +425,22 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) break; } } + catch (WorldPackets::InvalidHyperlinkException const& ihe) + { + TC_LOG_ERROR("network", "%s sent %s with an invalid link:\n%s", GetPlayerInfo().c_str(), + GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), ihe.GetInvalidValue().c_str()); + + if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK)) + KickPlayer(); + } + catch (WorldPackets::IllegalHyperlinkException const& ihe) + { + TC_LOG_ERROR("network", "%s sent %s which illegally contained a hyperlink:\n%s", GetPlayerInfo().c_str(), + GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), ihe.GetInvalidValue().c_str()); + + if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK)) + KickPlayer(); + } catch (WorldPackets::PacketArrayMaxCapacityException const& pamce) { TC_LOG_ERROR("network", "PacketArrayMaxCapacityException: %s while parsing %s from %s.", |