diff --git a/amxmodx/amxmodx.h b/amxmodx/amxmodx.h index 296326bd4a..5763abda05 100755 --- a/amxmodx/amxmodx.h +++ b/amxmodx/amxmodx.h @@ -142,6 +142,7 @@ unsigned int UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen, bool caseSensitive); void UTIL_TrimLeft(char *buffer); void UTIL_TrimRight(char *buffer); +size_t UTIL_FilterEvilCharacters(const char *in, char *out, size_t out_maxlen, bool name_only); #define GET_PLAYER_POINTER(e) (&g_players[ENTINDEX(e)]) //#define GET_PLAYER_POINTER(e) (&g_players[(((int)e-g_edict_point)/sizeof(edict_t))]) diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index 9fd351339a..32f395f456 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -149,6 +149,7 @@ int FF_ClientConnectEx = -1; IFileSystem* g_FileSystem; HLTypeConversion TypeConversion; +server_static_t *ServerStatic; bool ColoredMenus(const char *ModName) { @@ -929,6 +930,27 @@ void C_ClientPutInServer_Post(edict_t *pEntity) RETURN_META(MRES_IGNORED); } +void C_ClientUserInfoChanged_Pre(edict_t *pEntity, char *infobuffer) +{ + if (ServerStatic) + { + auto clientIndex = TypeConversion.edict_to_id(pEntity); + + const char *oldName = ServerStatic->clients[clientIndex - 1].name; + const char *newName = INFOKEY_VALUE(infobuffer, "name"); + + if (oldName[0] == '\0' || strcmp(newName, oldName) != 0) + { + char safeNewName[MAX_NAME]; + UTIL_FilterEvilCharacters(newName, safeNewName, sizeof(safeNewName), true); + + SET_CLIENT_KEYVALUE(clientIndex, infobuffer, "name", safeNewName); + } + } + + RETURN_META(MRES_IGNORED); +} + void C_ClientUserInfoChanged_Post(edict_t *pEntity, char *infobuffer) { CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity); @@ -1009,6 +1031,19 @@ void C_ClientCommand(edict_t *pEntity) } } + if (!strcmp(cmd, "say") || !strcmp(cmd, "say_team")) + { + auto args = CMD_ARGS(); + + if (args && *args) + { + char safeMessage[128]; + auto length = UTIL_FilterEvilCharacters(args, safeMessage, sizeof(safeMessage), false); + + memcpy(const_cast(args), safeMessage, length + 1); + } + } + if (executeForwards(FF_ClientCommand, static_cast(pPlayer->index)) > 0) RETURN_META(MRES_SUPERCEDE); @@ -1586,15 +1621,37 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m g_CvarManager.CreateCvarHook(); - void *address = nullptr; - - if (CommonConfig && CommonConfig->GetMemSig("SV_DropClient", &address) && address) + if (CommonConfig) { - DropClientDetour = DETOUR_CREATE_STATIC_FIXED(SV_DropClient, address); - } - else - { - AMXXLOG_Log("client_disconnected forward has been disabled - check your gamedata files."); + void *address = nullptr; + +#if defined(KE_WINDOWS) + TypeDescription typeDesc; + + if (CommonConfig->GetOffset("svs", &typeDesc)) + { + auto base = *reinterpret_cast(reinterpret_cast(g_engfuncs.pfnGetCurrentPlayer) + typeDesc.fieldOffset); + ServerStatic = reinterpret_cast(base - 4); + } +#else + if (CommonConfig->GetMemSig("svs", &address)) + { + ServerStatic = reinterpret_cast(address); + } +#endif + else + { + AMXXLOG_Log("svs global variable is not available - check your gamedata files."); + } + + if (CommonConfig->GetMemSig("SV_DropClient", &address) && address) + { + DropClientDetour = DETOUR_CREATE_STATIC_FIXED(SV_DropClient, address); + } + else + { + AMXXLOG_Log("client_disconnected forward has been disabled - check your gamedata files."); + } } GET_IFACE("filesystem_stdio", g_FileSystem, FILESYSTEM_INTERFACE_VERSION); @@ -1739,6 +1796,7 @@ C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersi gFunctionTable.pfnInconsistentFile = C_InconsistentFile; gFunctionTable.pfnServerActivate = C_ServerActivate; gFunctionTable.pfnClientConnect = C_ClientConnect; + gFunctionTable.pfnClientUserInfoChanged = C_ClientUserInfoChanged_Pre; memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS)); diff --git a/amxmodx/util.cpp b/amxmodx/util.cpp index 7ca7bc816a..579fa16f92 100755 --- a/amxmodx/util.cpp +++ b/amxmodx/util.cpp @@ -717,4 +717,42 @@ void UTIL_TrimRight(char *buffer) } } } -} \ No newline at end of file +} + +size_t UTIL_FilterEvilCharacters(const char *in, char *out, size_t out_maxlen, bool name_only) +{ + auto remainChars = out_maxlen - 1; + auto n = 0; + + for (auto s = in; *s != '\0' && remainChars; ++s) + { + if (*s == '#' || + *s == '%' || + (name_only && + *s == '&' || + (n && out[n - 1] == '+' && static_cast(*s) > 0 && isalnum(*s)) + )) + { + if (remainChars < 3) + { + break; + } + + // http://unicode-table.com/blocks/halfwidth-and-fullwidth-forms/ + out[n++] = 0xEF; + out[n++] = 0xBC | (((*s - 0x20) & 0x40) >> 6); + out[n++] = 0x80 + ((*s - 0x20) & 0x3F); + + remainChars -= 3; + } + else + { + out[n++] = *s; + remainChars--; + } + } + + out[n] = '\0'; + + return n; +}