Put name ban stuff into a separate file

Fix a bug when overlong names could be used to circumvent name bans. Add
tests for name bans.
This commit is contained in:
heinrich5991 2018-03-14 02:35:31 +01:00
parent d7f6cf2892
commit 11304661db
6 changed files with 84 additions and 40 deletions

View file

@ -917,6 +917,8 @@ endif()
set_glob(ENGINE_SERVER GLOB src/engine/server
authmanager.cpp
authmanager.h
name_ban.cpp
name_ban.h
register.cpp
register.h
server.cpp
@ -1102,6 +1104,7 @@ if(GTEST_FOUND OR DOWNLOAD_GTEST)
fs.cpp
git_revision.cpp
jobs.cpp
name_ban.cpp
str.cpp
strip_path_and_extension.cpp
teehistorian.cpp
@ -1111,6 +1114,8 @@ if(GTEST_FOUND OR DOWNLOAD_GTEST)
unix.cpp
)
set(TESTS_EXTRA
src/engine/server/name_ban.cpp
src/engine/server/name_ban.h
src/game/server/teehistorian.cpp
src/game/server/teehistorian.h
)

View file

@ -0,0 +1,24 @@
#include "name_ban.h"
CNameBan *IsNameBanned(const char *pName, CNameBan *pNameBans, int NumNameBans)
{
char aTrimmed[MAX_NAME_LENGTH];
str_copy(aTrimmed, str_utf8_skip_whitespaces(pName), sizeof(aTrimmed));
str_utf8_trim_right(aTrimmed);
int aSkeleton[MAX_NAME_SKELETON_LENGTH];
int SkeletonLength = str_utf8_to_skeleton(aTrimmed, aSkeleton, sizeof(aSkeleton) / sizeof(aSkeleton[0]));
int aBuffer[MAX_NAME_SKELETON_LENGTH * 2 + 2];
CNameBan *pResult = 0;
for(int i = 0; i < NumNameBans; i++)
{
CNameBan *pBan = &pNameBans[i];
int Distance = str_utf32_dist_buffer(aSkeleton, SkeletonLength, pBan->m_aSkeleton, pBan->m_SkeletonLength, aBuffer, sizeof(aBuffer) / sizeof(aBuffer[0]));
if(Distance <= pBan->m_Distance)
{
pResult = pBan;
}
}
return pResult;
}

View file

@ -0,0 +1,33 @@
#ifndef ENGINE_SERVER_NAME_BANS_H
#define ENGINE_SERVER_NAME_BANS_H
#include <base/system.h>
#include <engine/shared/protocol.h>
enum
{
MAX_NAME_SKELETON_LENGTH=MAX_NAME_LENGTH*4,
MAX_NAMEBAN_REASON_LENGTH=64
};
class CNameBan
{
public:
CNameBan() {}
CNameBan(const char *pName, int Distance, const char *pReason = "") :
m_Distance(Distance)
{
str_copy(m_aName, pName, sizeof(m_aName));
m_SkeletonLength = str_utf8_to_skeleton(m_aName, m_aSkeleton, sizeof(m_aSkeleton) / sizeof(m_aSkeleton[0]));
str_copy(m_aReason, pReason, sizeof(m_aReason));
}
char m_aName[MAX_NAME_LENGTH];
char m_aReason[MAX_NAMEBAN_REASON_LENGTH];
int m_aSkeleton[MAX_NAME_SKELETON_LENGTH];
int m_SkeletonLength;
int m_Distance;
};
CNameBan *IsNameBanned(const char *pName, CNameBan *pNameBans, int NumNameBans);
#endif // ENGINE_SERVER_NAME_BANS_H

View file

@ -343,8 +343,6 @@ int CServer::TrySetClientName(int ClientID, const char *pName)
return 0;
}
void CServer::SetClientName(int ClientID, const char *pName)
{
if(ClientID < 0 || ClientID >= MAX_CLIENTS || m_aClients[ClientID].m_State < CClient::STATE_READY)
@ -353,20 +351,7 @@ void CServer::SetClientName(int ClientID, const char *pName)
if(!pName)
return;
int Skeleton[MAX_NAME_SKELETON_LENGTH];
int SkeletonLength = str_utf8_to_skeleton(pName, Skeleton, sizeof(Skeleton) / sizeof(Skeleton[0]));
int Buffer[MAX_NAME_SKELETON_LENGTH * 2 + 2];
CNameBan *pBanned = 0;
for(int i = 0; i < m_aNameBans.size(); i++)
{
CNameBan *pBan = &m_aNameBans[i];
int Distance = str_utf32_dist_buffer(Skeleton, SkeletonLength, pBan->m_aSkeleton, pBan->m_SkeletonLength, Buffer, sizeof(Buffer) / sizeof(Buffer[0]));
if(Distance <= pBan->m_Distance)
{
pBanned = pBan;
}
}
CNameBan *pBanned = IsNameBanned(pName, m_aNameBans.base_ptr(), m_aNameBans.size());
if(pBanned)
{
if(m_aClients[ClientID].m_State == CClient::STATE_READY)

View file

@ -22,6 +22,7 @@
#include <base/tl/array.h>
#include "authmanager.h"
#include "name_ban.h"
#if defined (CONF_SQL)
#include "sql_connector.h"
@ -98,30 +99,6 @@ class CServer : public IServer
UNIXSOCKET m_ConnLoggingSocket;
#endif
enum
{
MAX_NAME_SKELETON_LENGTH=MAX_NAME_LENGTH*4,
MAX_REASON_LENGTH=64
};
class CNameBan
{
public:
CNameBan() {}
CNameBan(const char *pName, int Distance, const char *pReason) :
m_Distance(Distance)
{
str_copy(m_aName, pName, sizeof(m_aName));
m_SkeletonLength = str_utf8_to_skeleton(m_aName, m_aSkeleton, sizeof(m_aSkeleton) / sizeof(m_aSkeleton[0]));
str_copy(m_aReason, pReason, sizeof(m_aReason));
}
char m_aName[MAX_NAME_LENGTH];
char m_aReason[MAX_REASON_LENGTH];
int m_aSkeleton[MAX_NAME_SKELETON_LENGTH];
int m_SkeletonLength;
int m_Distance;
};
public:
class IGameServer *GameServer() { return m_pGameServer; }
class IConsole *Console() { return m_pConsole; }

20
src/test/name_ban.cpp Normal file
View file

@ -0,0 +1,20 @@
#include <gtest/gtest.h>
#include <engine/server/name_ban.h>
TEST(NameBan, Empty)
{
ASSERT_FALSE(IsNameBanned("", 0, 0));
ASSERT_FALSE(IsNameBanned("abc", 0, 0));
}
TEST(NameBan, Equality)
{
CNameBan Abc0("abc", 0);
ASSERT_TRUE(IsNameBanned("abc", &Abc0, 1));
ASSERT_TRUE(IsNameBanned(" abc", &Abc0, 1));
ASSERT_TRUE(IsNameBanned("abc ", &Abc0, 1));
ASSERT_TRUE(IsNameBanned("abc foo", &Abc0, 1)); // Maximum name length.
ASSERT_FALSE(IsNameBanned("def", &Abc0, 1));
ASSERT_FALSE(IsNameBanned("abcdef", &Abc0, 1));
}