diff --git a/src/engine/server.h b/src/engine/server.h index 4bdc3041f..2502929e9 100644 --- a/src/engine/server.h +++ b/src/engine/server.h @@ -157,6 +157,7 @@ public: }; virtual void SetRconCID(int ClientID) = 0; virtual int GetAuthedState(int ClientID) = 0; + virtual const char *GetAuthName(int ClientID) = 0; virtual void Kick(int ClientID, const char *pReason) = 0; virtual void DemoRecorder_HandleAutoStart() = 0; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index c6b9fc930..de1beefeb 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -496,6 +496,16 @@ int CServer::GetAuthedState(int ClientID) return m_aClients[ClientID].m_Authed; } +const char *CServer::GetAuthName(int ClientID) +{ + int Key = m_aClients[ClientID].m_AuthKey; + if(Key == -1) + { + return 0; + } + return m_AuthManager.KeyIdent(Key); +} + int CServer::GetClientInfo(int ClientID, CClientInfo *pInfo) { dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid"); @@ -2588,6 +2598,8 @@ void CServer::LogoutClient(int ClientID, const char *pReason) m_aClients[ClientID].m_Authed = AUTHED_NO; m_aClients[ClientID].m_AuthKey = -1; + GameServer()->OnSetAuthed(ClientID, AUTHED_NO); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); } diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 598b323d7..c778deebf 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -239,6 +239,7 @@ public: void SetRconCID(int ClientID); int GetAuthedState(int ClientID); + const char *GetAuthName(int ClientID); void GetMapInfo(char *pMapName, int MapNameSize, int *pMapSize, int *pMapCrc); int GetClientInfo(int ClientID, CClientInfo *pInfo); void GetClientAddr(int ClientID, char *pAddrStr, int Size); diff --git a/src/engine/shared/teehistorian_ex_chunks.h b/src/engine/shared/teehistorian_ex_chunks.h index 2aa23e781..daf619039 100644 --- a/src/engine/shared/teehistorian_ex_chunks.h +++ b/src/engine/shared/teehistorian_ex_chunks.h @@ -1 +1,4 @@ UUID(TEEHISTORIAN_TEST, "teehistorian-test@ddnet.tw") +UUID(TEEHISTORIAN_AUTH_INIT, "teehistorian-auth-init@ddnet.tw") +UUID(TEEHISTORIAN_AUTH_LOGIN, "teehistorian-auth-login@ddnet.tw") +UUID(TEEHISTORIAN_AUTH_LOGOUT, "teehistorian-auth-logout@ddnet.tw") diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index c4beb6885..2504d4ba6 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -2599,6 +2599,15 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/) GameInfo.m_pMapName = aMapName; m_TeeHistorian.Reset(&GameInfo, TeeHistorianWrite, this); + + for(int i = 0; i < MAX_CLIENTS; i++) + { + int Level = Server()->GetAuthedState(i); + if(Level) + { + m_TeeHistorian.RecordAuthInitial(i, Level, Server()->GetAuthName(i)); + } + } } if(g_Config.m_SvSoloServer) @@ -3084,6 +3093,17 @@ void CGameContext::OnSetAuthed(int ClientID, int Level) Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "CGameContext", "Aborted vote by admin login."); } } + if(m_TeeHistorianActive) + { + if(Level) + { + m_TeeHistorian.RecordAuthLogin(ClientID, Level, Server()->GetAuthName(ClientID)); + } + else + { + m_TeeHistorian.RecordAuthLogout(ClientID); + } + } } void CGameContext::SendRecord(int ClientID) diff --git a/src/game/server/teehistorian.cpp b/src/game/server/teehistorian.cpp index 77d1d9f5f..744c53e2b 100644 --- a/src/game/server/teehistorian.cpp +++ b/src/game/server/teehistorian.cpp @@ -100,7 +100,8 @@ void CTeeHistorian::Reset(const CGameInfo *pGameInfo, WRITE_CALLBACK pfnWriteCal m_Tick = 0; m_LastWrittenTick = 0; - // `m_TickWritten` is initialized in `BeginTick` + // Tick 0 is implicit at the start, game starts as tick 1. + m_TickWritten = true; m_MaxClientID = MAX_CLIENTS; // `m_PrevMaxClientID` is initialized in `BeginTick` for(int i = 0; i < MAX_CLIENTS; i++) @@ -515,6 +516,11 @@ void CTeeHistorian::RecordConsoleCommand(int ClientID, int FlagMask, const char void CTeeHistorian::RecordTestExtra() { + if(m_Debug) + { + dbg_msg("teehistorian", "test"); + } + WriteExtra(UUID_TEEHISTORIAN_TEST, "", 0); } @@ -531,6 +537,52 @@ void CTeeHistorian::EndTick() m_State = STATE_BEFORE_TICK; } +void CTeeHistorian::RecordAuthInitial(int ClientID, int Level, const char *pAuthName) +{ + CPacker Buffer; + Buffer.Reset(); + Buffer.AddInt(ClientID); + Buffer.AddInt(Level); + Buffer.AddString(pAuthName, 0); + + if(m_Debug) + { + dbg_msg("teehistorian", "auth_init cid=%d level=%d auth_name=%s", ClientID, Level, pAuthName); + } + + WriteExtra(UUID_TEEHISTORIAN_AUTH_INIT, Buffer.Data(), Buffer.Size()); +} + +void CTeeHistorian::RecordAuthLogin(int ClientID, int Level, const char *pAuthName) +{ + CPacker Buffer; + Buffer.Reset(); + Buffer.AddInt(ClientID); + Buffer.AddInt(Level); + Buffer.AddString(pAuthName, 0); + + if(m_Debug) + { + dbg_msg("teehistorian", "auth_login cid=%d level=%d auth_name=%s", ClientID, Level, pAuthName); + } + + WriteExtra(UUID_TEEHISTORIAN_AUTH_LOGIN, Buffer.Data(), Buffer.Size()); +} + +void CTeeHistorian::RecordAuthLogout(int ClientID) +{ + CPacker Buffer; + Buffer.Reset(); + Buffer.AddInt(ClientID); + + if(m_Debug) + { + dbg_msg("teehistorian", "auth_logout cid=%d", ClientID); + } + + WriteExtra(UUID_TEEHISTORIAN_AUTH_LOGOUT, Buffer.Data(), Buffer.Size()); +} + void CTeeHistorian::Finish() { dbg_assert(m_State == STATE_START || m_State == STATE_INPUTS || m_State == STATE_BEFORE_ENDTICK || m_State == STATE_BEFORE_TICK, "invalid teehistorian state"); diff --git a/src/game/server/teehistorian.h b/src/game/server/teehistorian.h index 9ef6596f3..5fd47ff16 100644 --- a/src/game/server/teehistorian.h +++ b/src/game/server/teehistorian.h @@ -58,6 +58,10 @@ public: void EndTick(); + void RecordAuthInitial(int ClientID, int Level, const char *pAuthName); + void RecordAuthLogin(int ClientID, int Level, const char *pAuthName); + void RecordAuthLogout(int ClientID); + int m_Debug; // Possible values: 0, 1, 2. private: diff --git a/src/test/teehistorian.cpp b/src/test/teehistorian.cpp index 58a48d391..ce05043c3 100644 --- a/src/test/teehistorian.cpp +++ b/src/test/teehistorian.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -296,7 +297,7 @@ TEST_F(TeeHistorian, ExtraMessage) { const unsigned char EXPECTED[] = { 0x41, 0x00, // TICK_SKIP dt=0 - // EX uuid=6bb8ba88-0f0b-382e-8dae-dbf4052b8b7d data="" + // EX uuid=6bb8ba88-0f0b-382e-8dae-dbf4052b8b7d data_len=0 0x4a, 0x6b, 0xb8, 0xba, 0x88, 0x0f, 0x0b, 0x38, 0x2e, 0x8d, 0xae, 0xdb, 0xf4, 0x05, 0x2b, 0x8b, 0x7d, @@ -307,3 +308,46 @@ TEST_F(TeeHistorian, ExtraMessage) Finish(); Expect(EXPECTED, sizeof(EXPECTED)); } + +TEST_F(TeeHistorian, Auth) +{ + const unsigned char EXPECTED[] = { + // EX uuid=60daba5c-52c4-3aeb-b8ba-b2953fb55a17 data_len=16 + 0x4a, + 0x60, 0xda, 0xba, 0x5c, 0x52, 0xc4, 0x3a, 0xeb, + 0xb8, 0xba, 0xb2, 0x95, 0x3f, 0xb5, 0x5a, 0x17, + 0x10, + // (AUTH_INIT) cid=0 level=3 auth_name="default_admin" + 0x00, 0x03, 'd', 'e', 'f', 'a', 'u', 'l', + 't', '_', 'a', 'd', 'm', 'i', 'n', 0x00, + // EX uuid=37ecd3b8-9218-3bb9-a71b-a935b86f6a81 data_len=9 + 0x4a, + 0x37, 0xec, 0xd3, 0xb8, 0x92, 0x18, 0x3b, 0xb9, + 0xa7, 0x1b, 0xa9, 0x35, 0xb8, 0x6f, 0x6a, 0x81, + 0x09, + // (AUTH_LOGIN) cid=1 level=2 auth_name="foobar" + 0x01, 0x02, 'f', 'o', 'o', 'b', 'a', 'r', + 0x00, + // EX uuid=37ecd3b8-9218-3bb9-a71b-a935b86f6a81 data_len=7 + 0x4a, + 0x37, 0xec, 0xd3, 0xb8, 0x92, 0x18, 0x3b, 0xb9, + 0xa7, 0x1b, 0xa9, 0x35, 0xb8, 0x6f, 0x6a, 0x81, + 0x07, + // (AUTH_LOGIN) cid=1 level=2 auth_name="foobar" + 0x02, 0x01, 'h', 'e', 'l', 'p', 0x00, + // EX uuid=d4f5abe8-edd2-3fb9-abd8-1c8bb84f4a63 data_len=7 + 0x4a, + 0xd4, 0xf5, 0xab, 0xe8, 0xed, 0xd2, 0x3f, 0xb9, + 0xab, 0xd8, 0x1c, 0x8b, 0xb8, 0x4f, 0x4a, 0x63, + 0x01, + // (AUTH_LOGOUT) cid=1 + 0x01, + 0x40, // FINISH + }; + m_TH.RecordAuthInitial(0, IServer::AUTHED_ADMIN, "default_admin"); + m_TH.RecordAuthLogin(1, IServer::AUTHED_MOD, "foobar"); + m_TH.RecordAuthLogin(2, IServer::AUTHED_HELPER, "help"); + m_TH.RecordAuthLogout(1); + Finish(); + Expect(EXPECTED, sizeof(EXPECTED)); +}