diff options
| author | Shauren <shauren.trinity@gmail.com> | 2020-03-18 23:20:11 +0100 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2020-03-18 23:20:11 +0100 |
| commit | f2f47f774f3d9c5da1a38b5f20cbfe59c2ff66af (patch) | |
| tree | 8e270920bf5665b255d3ba982528a021689517f1 /src/server/game | |
| parent | 9d77b2be3b72810db1f12b6fde5e39583d521bc9 (diff) | |
Core/PacketIO: Add a validating string helper class for use in packet classes
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 | 81 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSession.cpp | 16 |
3 files changed, 136 insertions, 0 deletions
diff --git a/src/server/game/Server/Packets/PacketUtilities.cpp b/src/server/game/Server/Packets/PacketUtilities.cpp index 96fc5298e21..862c643013c 100644 --- a/src/server/game/Server/Packets/PacketUtilities.cpp +++ b/src/server/game/Server/Packets/PacketUtilities.cpp @@ -16,10 +16,49 @@ */ #include "PacketUtilities.h" +#include "Hyperlinks.h" #include "Errors.h" +#include <utf8.h> #include <sstream> #include <array> +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 1ed6efb12b0..9ff6b42bed2 100644 --- a/src/server/game/Server/Packets/PacketUtilities.h +++ b/src/server/game/Server/Packets/PacketUtilities.h @@ -19,9 +19,90 @@ #define PacketUtilities_h__ #include "ByteBuffer.h" +#include "Tuples.h" 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) + { + value._storage = data.ReadCString(false); + value.Validate(); + return data; + } + + private: + bool Validate() const + { + return ValidateNth(std::make_index_sequence<std::tuple_size_v<ValidatorList>>{}); + } + + template<std::size_t... indexes> + bool ValidateNth(std::index_sequence<indexes...>) const + { + return (std::tuple_element_t<indexes, ValidatorList>::Validate(_storage) && ...); + } + + 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 d38516491e4..2fbe68285e9 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -371,6 +371,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.", |
