mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/PacketIO: Add a validating string helper class for use in packet classes
(cherry picked from commit f2f47f774f)
This commit is contained in:
34
src/common/Utilities/Tuples.h
Normal file
34
src/common/Utilities/Tuples.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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 Tuples_h__
|
||||
#define Tuples_h__
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace Trinity
|
||||
{
|
||||
template <typename T, typename Tuple>
|
||||
struct has_type;
|
||||
|
||||
template <typename T, typename... Us>
|
||||
struct has_type<T, std::tuple<Us...>> : std::disjunction<std::is_same<T, Us>...>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
#endif // Tuples_h__
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -39,16 +39,16 @@ ByteBufferPositionException::ByteBufferPositionException(size_t pos, size_t size
|
||||
message().assign(ss.str());
|
||||
}
|
||||
|
||||
ByteBufferInvalidValueException::ByteBufferInvalidValueException(char const* type, size_t pos)
|
||||
ByteBufferInvalidValueException::ByteBufferInvalidValueException(char const* type, char const* value)
|
||||
{
|
||||
message().assign(Trinity::StringFormat("Invalid %s value found in ByteBuffer at pos " SZFMTD, type, pos));
|
||||
message().assign(Trinity::StringFormat("Invalid %s value (%s) found in ByteBuffer", type, value));
|
||||
}
|
||||
|
||||
ByteBuffer& ByteBuffer::operator>>(float& value)
|
||||
{
|
||||
value = read<float>();
|
||||
if (!std::isfinite(value))
|
||||
throw ByteBufferInvalidValueException("float", _rpos - sizeof(float));
|
||||
throw ByteBufferInvalidValueException("float", "infinity");
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ ByteBuffer& ByteBuffer::operator>>(double& value)
|
||||
{
|
||||
value = read<double>();
|
||||
if (!std::isfinite(value))
|
||||
throw ByteBufferInvalidValueException("double", _rpos - sizeof(double));
|
||||
throw ByteBufferInvalidValueException("double", "infinity");
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ std::string ByteBuffer::ReadCString(bool requireValidUtf8 /*= true*/)
|
||||
value += c;
|
||||
}
|
||||
if (requireValidUtf8 && !utf8::is_valid(value.begin(), value.end()))
|
||||
throw ByteBufferInvalidValueException("string", _rpos - value.length() - 1);
|
||||
throw ByteBufferInvalidValueException("string", value.c_str());
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ std::string ByteBuffer::ReadString(uint32 length, bool requireValidUtf8 /*= true
|
||||
std::string value(reinterpret_cast<char const*>(&_storage[_rpos]), length);
|
||||
_rpos += length;
|
||||
if (requireValidUtf8 && !utf8::is_valid(value.begin(), value.end()))
|
||||
throw ByteBufferInvalidValueException("string", _rpos - value.length() - 1);
|
||||
throw ByteBufferInvalidValueException("string", value.c_str());
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
class TC_SHARED_API ByteBufferInvalidValueException : public ByteBufferException
|
||||
{
|
||||
public:
|
||||
ByteBufferInvalidValueException(char const* type, size_t pos);
|
||||
ByteBufferInvalidValueException(char const* type, char const* value);
|
||||
|
||||
~ByteBufferInvalidValueException() noexcept = default;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user