diff --git a/Server/mods/deathmatch/logic/CAccount.cpp b/Server/mods/deathmatch/logic/CAccount.cpp index 90e52e5696..73934a9f8b 100644 --- a/Server/mods/deathmatch/logic/CAccount.cpp +++ b/Server/mods/deathmatch/logic/CAccount.cpp @@ -210,7 +210,7 @@ void CAccount::EnsureLoadedSerialUsage() } } -bool CAccount::HasLoadedSerialUsage() +bool CAccount::HasLoadedSerialUsage() const { return m_bLoadedSerialUsage; } @@ -238,11 +238,7 @@ CAccount::SSerialUsage* CAccount::GetSerialUsage(const SString& strSerial) bool CAccount::IsSerialAuthorized(const SString& strSerial) { SSerialUsage* pInfo = GetSerialUsage(strSerial); - if (pInfo) - { - return pInfo->IsAuthorized(); - } - return false; + return pInfo ? pInfo->IsAuthorized() : false; } // @@ -265,17 +261,13 @@ bool CAccount::IsIpAuthorized(const SString& strIp) bool CAccount::AuthorizeSerial(const SString& strSerial, const SString& strWho) { SSerialUsage* pInfo = GetSerialUsage(strSerial); - if (pInfo) - { - if (!pInfo->IsAuthorized()) - { - pInfo->tAuthDate = time(nullptr); - pInfo->strAuthWho = strWho; - m_pManager->MarkAsChanged(this); - return true; - } - } - return false; + if (!pInfo || pInfo->IsAuthorized()) + return false; + + pInfo->tAuthDate = time(nullptr); + pInfo->strAuthWho = strWho; + m_pManager->MarkAsChanged(this); + return true; } // @@ -320,29 +312,28 @@ void CAccount::RemoveUnauthorizedSerials() bool CAccount::AddSerialForAuthorization(const SString& strSerial, const SString& strIp) { SSerialUsage* pInfo = GetSerialUsage(strSerial); - if (!pInfo) - { - // Only one new serial at a time, so remove all other unauthorized serials for this account - RemoveUnauthorizedSerials(); + if (pInfo) + return false; - SSerialUsage info; - info.strSerial = strSerial; - info.strAddedIp = strIp; - info.tAddedDate = time(nullptr); - info.tAuthDate = 0; - info.tLastLoginDate = 0; - info.tLastLoginHttpDate = 0; + // Only one new serial at a time, so remove all other unauthorized serials for this account + RemoveUnauthorizedSerials(); - // First one doesn't require authorization - if (m_SerialUsageList.size() == 0) - { - info.tAuthDate = time(nullptr); - } - m_SerialUsageList.push_back(info); - m_pManager->MarkAsChanged(this); - return true; + SSerialUsage info; + info.strSerial = strSerial; + info.strAddedIp = strIp; + info.tAddedDate = time(nullptr); + info.tAuthDate = 0; + info.tLastLoginDate = 0; + info.tLastLoginHttpDate = 0; + + // First one doesn't require authorization + if (m_SerialUsageList.size() == 0) + { + info.tAuthDate = time(nullptr); } - return false; + m_SerialUsageList.push_back(info); + m_pManager->MarkAsChanged(this); + return true; } // @@ -372,10 +363,10 @@ void CAccount::OnLoginHttpSuccess(const SString& strIp) EnsureLoadedSerialUsage(); for (auto& info : m_SerialUsageList) { - if (info.strLastLoginIp == strIp && info.IsAuthorized()) - { - info.tLastLoginHttpDate = time(nullptr); - m_pManager->MarkAsChanged(this); - } + if (info.strLastLoginIp != strIp || !info.IsAuthorized()) + continue; + + info.tLastLoginHttpDate = time(nullptr); + m_pManager->MarkAsChanged(this); } } diff --git a/Server/mods/deathmatch/logic/CAccount.h b/Server/mods/deathmatch/logic/CAccount.h index b2ea2f58e9..363dd57d98 100644 --- a/Server/mods/deathmatch/logic/CAccount.h +++ b/Server/mods/deathmatch/logic/CAccount.h @@ -71,25 +71,27 @@ class CAccount const std::string& strIP = "", const std::string& strSerial = "", const SString& strHttpPassAppend = ""); ~CAccount(); - bool IsRegistered() { return m_AccountType != EAccountType::Guest; } - bool IsConsoleAccount() { return m_AccountType == EAccountType::Console; } + bool IsRegistered() const { return m_AccountType != EAccountType::Guest; } + bool IsConsoleAccount() const { return m_AccountType == EAccountType::Console; } void OnLoginSuccess(const SString& strSerial, const SString& strIp); void OnLoginHttpSuccess(const SString& strIp); - const SString& GetName() { return m_strName; } + const SString& GetName() const { return m_strName; } void SetName(const std::string& strName); + const EAccountType GetType() const { return m_AccountType; } + void SetPassword(const SString& strPassword); bool IsPassword(const SString& strPassword, bool* pbUsedHttpPassAppend = nullptr); SString GetPasswordHash(); - const SString& GetHttpPassAppend() { return m_strHttpPassAppend; } + const SString& GetHttpPassAppend() const { return m_strHttpPassAppend; } void SetHttpPassAppend(const SString& strHttpPassAppend); - const std::string& GetIP() { return m_strIP; } - const std::string& GetSerial() { return m_strSerial; } - int GetID() { return m_iUserID; } + const std::string& GetIP() const { return m_strIP; } + const std::string& GetSerial() const { return m_strSerial; } + const int GetID() const { return m_iUserID; } - bool HasLoadedSerialUsage(); + bool HasLoadedSerialUsage() const; void EnsureLoadedSerialUsage(); std::vector& GetSerialUsageList(); SSerialUsage* GetSerialUsage(const SString& strSerial); @@ -100,19 +102,19 @@ class CAccount bool RemoveSerial(const SString& strSerial); void RemoveUnauthorizedSerials(); - CClient* GetClient() { return m_pClient; } + CClient* GetClient() const { return m_pClient; } void SetClient(CClient* pClient); void SetChanged(bool bChanged) { m_bChanged = bChanged; } - bool HasChanged() { return m_bChanged; } + bool HasChanged() const { return m_bChanged; } uint GetScriptID() const { return m_uiScriptID; } std::shared_ptr GetData(const std::string& strKey); bool SetData(const std::string& strKey, const std::string& strValue, int iType); bool HasData(const std::string& strKey); void RemoveData(const std::string& strKey); - std::map::iterator DataBegin() { return m_Data.begin(); } - std::map::iterator DataEnd() { return m_Data.end(); } + std::map::iterator begin() { return m_Data.begin(); } + std::map::iterator end() { return m_Data.end(); } protected: CAccountData* GetDataPointer(const std::string& strKey); @@ -147,9 +149,9 @@ class CAccountData m_iType = iType; } - const std::string& GetKey() { return m_strKey; } - const std::string& GetStrValue() { return m_strValue; } - int GetType() { return m_iType; } + const std::string& GetKey() const { return m_strKey; } + const std::string& GetStrValue() const { return m_strValue; } + int GetType() const { return m_iType; } void SetStrValue(const std::string& strValue) { m_strValue = strValue; } void SetType(int iType) { m_iType = iType; } diff --git a/Server/mods/deathmatch/logic/CAccountManager.cpp b/Server/mods/deathmatch/logic/CAccountManager.cpp index 99037771a0..cae195a3a3 100644 --- a/Server/mods/deathmatch/logic/CAccountManager.cpp +++ b/Server/mods/deathmatch/logic/CAccountManager.cpp @@ -18,6 +18,7 @@ #include "CIdArray.h" #include "CAccessControlListManager.h" #include "Utils.h" +#include "CMapManager.h" CAccountManager::CAccountManager(const SString& strDbPathFilename) : m_AccountProtect(6, 30000, 60000 * 1) // Max of 6 attempts per 30 seconds, then 1 minute ignore @@ -778,10 +779,9 @@ bool CAccountManager::CopyAccountData(CAccount* pFromAccount, CAccount* pToAccou if (!pFromAccount->IsRegistered()) // is not registered account, retrieve data from memory { - std::map::iterator iter = pFromAccount->DataBegin(); - for (; iter != pFromAccount->DataEnd(); iter++) + for (const auto& iter : *pFromAccount) { - MapSet(copiedData, iter->second.GetKey(), CAccountData(iter->second.GetKey(), iter->second.GetStrValue(), iter->second.GetType())); + MapSet(copiedData, iter.second.GetKey(), CAccountData(iter.second.GetKey(), iter.second.GetStrValue(), iter.second.GetType())); } } else // is registered account, retrieve from database @@ -850,31 +850,30 @@ bool CAccountManager::GetAllAccountData(CAccount* pAccount, lua_State* pLua) { if (!pAccount->IsRegistered()) { - std::map::iterator iter = pAccount->DataBegin(); - for (; iter != pAccount->DataEnd(); iter++) + for (const auto& iter : *pAccount) { - if (iter->second.GetType() == LUA_TNIL) + if (iter.second.GetType() == LUA_TNIL) { - lua_pushstring(pLua, iter->second.GetKey().c_str()); + lua_pushstring(pLua, iter.second.GetKey().c_str()); lua_pushnil(pLua); lua_settable(pLua, -3); } - if (iter->second.GetType() == LUA_TBOOLEAN) + if (iter.second.GetType() == LUA_TBOOLEAN) { - lua_pushstring(pLua, iter->second.GetKey().c_str()); - lua_pushboolean(pLua, iter->second.GetStrValue() == "true" ? true : false); + lua_pushstring(pLua, iter.second.GetKey().c_str()); + lua_pushboolean(pLua, iter.second.GetStrValue() == "true"); lua_settable(pLua, -3); } - if (iter->second.GetType() == LUA_TNUMBER) + if (iter.second.GetType() == LUA_TNUMBER) { - lua_pushstring(pLua, iter->second.GetKey().c_str()); - lua_pushnumber(pLua, strtod(iter->second.GetStrValue().c_str(), NULL)); + lua_pushstring(pLua, iter.second.GetKey().c_str()); + lua_pushnumber(pLua, strtod(iter.second.GetStrValue().c_str(), NULL)); lua_settable(pLua, -3); } else { - lua_pushstring(pLua, iter->second.GetKey().c_str()); - lua_pushstring(pLua, iter->second.GetStrValue().c_str()); + lua_pushstring(pLua, iter.second.GetKey().c_str()); + lua_pushstring(pLua, iter.second.GetStrValue().c_str()); lua_settable(pLua, -3); } } @@ -891,46 +890,44 @@ bool CAccountManager::GetAllAccountData(CAccount* pAccount, lua_State* pLua) m_pDatabaseManager->QueryWithResultf(m_hDbConnection, &result, "SELECT key,value,type from userdata where userid=?", SQLITE_INTEGER, iUserID); // Do we have any results? - if (result->nRows > 0) + if (result->nRows <= 0) + return false; + + // Loop through until i is the same as the number of rows + for (const auto& row : result->Data) { - // Loop through until i is the same as the number of rows - for (CRegistryResultIterator iter = result->begin(); iter != result->end(); ++iter) + // Get our key + strKey = reinterpret_cast(row[0].pVal); + // Get our type + int iType = static_cast(row[2].nVal); + // Account data is stored as text so we don't need to check what type it is just return it + if (iType == LUA_TNIL) { - const CRegistryResultRow& row = *iter; - // Get our key - strKey = (const char*)row[0].pVal; - // Get our type - int iType = static_cast(row[2].nVal); - // Account data is stored as text so we don't need to check what type it is just return it - if (iType == LUA_TNIL) - { - lua_pushstring(pLua, strKey); - lua_pushnil(pLua); - lua_settable(pLua, -3); - } - if (iType == LUA_TBOOLEAN) - { - SString strResult = (const char*)row[1].pVal; - lua_pushstring(pLua, strKey); - lua_pushboolean(pLua, strResult == "true" ? true : false); - lua_settable(pLua, -3); - } - if (iType == LUA_TNUMBER) - { - lua_pushstring(pLua, strKey); - lua_pushnumber(pLua, strtod((const char*)row[1].pVal, NULL)); - lua_settable(pLua, -3); - } - else - { - lua_pushstring(pLua, strKey); - lua_pushstring(pLua, ((const char*)row[1].pVal)); - lua_settable(pLua, -3); - } + lua_pushstring(pLua, strKey); + lua_pushnil(pLua); + lua_settable(pLua, -3); + } + if (iType == LUA_TBOOLEAN) + { + SString strResult = (const char*)row[1].pVal; + lua_pushstring(pLua, strKey); + lua_pushboolean(pLua, strResult == "true"); + lua_settable(pLua, -3); + } + if (iType == LUA_TNUMBER) + { + lua_pushstring(pLua, strKey); + lua_pushnumber(pLua, strtod((const char*)row[1].pVal, NULL)); + lua_settable(pLua, -3); + } + else + { + lua_pushstring(pLua, strKey); + lua_pushstring(pLua, ((const char*)row[1].pVal)); + lua_settable(pLua, -3); } - return true; } - return false; + return true; } void CAccountManager::GetAccountsBySerial(const SString& strSerial, std::vector& outAccounts) @@ -939,10 +936,8 @@ void CAccountManager::GetAccountsBySerial(const SString& strSerial, std::vector< CRegistryResult result; m_pDatabaseManager->QueryWithResultf(m_hDbConnection, &result, "SELECT name FROM accounts WHERE serial = ?", SQLITE_TEXT, strSerial.c_str()); - for (CRegistryResultIterator iter = result->begin(); iter != result->end(); ++iter) + for (const auto& row : result->Data) { - const CRegistryResultRow& row = *iter; - CAccount* pAccount = Get((const char*)row[0].pVal); if (pAccount) outAccounts.push_back(pAccount); @@ -955,10 +950,8 @@ void CAccountManager::GetAccountsByIP(const SString& strIP, std::vectorQueryWithResultf(m_hDbConnection, &result, "SELECT name FROM accounts WHERE ip = ?", SQLITE_TEXT, strIP.c_str()); - for (CRegistryResultIterator iter = result->begin(); iter != result->end(); ++iter) + for (const auto& row : result->Data) { - const CRegistryResultRow& row = *iter; - CAccount* pAccount = Get((const char*)row[0].pVal); if (pAccount) outAccounts.push_back(pAccount); @@ -970,10 +963,8 @@ CAccount* CAccountManager::GetAccountByID(int ID) CRegistryResult result; m_pDatabaseManager->QueryWithResultf(m_hDbConnection, &result, "SELECT name FROM accounts WHERE id = ?", SQLITE_INTEGER, ID); - for (CRegistryResultIterator iter = result->begin(); iter != result->end(); ++iter) + for (const auto& row : result->Data) { - const auto& row = *iter; - return Get(reinterpret_cast(row[0].pVal)); } @@ -988,39 +979,53 @@ void CAccountManager::GetAccountsByData(const SString& dataName, const SString& "SELECT acc.name FROM accounts acc, userdata dat WHERE dat.key = ? AND dat.value = ? AND dat.userid = acc.id", SQLITE_TEXT, dataName.c_str(), SQLITE_TEXT, value.c_str()); - for (CRegistryResultIterator iter = result->begin(); iter != result->end(); ++iter) + for (const auto& row : result->Data) { - const CRegistryResultRow& row = *iter; - CAccount* pAccount = Get((const char*)row[0].pVal); if (pAccount) outAccounts.push_back(pAccount); } } +// Fires for all joining players CAccount* CAccountManager::AddGuestAccount(const SString& strName) { - CAccount* pAccount = new CAccount(this, EAccountType::Guest, strName); + CAccount* pAccount = new CAccount(this, EAccountType::Guest, strName); + CLuaArguments Arguments; + Arguments.PushAccount(pAccount); + g_pGame->GetMapManager()->GetRootElement()->CallEvent("onAccountCreate", Arguments); return pAccount; } +// Fires only when console is created CAccount* CAccountManager::AddConsoleAccount(const SString& strName) { - CAccount* pAccount = new CAccount(this, EAccountType::Console, strName); + CAccount* pAccount = new CAccount(this, EAccountType::Console, strName); + CLuaArguments Arguments; + Arguments.PushAccount(pAccount); + g_pGame->GetMapManager()->GetRootElement()->CallEvent("onAccountCreate", Arguments); return pAccount; } +// Fires for all created player accounts CAccount* CAccountManager::AddPlayerAccount(const SString& strName, const SString& strPassword, int iUserID, const SString& strIP, const SString& strSerial, const SString& strHttpPassAppend) { CAccount* pAccount = new CAccount(this, EAccountType::Player, strName, strPassword, iUserID, strIP, strSerial, strHttpPassAppend); + CLuaArguments Arguments; + Arguments.PushAccount(pAccount); + g_pGame->GetMapManager()->GetRootElement()->CallEvent("onAccountCreate", Arguments); return pAccount; } +// Fires whenever "addaccount" or "addAccount" was executed CAccount* CAccountManager::AddNewPlayerAccount(const SString& strName, const SString& strPassword) { CAccount* pAccount = new CAccount(this, EAccountType::Player, strName, strPassword, ++m_iAccounts); Save(pAccount); + CLuaArguments Arguments; + Arguments.PushAccount(pAccount); + g_pGame->GetMapManager()->GetRootElement()->CallEvent("onAccountCreate", Arguments); return pAccount; } @@ -1035,6 +1040,9 @@ bool CAccountManager::RemoveAccount(CAccount* pAccount) m_pDatabaseManager->Execf(m_hDbConnection, "DELETE FROM userdata WHERE userid=?", SQLITE_INTEGER, iUserID); m_pDatabaseManager->Execf(m_hDbConnection, "DELETE FROM serialusage WHERE userid=?", SQLITE_INTEGER, iUserID); } + CLuaArguments Arguments; + Arguments.PushAccount(pAccount); + g_pGame->GetMapManager()->GetRootElement()->CallEvent("onAccountRemove", Arguments); delete pAccount; return true; } @@ -1055,22 +1063,21 @@ void CAccountManager::StaticDbCallback(CDbJobData* pJobData, void* pContext) void CAccountManager::DbCallback(CDbJobData* pJobData) { - if (m_pDatabaseManager->QueryPoll(pJobData, 0)) + if (!m_pDatabaseManager->QueryPoll(pJobData, 0)) { - if (pJobData->result.status == EJobResult::FAIL) - { - CLogger::LogPrintf("ERROR: While updating account with '%s': %s.\n", *pJobData->GetCommandStringForLog(), *pJobData->result.strReason); - if (pJobData->result.strReason.ContainsI("missing database")) - { - // Try reconnection - CLogger::LogPrintf("INFO: Reconnecting to accounts database\n"); - ReconnectToDatabase(); - } - } + CLogger::LogPrintf("ERROR: Something worrying happened in DbCallback '%s': %s.\n", *pJobData->GetCommandStringForLog(), *pJobData->result.strReason); + return; } - else + + if (pJobData->result.status != EJobResult::FAIL) + return; + + CLogger::LogPrintf("ERROR: While updating account with '%s': %s.\n", *pJobData->GetCommandStringForLog(), *pJobData->result.strReason); + if (pJobData->result.strReason.ContainsI("missing database")) { - CLogger::LogPrintf("ERROR: Something worrying happened in DbCallback '%s': %s.\n", *pJobData->GetCommandStringForLog(), *pJobData->result.strReason); + // Try reconnection + CLogger::LogPrintf("INFO: Reconnecting to accounts database\n"); + ReconnectToDatabase(); } } @@ -1079,9 +1086,7 @@ void CAccountManager::DbCallback(CDbJobData* pJobData) // bool CAccountManager::IsValidAccountName(const SString& strName) { - if (strName.length() < MIN_USERNAME_LENGTH) - return false; - return true; + return strName.length() >= MIN_USERNAME_LENGTH; } // @@ -1089,9 +1094,7 @@ bool CAccountManager::IsValidAccountName(const SString& strName) // bool CAccountManager::IsValidPassword(const SString& strPassword) { - if (strPassword.length() < MIN_PASSWORD_LENGTH) - return false; - return true; + return strPassword.length() >= MIN_PASSWORD_LENGTH; } // @@ -1142,12 +1145,8 @@ bool CAccountManager::IsAuthorizedSerialRequired(CAccount* pAccount) // bool CAccountManager::IsHttpLoginAllowed(CAccount* pAccount, const SString& strIp) { - if (!g_pGame->GetConfig()->GetAuthSerialHttpEnabled() || g_pGame->GetConfig()->IsAuthSerialHttpIpException(strIp) || - !IsAuthorizedSerialRequired(pAccount) || pAccount->IsIpAuthorized(strIp)) - { - return true; - } - return false; + return !g_pGame->GetConfig()->GetAuthSerialHttpEnabled() || g_pGame->GetConfig()->IsAuthSerialHttpIpException(strIp) || + !IsAuthorizedSerialRequired(pAccount) || pAccount->IsIpAuthorized(strIp); } // @@ -1173,9 +1172,8 @@ void CAccountManager::LoadAccountSerialUsage(CAccount* pAccount) " WHERE userid=?", SQLITE_INTEGER, pAccount->GetID()); - for (CRegistryResultIterator iter = result->begin(); iter != result->end(); ++iter) + for (const auto& row : result->Data) { - const CRegistryResultRow& row = *iter; outSerialUsageList.push_back(CAccount::SSerialUsage()); CAccount::SSerialUsage& info = outSerialUsageList.back(); info.strSerial = (const char*)row[0].pVal; diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 0b47682dcb..2d38b37e3a 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -1643,6 +1643,9 @@ void CGame::AddBuiltInEvents() // Account events m_Events.AddEvent("onAccountDataChange", "account, key, value", NULL, false); + m_Events.AddEvent("onAccountCreate", "account", NULL, false); + m_Events.AddEvent("onAccountRemove", "account", NULL, false); + // Other events m_Events.AddEvent("onSettingChange", "setting, oldValue, newValue", NULL, false); m_Events.AddEvent("onChatMessage", "message, element", NULL, false); diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaAccountDefs.cpp b/Server/mods/deathmatch/logic/luadefs/CLuaAccountDefs.cpp index 22e24c73e8..339fde0449 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaAccountDefs.cpp +++ b/Server/mods/deathmatch/logic/luadefs/CLuaAccountDefs.cpp @@ -23,6 +23,7 @@ void CLuaAccountDefs::LoadFunctions() // Account get functions {"getAccountName", GetAccountName}, + {"getAccountType", ArgumentParser}, {"getAccountPlayer", GetAccountPlayer}, {"isGuestAccount", IsGuestAccount}, {"getAccountData", GetAccountData}, @@ -77,6 +78,7 @@ void CLuaAccountDefs::AddClass(lua_State* luaVM) lua_classfunction(luaVM, "getData", "getAccountData"); lua_classfunction(luaVM, "getAllData", "getAllAccountData"); lua_classfunction(luaVM, "getName", "getAccountName"); + lua_classfunction(luaVM, "getType", "getAccountType"); lua_classfunction(luaVM, "getPlayer", "getAccountPlayer"); lua_classfunction(luaVM, "isGuest", "isGuestAccount"); @@ -116,6 +118,20 @@ int CLuaAccountDefs::GetAccountName(lua_State* luaVM) return 1; } +std::optional CLuaAccountDefs::GetAccountType(CAccount* pAccount) +{ + switch (pAccount->GetType()) + { + case EAccountType::Guest: + return "guest"; + case EAccountType::Console: + return "console"; + case EAccountType::Player: + return "player"; + } + return {}; +} + int CLuaAccountDefs::GetAccountPlayer(lua_State* luaVM) { // player getAccountPlayer ( account theAccount ) diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaAccountDefs.h b/Server/mods/deathmatch/logic/luadefs/CLuaAccountDefs.h index dead6074fa..e1e2e82340 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaAccountDefs.h +++ b/Server/mods/deathmatch/logic/luadefs/CLuaAccountDefs.h @@ -26,6 +26,9 @@ class CLuaAccountDefs : public CLuaDefs LUA_DECLARE(GetAccount); LUA_DECLARE(GetAccounts); LUA_DECLARE(GetAccountName); + + static std::optional GetAccountType(CAccount* pAccount); + LUA_DECLARE(GetAccountPlayer); LUA_DECLARE(IsGuestAccount); LUA_DECLARE(GetAccountData);