2022-02-27 07:53:44 -05:00
|
|
|
#include <STDInclude.hpp>
|
2022-12-26 07:07:24 -05:00
|
|
|
#include "ClanTags.hpp"
|
|
|
|
#include "PlayerName.hpp"
|
2023-04-17 08:47:29 -04:00
|
|
|
#include "TextRenderer.hpp"
|
2017-01-19 16:23:59 -05:00
|
|
|
|
|
|
|
namespace Components
|
|
|
|
{
|
2022-07-08 12:42:09 -04:00
|
|
|
Dvar::Var PlayerName::sv_allowColoredNames;
|
|
|
|
|
2023-03-14 08:07:20 -04:00
|
|
|
void PlayerName::UserInfoCopy(char* buffer, const char* name, const int size)
|
2022-07-08 12:42:09 -04:00
|
|
|
{
|
|
|
|
if (!sv_allowColoredNames.get<bool>())
|
|
|
|
{
|
2023-03-14 08:07:20 -04:00
|
|
|
char nameBuffer[64]{};
|
2022-07-08 12:42:09 -04:00
|
|
|
TextRenderer::StripColors(name, nameBuffer, sizeof(nameBuffer));
|
|
|
|
TextRenderer::StripAllTextIcons(nameBuffer, buffer, size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TextRenderer::StripAllTextIcons(name, buffer, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string readablePlayerName(buffer);
|
2022-11-29 09:18:10 -05:00
|
|
|
Utils::String::Trim(readablePlayerName);
|
2022-07-08 12:42:09 -04:00
|
|
|
|
|
|
|
if (readablePlayerName.size() < 3)
|
|
|
|
{
|
|
|
|
strncpy(buffer, "Unknown Soldier", size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__declspec(naked) void PlayerName::ClientCleanName()
|
|
|
|
{
|
|
|
|
__asm
|
|
|
|
{
|
2023-03-14 08:07:20 -04:00
|
|
|
pushad
|
2022-07-08 12:42:09 -04:00
|
|
|
|
2023-03-14 08:07:20 -04:00
|
|
|
push [esp + 0x20 + 0x4] // length
|
2022-07-08 12:42:09 -04:00
|
|
|
push ecx // name
|
|
|
|
push edx // buffer
|
|
|
|
|
|
|
|
call UserInfoCopy
|
2023-03-14 08:07:20 -04:00
|
|
|
add esp, 0xC
|
2022-07-08 12:42:09 -04:00
|
|
|
|
2023-03-14 08:07:20 -04:00
|
|
|
popad
|
|
|
|
|
|
|
|
ret
|
2022-07-08 12:42:09 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-16 17:24:26 -04:00
|
|
|
int PlayerName::GetClientName(int localClientNum, int index, char* buf, int size)
|
2022-07-08 12:42:09 -04:00
|
|
|
{
|
2022-07-16 17:24:26 -04:00
|
|
|
const auto result = Game::CL_GetClientName(localClientNum, index, buf, size);
|
2022-07-08 12:42:09 -04:00
|
|
|
|
2022-07-16 17:24:26 -04:00
|
|
|
// Prepend clanName to username & remove the colors
|
|
|
|
strncpy_s(buf, size, TextRenderer::StripColors(ClanTags::GetClanTagWithName(index, buf)).data(), size);
|
2022-07-08 12:42:09 -04:00
|
|
|
|
2022-07-16 17:24:26 -04:00
|
|
|
return result;
|
2022-07-08 12:42:09 -04:00
|
|
|
}
|
2022-04-19 09:26:29 -04:00
|
|
|
|
2021-09-07 09:06:58 -04:00
|
|
|
char* PlayerName::CleanStrStub(char* string)
|
2017-01-19 16:23:59 -05:00
|
|
|
{
|
2023-03-14 08:07:20 -04:00
|
|
|
TextRenderer::StripColors(string, string, std::strlen(string) + 1);
|
2021-09-07 09:06:58 -04:00
|
|
|
return string;
|
2017-01-19 16:23:59 -05:00
|
|
|
}
|
|
|
|
|
2023-03-31 10:59:08 -04:00
|
|
|
bool PlayerName::IsBadChar(int c)
|
|
|
|
{
|
|
|
|
if (c == '%')
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == '~')
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c < 32 || c > 126)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-04-19 09:26:29 -04:00
|
|
|
bool PlayerName::CopyClientNameCheck(char* dest, const char* source, int size)
|
|
|
|
{
|
|
|
|
Utils::Hook::Call<void(char*, const char*, int)>(0x4D6F80)(dest, source, size); // I_strncpyz
|
|
|
|
|
|
|
|
auto i = 0;
|
|
|
|
while (i < size - 1 && dest[i] != '\0')
|
|
|
|
{
|
2023-03-14 08:07:20 -04:00
|
|
|
// Check for various illegal characters
|
2023-03-31 06:35:49 -04:00
|
|
|
const auto c = static_cast<unsigned char>(dest[i]);
|
|
|
|
if (IsBadChar(c))
|
2023-03-14 08:07:20 -04:00
|
|
|
{
|
|
|
|
return false;
|
2022-04-19 09:26:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-05-03 12:31:24 -04:00
|
|
|
void PlayerName::DropClient(Game::client_s* drop)
|
2022-04-19 09:26:29 -04:00
|
|
|
{
|
2023-03-31 10:59:08 -04:00
|
|
|
const auto* reason = "Invalid name detected";
|
|
|
|
Network::SendCommand(drop->header.netchan.remoteAddress, "error", reason);
|
|
|
|
Game::SV_DropClient(drop, reason, false);
|
|
|
|
}
|
2023-03-14 08:07:20 -04:00
|
|
|
|
2023-03-31 10:59:08 -04:00
|
|
|
__declspec(naked) void PlayerName::SV_UserinfoChangedStub()
|
|
|
|
{
|
2022-04-19 09:26:29 -04:00
|
|
|
__asm
|
|
|
|
{
|
|
|
|
call CopyClientNameCheck
|
|
|
|
test al, al
|
|
|
|
|
|
|
|
jnz returnSafe
|
|
|
|
|
|
|
|
pushad
|
|
|
|
|
|
|
|
push edi // drop
|
2023-03-31 10:59:08 -04:00
|
|
|
call DropClient
|
|
|
|
add esp, 0x4
|
2022-04-19 09:26:29 -04:00
|
|
|
|
|
|
|
popad
|
|
|
|
|
|
|
|
returnSafe:
|
|
|
|
push 0x401988
|
|
|
|
retn
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-19 16:23:59 -05:00
|
|
|
PlayerName::PlayerName()
|
|
|
|
{
|
2022-07-02 13:52:57 -04:00
|
|
|
sv_allowColoredNames = Dvar::Register<bool>("sv_allowColoredNames", true, Game::DVAR_NONE, "Allow colored names on the server");
|
2017-01-19 16:23:59 -05:00
|
|
|
|
2023-03-22 08:55:39 -04:00
|
|
|
// Disable SV_UpdateUserinfo_f to block changing the name ingame
|
2021-09-07 09:06:58 -04:00
|
|
|
Utils::Hook::Set<BYTE>(0x6258D0, 0xC3);
|
|
|
|
|
2022-04-19 09:26:29 -04:00
|
|
|
// Allow colored names ingame. Hook placed in ClientUserinfoChanged
|
2023-03-14 08:07:20 -04:00
|
|
|
Utils::Hook(0x445301, ClientCleanName, HOOK_CALL).install()->quick();
|
|
|
|
Utils::Hook(0x44533A, ClientCleanName, HOOK_CALL).install()->quick();
|
2021-09-07 09:06:58 -04:00
|
|
|
|
|
|
|
// Though, don't apply that to overhead names.
|
|
|
|
Utils::Hook(0x581932, GetClientName, HOOK_CALL).install()->quick();
|
|
|
|
|
|
|
|
// Patch I_CleanStr
|
|
|
|
Utils::Hook(0x4AD470, CleanStrStub, HOOK_JUMP).install()->quick();
|
2022-04-19 09:26:29 -04:00
|
|
|
|
|
|
|
// Detect invalid characters including '%' to prevent format string vulnerabilities.
|
|
|
|
// Kicks the player as soon as possible
|
|
|
|
Utils::Hook(0x401983, SV_UserinfoChangedStub, HOOK_JUMP).install()->quick();
|
2017-01-19 16:23:59 -05:00
|
|
|
}
|
|
|
|
}
|