improved chat msg spam protection

This commit is contained in:
oy 2013-04-01 20:30:58 +02:00
parent 75cdc0a769
commit f0e09f50d9
10 changed files with 119 additions and 26 deletions

View file

@ -231,7 +231,7 @@ Messages = [
NetMessage("Sv_Chat", [
NetIntRange("m_Team", 'TEAM_SPECTATORS', 'TEAM_BLUE'),
NetIntRange("m_ClientID", -1, 'MAX_CLIENTS-1'),
NetString("m_pMessage"),
NetStringStrict("m_pMessage"),
]),
NetMessage("Sv_KillMsg", [
@ -294,7 +294,7 @@ Messages = [
### Client messages
NetMessage("Cl_Say", [
NetBool("m_Team"),
NetString("m_pMessage"),
NetStringStrict("m_pMessage"),
]),
NetMessage("Cl_SetTeam", [

View file

@ -1829,6 +1829,27 @@ int str_toint(const char *str) { return atoi(str); }
float str_tofloat(const char *str) { return atof(str); }
char *str_utf8_skip_whitespaces(char *str)
{
char *str_old;
int code;
while(*str)
{
str_old = str;
code = str_utf8_decode(&str);
// check if unicode is not empty
if(code > 0x20 && code != 0xA0 && code != 0x034F && (code < 0x2000 || code > 0x200F) && (code < 0x2028 || code > 0x202F) &&
(code < 0x205F || code > 0x2064) && (code < 0x206A || code > 0x206F) && (code < 0xFE00 || code > 0xFE0F) &&
code != 0xFEFF && (code < 0xFFF9 || code > 0xFFFC))
{
return str_old;
}
}
return str;
}
static int str_utf8_isstart(char c)
{

View file

@ -1213,6 +1213,7 @@ unsigned str_quickhash(const char *str);
*/
void gui_messagebox(const char *title, const char *message);
char *str_utf8_skip_whitespaces(char *str);
/*
Function: str_utf8_rewind

View file

@ -136,7 +136,7 @@ const char *CUnpacker::GetString(int SanitizeType)
str_sanitize(pPtr);
else if(SanitizeType&SANITIZE_CC)
str_sanitize_cc(pPtr);
return SanitizeType&SKIP_START_WHITESPACES ? str_skip_whitespaces(pPtr) : pPtr;
return SanitizeType&SKIP_START_WHITESPACES ? str_utf8_skip_whitespaces(pPtr) : pPtr;
}
const unsigned char *CUnpacker::GetRaw(int Size)

View file

@ -282,6 +282,34 @@ void CChat::AddLine(int ClientID, int Team, const char *pLine)
(m_pClient->m_Snap.m_LocalClientID != ClientID && g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[ClientID].m_Friend))))
return;
// trim right and set maximum length to 128 utf8-characters
int Length = 0;
const char *pStr = pLine;
const char *pEnd = 0;
while(*pStr)
{
const char *pStrOld = pStr;
int Code = str_utf8_decode(&pStr);
// check if unicode is not empty
if(Code > 0x20 && Code != 0xA0 && Code != 0x034F && (Code < 0x2000 || Code > 0x200F) && (Code < 0x2028 || Code > 0x202F) &&
(Code < 0x205F || Code > 0x2064) && (Code < 0x206A || Code > 0x206F) && (Code < 0xFE00 || Code > 0xFE0F) &&
Code != 0xFEFF && (Code < 0xFFF9 || Code > 0xFFFC))
{
pEnd = 0;
}
else if(pEnd == 0)
pEnd = pStrOld;
if(++Length >= 127)
{
*(const_cast<char *>(pStr)) = 0;
break;
}
}
if(pEnd != 0)
*(const_cast<char *>(pEnd)) = 0;
bool Highlighted = false;
char *p = const_cast<char*>(pLine);
while(*p)

View file

@ -243,7 +243,8 @@ int CMenus::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrS
for(int i = 0; i < m_NumInputEvents; i++)
{
Len = str_length(pStr);
ReturnValue |= CLineInput::Manipulate(m_aInputEvents[i], pStr, StrSize, &Len, &s_AtIndex);
int NumChars = Len;
ReturnValue |= CLineInput::Manipulate(m_aInputEvents[i], pStr, StrSize, StrSize, &Len, &s_AtIndex, &NumChars);
}
}

View file

@ -13,6 +13,7 @@ void CLineInput::Clear()
mem_zero(m_Str, sizeof(m_Str));
m_Len = 0;
m_CursorPos = 0;
m_NumChars = 0;
}
void CLineInput::Set(const char *pString)
@ -20,10 +21,18 @@ void CLineInput::Set(const char *pString)
str_copy(m_Str, pString, sizeof(m_Str));
m_Len = str_length(m_Str);
m_CursorPos = m_Len;
m_NumChars = 0;
int Offset = 0;
while(pString[Offset])
{
Offset = str_utf8_forward(pString, Offset);
++m_NumChars;
}
}
bool CLineInput::Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int *pStrLenPtr, int *pCursorPosPtr)
bool CLineInput::Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int StrMaxChars, int *pStrLenPtr, int *pCursorPosPtr, int *pNumCharsPtr)
{
int NumChars = *pNumCharsPtr;
int CursorPos = *pCursorPosPtr;
int Len = *pStrLenPtr;
bool Changes = false;
@ -40,13 +49,15 @@ bool CLineInput::Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int *p
char Tmp[8];
int CharSize = str_utf8_encode(Tmp, Code);
if (Len < StrMaxSize - CharSize && CursorPos < StrMaxSize - CharSize)
if (Len < StrMaxSize - CharSize && CursorPos < StrMaxSize - CharSize && NumChars < StrMaxChars)
{
mem_move(pStr + CursorPos + CharSize, pStr + CursorPos, Len-CursorPos+1); // +1 == null term
for(int i = 0; i < CharSize; i++)
pStr[CursorPos+i] = Tmp[i];
CursorPos += CharSize;
Len += CharSize;
if(CharSize > 0)
++NumChars;
Changes = true;
}
}
@ -60,6 +71,8 @@ bool CLineInput::Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int *p
mem_move(pStr+NewCursorPos, pStr+CursorPos, Len - NewCursorPos - CharSize + 1); // +1 == null term
CursorPos = NewCursorPos;
Len -= CharSize;
if(CharSize > 0)
--NumChars;
Changes = true;
}
else if (k == KEY_DELETE && CursorPos < Len)
@ -68,6 +81,8 @@ bool CLineInput::Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int *p
int CharSize = p-CursorPos;
mem_move(pStr + CursorPos, pStr + CursorPos + CharSize, Len - CursorPos - CharSize + 1); // +1 == null term
Len -= CharSize;
if(CharSize > 0)
--NumChars;
Changes = true;
}
else if (k == KEY_LEFT && CursorPos > 0)
@ -80,6 +95,7 @@ bool CLineInput::Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int *p
CursorPos = Len;
}
*pNumCharsPtr = NumChars;
*pCursorPosPtr = CursorPos;
*pStrLenPtr = Len;
@ -88,5 +104,5 @@ bool CLineInput::Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int *p
void CLineInput::ProcessInput(IInput::CEvent e)
{
Manipulate(e, m_Str, sizeof(m_Str), &m_Len, &m_CursorPos);
Manipulate(e, m_Str, MAX_SIZE, MAX_CHARS, &m_Len, &m_CursorPos, &m_NumChars);
}

View file

@ -8,11 +8,17 @@
// line input helter
class CLineInput
{
char m_Str[256];
enum
{
MAX_SIZE=512,
MAX_CHARS=MAX_SIZE/4,
};
char m_Str[MAX_SIZE];
int m_Len;
int m_CursorPos;
int m_NumChars;
public:
static bool Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int *pStrLenPtr, int *pCursorPosPtr);
static bool Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int StrMaxChars, int *pStrLenPtr, int *pCursorPosPtr, int *pNumCharsPtr);
class CCallback
{

View file

@ -277,7 +277,8 @@ int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned Str
for(int i = 0; i < Input()->NumEvents(); i++)
{
Len = str_length(pStr);
ReturnValue |= CLineInput::Manipulate(Input()->GetEvent(i), pStr, StrSize, &Len, &s_AtIndex);
int NumChars = Len;
ReturnValue |= CLineInput::Manipulate(Input()->GetEvent(i), pStr, StrSize, StrSize, &Len, &s_AtIndex, &NumChars);
}
}

View file

@ -612,26 +612,45 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
{
if(MsgID == NETMSGTYPE_CL_SAY)
{
CNetMsg_Cl_Say *pMsg = (CNetMsg_Cl_Say *)pRawMsg;
int Team = pMsg->m_Team;
if(Team)
Team = pPlayer->GetTeam();
else
Team = CGameContext::CHAT_ALL;
if(g_Config.m_SvSpamprotection && pPlayer->m_LastChat && pPlayer->m_LastChat+Server()->TickSpeed() > Server()->Tick())
return;
pPlayer->m_LastChat = Server()->Tick();
CNetMsg_Cl_Say *pMsg = (CNetMsg_Cl_Say *)pRawMsg;
int Team = pMsg->m_Team ? pPlayer->GetTeam() : CGameContext::CHAT_ALL;
// trim right and set maximum length to 128 utf8-characters
int Length = 0;
const char *p = pMsg->m_pMessage;
const char *pEnd = 0;
while(*p)
{
const char *pStrOld = p;
int Code = str_utf8_decode(&p);
// check for invalid chars
unsigned char *pMessage = (unsigned char *)pMsg->m_pMessage;
while (*pMessage)
{
if(*pMessage < 32)
*pMessage = ' ';
pMessage++;
}
// check if unicode is not empty
if(Code > 0x20 && Code != 0xA0 && Code != 0x034F && (Code < 0x2000 || Code > 0x200F) && (Code < 0x2028 || Code > 0x202F) &&
(Code < 0x205F || Code > 0x2064) && (Code < 0x206A || Code > 0x206F) && (Code < 0xFE00 || Code > 0xFE0F) &&
Code != 0xFEFF && (Code < 0xFFF9 || Code > 0xFFFC))
{
pEnd = 0;
}
else if(pEnd == 0)
pEnd = pStrOld;
if(++Length >= 127)
{
*(const_cast<char *>(p)) = 0;
break;
}
}
if(pEnd != 0)
*(const_cast<char *>(pEnd)) = 0;
// drop empty and autocreated spam messages (more than 16 characters per second)
if(Length == 0 || (g_Config.m_SvSpamprotection && pPlayer->m_LastChat && pPlayer->m_LastChat+Server()->TickSpeed()*((15+Length)/16) > Server()->Tick()))
return;
pPlayer->m_LastChat = Server()->Tick();
SendChat(ClientID, Team, pMsg->m_pMessage);
}