diff --git a/data/sql/updates/pending_db_world/rev_1552751401332509400.sql b/data/sql/updates/pending_db_world/rev_1552751401332509400.sql new file mode 100644 index 000000000..710184f5b --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1552751401332509400.sql @@ -0,0 +1,15 @@ +INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1552751401332509400'); + +-- Delete old +DELETE FROM `trinity_string` WHERE `entry` IN (11002, 11003, 11004, 11005, 11006, 11007, 11017, 11018); + +-- Add rus and replace eng +INSERT INTO `trinity_string`(`entry`, `content_default`, `content_loc8`) VALUES +(11002, 'Server: %s has kicked %s, reason: %s', 'Server: %s кикнул %s, причина: %s'), +(11003, 'Server: %s has muted %s for %u minutes, reason: %s', 'Server: %s замутил %s на %u минут, причина: %s'), +(11004, 'Server: %s has banned character %s for %s, reason: %s', 'Server: %s забанил персонажа %s на %s, причина: %s'), +(11005, 'Server: %s has banned character %s permanetly, reason: %s', 'Server: %s забанил персонажа %s permanetly, reason: %s'), +(11006, 'Server: %s has banned account %s for %s, reason: %s', 'Server: %s забанил аккаунт %s на %s, причина: %s'), +(11007, 'Server: %s has banned account %s permanetly, reason: %s', 'Server: %s забанил аккаунт %s навсегда, причина: %s'), +(11017, 'Server: %s has banned ip %s for %s, reason: %s', 'Server: %s забанил айпи %s на %s, причина: %s'), +(11018, 'Server: %s has banned ip %s permanetly, reason: %s', 'Server: %s забанил айпи %s навсегда, причина: %s'); diff --git a/src/server/game/Misc/BanManager.cpp b/src/server/game/Misc/BanManager.cpp new file mode 100644 index 000000000..948100914 --- /dev/null +++ b/src/server/game/Misc/BanManager.cpp @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL3 v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + */ + +#include "BanManager.h" +#include "AccountMgr.h" +#include "DatabaseEnv.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "Language.h" +#include "ScriptMgr.h" +#include "World.h" +#include "WorldSession.h" + +BanManager* BanManager::instance() +{ + static BanManager instance; + return &instance; +} + +/// Ban an account, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban +BanReturn BanManager::BanAccount(std::string const& AccountName, std::string const& Duration, std::string const& Reason, std::string const& Author) +{ + if (AccountName.empty() || Duration.empty()) + return BAN_SYNTAX_ERROR; + + uint32 DurationSecs = TimeStringToSecs(Duration); + + uint32 AccountID = AccountMgr::GetId(AccountName); + if (!AccountID) + return BAN_NOTFOUND; + + ///- Disconnect all affected players (for IP it can be several) + SQLTransaction trans = LoginDatabase.BeginTransaction(); + + // pussywizard: check existing ban to prevent overriding by a shorter one! >_> + PreparedStatement* stmtAccountBanned = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); + stmtAccountBanned->setUInt32(0, AccountID); + + PreparedQueryResult banresult = LoginDatabase.Query(stmtAccountBanned); + if (banresult && ((*banresult)[0].GetUInt32() == (*banresult)[1].GetUInt32() || ((*banresult)[1].GetUInt32() > time(nullptr) + DurationSecs && DurationSecs))) + return BAN_LONGER_EXISTS; + + // make sure there is only one active ban + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED); + stmt->setUInt32(0, AccountID); + trans->Append(stmt); + + // No SQL injection with prepared statements + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_BANNED); + stmt->setUInt32(0, AccountID); + stmt->setUInt32(1, DurationSecs); + stmt->setString(2, Author); + stmt->setString(3, Reason); + trans->Append(stmt); + + if (WorldSession* session = sWorld->FindSession(AccountID)) + if (session->GetPlayerName() != Author) + session->KickPlayer("Ban Account at condition 'FindSession(account)->GetPlayerName() != author'"); + + if (WorldSession* session = sWorld->FindOfflineSession(AccountID)) + if (session->GetPlayerName() != Author) + session->KickPlayer("Ban Account at condition 'FindOfflineSession(account)->GetPlayerName() != author'"); + + LoginDatabase.CommitTransaction(trans); + + if (sWorld->getBoolConfig(CONFIG_SHOW_BAN_IN_WORLD)) + { + bool IsPermanetly = true; + + if (TimeStringToSecs(Duration) > 0) + IsPermanetly = false; + + if (!IsPermanetly) + sWorld->SendWorldText(LANG_BAN_ACCOUNT_YOUBANNEDMESSAGE_WORLD, Author.c_str(), AccountName.c_str(), secsToTimeString(TimeStringToSecs(Duration), true).c_str(), Reason.c_str()); + else + sWorld->SendWorldText(LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD, Author.c_str(), AccountName.c_str(), Reason.c_str()); + } + + return BAN_SUCCESS; +} + +/// Ban an account by player name, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban +BanReturn BanManager::BanAccountByPlayerName(std::string const& CharacterName, std::string const& Duration, std::string const& Reason, std::string const& Author) +{ + if (CharacterName.empty() || Duration.empty()) + return BAN_SYNTAX_ERROR; + + uint32 DurationSecs = TimeStringToSecs(Duration); + + uint32 AccountID = sObjectMgr->GetPlayerAccountIdByPlayerName(CharacterName); + if (!AccountID) + return BAN_NOTFOUND; + + ///- Disconnect all affected players (for IP it can be several) + SQLTransaction trans = LoginDatabase.BeginTransaction(); + + // pussywizard: check existing ban to prevent overriding by a shorter one! >_> + PreparedStatement* stmtAccountBanned = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); + stmtAccountBanned->setUInt32(0, AccountID); + + PreparedQueryResult banresult = LoginDatabase.Query(stmtAccountBanned); + if (banresult && ((*banresult)[0].GetUInt32() == (*banresult)[1].GetUInt32() || ((*banresult)[1].GetUInt32() > time(nullptr) + DurationSecs && DurationSecs))) + return BAN_LONGER_EXISTS; + + // make sure there is only one active ban + PreparedStatement * stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED); + stmt->setUInt32(0, AccountID); + trans->Append(stmt); + + // No SQL injection with prepared statements + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_BANNED); + stmt->setUInt32(0, AccountID); + stmt->setUInt32(1, DurationSecs); + stmt->setString(2, Author); + stmt->setString(3, Reason); + trans->Append(stmt); + + if (WorldSession* session = sWorld->FindSession(AccountID)) + if (session->GetPlayerName() != Author) + session->KickPlayer("Ban Account at condition 'FindSession(account)->GetPlayerName() != author'"); + + if (WorldSession* session = sWorld->FindOfflineSession(AccountID)) + if (session->GetPlayerName() != Author) + session->KickPlayer("Ban Account at condition 'FindOfflineSession(account)->GetPlayerName() != author'"); + + LoginDatabase.CommitTransaction(trans); + + if (sWorld->getBoolConfig(CONFIG_SHOW_BAN_IN_WORLD)) + { + bool IsPermanetly = true; + + if (TimeStringToSecs(Duration) > 0) + IsPermanetly = false; + + std::string AccountName; + + AccountMgr::GetName(AccountID, AccountName); + + if (!IsPermanetly) + sWorld->SendWorldText(LANG_BAN_ACCOUNT_YOUBANNEDMESSAGE_WORLD, Author.c_str(), AccountName.c_str(), secsToTimeString(TimeStringToSecs(Duration), true).c_str(), Reason.c_str()); + else + sWorld->SendWorldText(LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD, Author.c_str(), AccountName.c_str(), Reason.c_str()); + } + + return BAN_SUCCESS; +} + +/// Ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban +BanReturn BanManager::BanIP(std::string const& IP, std::string const& Duration, std::string const& Reason, std::string const& Author) +{ + if (IP.empty() || Duration.empty()) + return BAN_SYNTAX_ERROR; + + uint32 DurationSecs = TimeStringToSecs(Duration); + + // No SQL injection with prepared statements + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_IP); + stmt->setString(0, IP); + PreparedQueryResult resultAccounts = LoginDatabase.Query(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_BANNED); + stmt->setString(0, IP); + stmt->setUInt32(1, DurationSecs); + stmt->setString(2, Author); + stmt->setString(3, Reason); + LoginDatabase.Execute(stmt); + + if (sWorld->getBoolConfig(CONFIG_SHOW_BAN_IN_WORLD)) + { + bool IsPermanetly = true; + + if (TimeStringToSecs(Duration) > 0) + IsPermanetly = false; + + if (IsPermanetly) + sWorld->SendWorldText(LANG_BAN_IP_YOUPERMBANNEDMESSAGE_WORLD, Author.c_str(), IP.c_str(), Reason.c_str()); + else + sWorld->SendWorldText(LANG_BAN_IP_YOUBANNEDMESSAGE_WORLD, Author.c_str(), IP.c_str(), secsToTimeString(TimeStringToSecs(Duration), true).c_str(), Reason.c_str()); + } + + if (!resultAccounts) + return BAN_SUCCESS; + + ///- Disconnect all affected players (for IP it can be several) + SQLTransaction trans = LoginDatabase.BeginTransaction(); + + do + { + Field* fields = resultAccounts->Fetch(); + uint32 AccountID = fields[0].GetUInt32(); + + if (WorldSession* session = sWorld->FindSession(AccountID)) + if (session->GetPlayerName() != Author) + session->KickPlayer("Ban IP at condition 'FindSession(account)->GetPlayerName() != author'"); + + if (WorldSession* session = sWorld->FindOfflineSession(AccountID)) + if (session->GetPlayerName() != Author) + session->KickPlayer("Ban IP at condition 'FindOfflineSession(account)->GetPlayerName() != author'"); + + } while (resultAccounts->NextRow()); + + LoginDatabase.CommitTransaction(trans); + + return BAN_SUCCESS; +} + +/// Ban an character, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban +BanReturn BanManager::BanCharacter(std::string const& CharacterName, std::string const& Duration, std::string const& Reason, std::string const& Author) +{ + Player* target = ObjectAccessor::FindPlayerByName(CharacterName, false); + uint32 DurationSecs = TimeStringToSecs(Duration); + uint32 TargetGUID = 0; + + /// Pick a player to ban if not online + if (!target) + { + TargetGUID = sWorld->GetGlobalPlayerGUID(CharacterName); + if (!TargetGUID) + return BAN_NOTFOUND; + } + else + TargetGUID = target->GetGUIDLow(); + + // make sure there is only one active ban + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_BAN); + stmt->setUInt32(0, TargetGUID); + CharacterDatabase.Execute(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_BAN); + stmt->setUInt32(0, TargetGUID); + stmt->setUInt32(1, DurationSecs); + stmt->setString(2, Author); + stmt->setString(3, Reason); + CharacterDatabase.Execute(stmt); + + if (target) + target->GetSession()->KickPlayer("Ban"); + + if (sWorld->getBoolConfig(CONFIG_SHOW_BAN_IN_WORLD)) + { + bool IsPermanetly = true; + + if (TimeStringToSecs(Duration) > 0) + IsPermanetly = false; + + if (!IsPermanetly) + sWorld->SendWorldText(LANG_BAN_CHARACTER_YOUBANNEDMESSAGE_WORLD, Author.c_str(), CharacterName.c_str(), secsToTimeString(TimeStringToSecs(Duration), true).c_str(), Reason.c_str()); + else + sWorld->SendWorldText(LANG_BAN_CHARACTER_YOUPERMBANNEDMESSAGE_WORLD, Author.c_str(), CharacterName.c_str(), Reason.c_str()); + } + + return BAN_SUCCESS; +} + +/// Remove a ban from an account +bool BanManager::RemoveBanAccount(std::string const& AccountName) +{ + uint32 AccountID = AccountMgr::GetId(AccountName); + if (!AccountID) + return false; + + // NO SQL injection as account is uint32 + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED); + stmt->setUInt32(0, AccountID); + LoginDatabase.Execute(stmt); + + return true; +} + +/// Remove a ban from an player name +bool BanManager::RemoveBanAccountByPlayerName(std::string const& CharacterName) +{ + uint32 AccountID = sObjectMgr->GetPlayerAccountIdByPlayerName(CharacterName); + if (!AccountID) + return false; + + // NO SQL injection as account is uint32 + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED); + stmt->setUInt32(0, AccountID); + LoginDatabase.Execute(stmt); + + return true; +} + +/// Remove a ban from an account +bool BanManager::RemoveBanIP(std::string const& IP) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_IP_NOT_BANNED); + stmt->setString(0, IP); + LoginDatabase.Execute(stmt); + + return true; +} + +/// Remove a ban from a character +bool BanManager::RemoveBanCharacter(std::string const& CharacterName) +{ + Player* pBanned = ObjectAccessor::FindPlayerByName(CharacterName, false); + uint32 guid = 0; + + /// Pick a player to ban if not online + if (!pBanned) + guid = sWorld->GetGlobalPlayerGUID(CharacterName); + else + guid = pBanned->GetGUIDLow(); + + if (!guid) + return false; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_BAN); + stmt->setUInt32(0, guid); + CharacterDatabase.Execute(stmt); + return true; +} diff --git a/src/server/game/Misc/BanManager.h b/src/server/game/Misc/BanManager.h new file mode 100644 index 000000000..6e7ff1ef9 --- /dev/null +++ b/src/server/game/Misc/BanManager.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL3 v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + */ + +#ifndef _BAN_MANAGER_H +#define _BAN_MANAGER_H + +#include "Common.h" + + /// Ban function return codes +enum BanReturn +{ + BAN_SUCCESS, + BAN_SYNTAX_ERROR, + BAN_NOTFOUND, + BAN_LONGER_EXISTS +}; + +class BanManager +{ +public: + + static BanManager* instance(); + + BanReturn BanAccount(std::string const& AccountName, std::string const& Duration, std::string const& Reason, std::string const& Author); + BanReturn BanAccountByPlayerName(std::string const& CharacterName, std::string const& Duration, std::string const& Reason, std::string const& Author); + BanReturn BanIP(std::string const& IP, std::string const& Duration, std::string const& Reason, std::string const& Author); + BanReturn BanCharacter(std::string const& CharacterName, std::string const& Duration, std::string const& Reason, std::string const& Author); + + bool RemoveBanAccount(std::string const& AccountName); + bool RemoveBanAccountByPlayerName(std::string const& CharacterName); + bool RemoveBanIP(std::string const& IP); + bool RemoveBanCharacter(std::string const& CharacterName); +}; + +#define sBan BanManager::instance() + +#endif // _BAN_MANAGER_H diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 6fa20db51..89ea662a5 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1290,6 +1290,7 @@ enum TrinityStrings LANG_BAN_CHARACTER_YOUPERMBANNEDMESSAGE_WORLD = 11005, LANG_BAN_ACCOUNT_YOUBANNEDMESSAGE_WORLD = 11006, LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD = 11007, + LANG_NPCINFO_INHABIT_TYPE = 11008, LANG_NPCINFO_FLAGS_EXTRA = 11009, @@ -1302,6 +1303,10 @@ enum TrinityStrings LANG_CREATURE_NOT_AI_ENABLED = 11015, LANG_SELECT_PLAYER_OR_PET = 11016, + // Continue show Ban in world (ip) + LANG_BAN_IP_YOUBANNEDMESSAGE_WORLD = 11017, + LANG_BAN_IP_YOUPERMBANNEDMESSAGE_WORLD = 11018, + LANG_MUTED_PLAYER = 30000, // Mute for player 2 hour }; #endif diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 6cbece948..d36aeab60 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -3277,23 +3277,6 @@ enum ResponseCodes CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x67 }; -/// Ban function modes -enum BanMode -{ - BAN_ACCOUNT, - BAN_CHARACTER, - BAN_IP -}; - -/// Ban function return codes -enum BanReturn -{ - BAN_SUCCESS, - BAN_SYNTAX_ERROR, - BAN_NOTFOUND, - BAN_LONGER_EXISTS -}; - // indexes of BattlemasterList.dbc enum BattlegroundTypeId { diff --git a/src/server/game/Warden/Warden.cpp b/src/server/game/Warden/Warden.cpp index f58d2e0ad..941304fe5 100644 --- a/src/server/game/Warden/Warden.cpp +++ b/src/server/game/Warden/Warden.cpp @@ -17,6 +17,7 @@ #include "Util.h" #include "Warden.h" #include "AccountMgr.h" +#include "BanManager.h" Warden::Warden() : _session(NULL), _inputCrypto(16), _outputCrypto(16), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0), _dataSent(false), _previousTimestamp(0), _module(NULL), _initialized(false) @@ -227,7 +228,7 @@ std::string Warden::Penalty(WardenCheck* check /*= NULL*/, uint16 checkFailed /* duration << sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_BAN_DURATION) << "s"; std::string accountName; AccountMgr::GetName(_session->GetAccountId(), accountName); - sWorld->BanAccount(BAN_ACCOUNT, accountName, ((longBan && false /*ZOMG!*/) ? "1209600s" : duration.str()), banReason, "Server"); + sBan->BanAccount(accountName, ((longBan && false /*ZOMG!*/) ? "1209600s" : duration.str()), banReason, "Server"); return "Ban"; } diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 47ffd5d49..76e3112ab 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1242,6 +1242,7 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_NO_RESET_TALENT_COST] = sConfigMgr->GetBoolDefault("NoResetTalentsCost", false); m_bool_configs[CONFIG_SHOW_KICK_IN_WORLD] = sConfigMgr->GetBoolDefault("ShowKickInWorld", false); + m_bool_configs[CONFIG_SHOW_BAN_IN_WORLD] = sConfigMgr->GetBoolDefault("ShowBanInWorld", false); m_int_configs[CONFIG_INTERVAL_LOG_UPDATE] = sConfigMgr->GetIntDefault("RecordUpdateTimeDiffInterval", 60000); m_int_configs[CONFIG_MIN_LOG_UPDATE] = sConfigMgr->GetIntDefault("MinRecordUpdateTimeDiff", 100); m_int_configs[CONFIG_NUMTHREADS] = sConfigMgr->GetIntDefault("MapUpdate.Threads", 1); @@ -2440,180 +2441,6 @@ void World::KickAllLess(AccountTypes sec) itr->second->KickPlayer("KickAllLess"); } -/// Ban an account or ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban -BanReturn World::BanAccount(BanMode mode, std::string const& nameOrIP, std::string const& duration, std::string const& reason, std::string const& author) -{ - uint32 duration_secs = TimeStringToSecs(duration); - PreparedQueryResult resultAccounts = PreparedQueryResult(NULL); //used for kicking - PreparedStatement* stmt = NULL; - - ///- Update the database with ban information - switch (mode) - { - case BAN_IP: - // No SQL injection with prepared statements - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_IP); - stmt->setString(0, nameOrIP); - resultAccounts = LoginDatabase.Query(stmt); - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_BANNED); - stmt->setString(0, nameOrIP); - stmt->setUInt32(1, duration_secs); - stmt->setString(2, author); - stmt->setString(3, reason); - LoginDatabase.Execute(stmt); - break; - case BAN_ACCOUNT: - // No SQL injection with prepared statements - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME); - stmt->setString(0, nameOrIP); - resultAccounts = LoginDatabase.Query(stmt); - break; - case BAN_CHARACTER: - // No SQL injection with prepared statements - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_BY_NAME); - stmt->setString(0, nameOrIP); - resultAccounts = CharacterDatabase.Query(stmt); - break; - default: - return BAN_SYNTAX_ERROR; - } - - if (!resultAccounts) - { - if (mode == BAN_IP) - return BAN_SUCCESS; // ip correctly banned but nobody affected (yet) - else - return BAN_NOTFOUND; // Nobody to ban - } - - ///- Disconnect all affected players (for IP it can be several) - SQLTransaction trans = LoginDatabase.BeginTransaction(); - do - { - Field* fieldsAccount = resultAccounts->Fetch(); - uint32 account = fieldsAccount[0].GetUInt32(); - - if (mode != BAN_IP) - { - // pussywizard: check existing ban to prevent overriding by a shorter one! >_> - PreparedStatement* stmtx = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); - stmtx->setUInt32(0, account); - PreparedQueryResult banresultx = LoginDatabase.Query(stmtx); - if (banresultx && ((*banresultx)[0].GetUInt32() == (*banresultx)[1].GetUInt32() || ((*banresultx)[1].GetUInt32() > time(NULL)+duration_secs && duration_secs))) - return BAN_LONGER_EXISTS; - - // make sure there is only one active ban - stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED); - stmt->setUInt32(0, account); - trans->Append(stmt); - // No SQL injection with prepared statements - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_BANNED); - stmt->setUInt32(0, account); - stmt->setUInt32(1, duration_secs); - stmt->setString(2, author); - stmt->setString(3, reason); - trans->Append(stmt); - } - - if (WorldSession* sess = FindSession(account)) - if (sess->GetPlayerName() != author) - sess->KickPlayer("FindSession(account)->GetPlayerName() != author"); - if (WorldSession* sess = FindOfflineSession(account)) - if (sess->GetPlayerName() != author) - sess->KickPlayer("FindOfflineSession(account)->GetPlayerName() != author"); - } while (resultAccounts->NextRow()); - - LoginDatabase.CommitTransaction(trans); - - return BAN_SUCCESS; -} - -/// Remove a ban from an account or IP address -bool World::RemoveBanAccount(BanMode mode, std::string const& nameOrIP) -{ - PreparedStatement* stmt = NULL; - if (mode == BAN_IP) - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_IP_NOT_BANNED); - stmt->setString(0, nameOrIP); - LoginDatabase.Execute(stmt); - } - else - { - uint32 account = 0; - if (mode == BAN_ACCOUNT) - account = AccountMgr::GetId(nameOrIP); - else if (mode == BAN_CHARACTER) - account = sObjectMgr->GetPlayerAccountIdByPlayerName(nameOrIP); - - if (!account) - return false; - - //NO SQL injection as account is uint32 - stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED); - stmt->setUInt32(0, account); - LoginDatabase.Execute(stmt); - } - return true; -} - -/// Ban an account or ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban -BanReturn World::BanCharacter(std::string const& name, std::string const& duration, std::string const& reason, std::string const& author) -{ - Player* pBanned = ObjectAccessor::FindPlayerByName(name, false); - uint32 guid = 0; - - uint32 duration_secs = TimeStringToSecs(duration); - - /// Pick a player to ban if not online - if (!pBanned) - { - guid = sWorld->GetGlobalPlayerGUID(name); - if (!guid) - return BAN_NOTFOUND; - } - else - guid = pBanned->GetGUIDLow(); - - // make sure there is only one active ban - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_BAN); - stmt->setUInt32(0, guid); - CharacterDatabase.Execute(stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_BAN); - stmt->setUInt32(0, guid); - stmt->setUInt32(1, duration_secs); - stmt->setString(2, author); - stmt->setString(3, reason); - CharacterDatabase.Execute(stmt); - - if (pBanned) - pBanned->GetSession()->KickPlayer("Ban"); - - return BAN_SUCCESS; -} - -/// Remove a ban from a character -bool World::RemoveBanCharacter(std::string const& name) -{ - Player* pBanned = ObjectAccessor::FindPlayerByName(name, false); - uint32 guid = 0; - - /// Pick a player to ban if not online - if (!pBanned) - guid = sWorld->GetGlobalPlayerGUID(name); - else - guid = pBanned->GetGUIDLow(); - - if (!guid) - return false; - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_BAN); - stmt->setUInt32(0, guid); - CharacterDatabase.Execute(stmt); - return true; -} - /// Update the game time void World::_UpdateGameTime() { diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 4e158768a..67e71c2ac 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -136,6 +136,7 @@ enum WorldBoolConfigs CONFIG_PVP_TOKEN_ENABLE, CONFIG_NO_RESET_TALENT_COST, CONFIG_SHOW_KICK_IN_WORLD, + CONFIG_SHOW_BAN_IN_WORLD, CONFIG_CHATLOG_CHANNEL, CONFIG_CHATLOG_WHISPER, CONFIG_CHATLOG_SYSCHAN, @@ -726,10 +727,6 @@ class World void KickAll(); void KickAllLess(AccountTypes sec); - BanReturn BanAccount(BanMode mode, std::string const& nameOrIP, std::string const& duration, std::string const& reason, std::string const& author); - bool RemoveBanAccount(BanMode mode, std::string const& nameOrIP); - BanReturn BanCharacter(std::string const& name, std::string const& duration, std::string const& reason, std::string const& author); - bool RemoveBanCharacter(std::string const& name); // for max speed access static float GetMaxVisibleDistanceOnContinents() { return m_MaxVisibleDistanceOnContinents; } diff --git a/src/server/scripts/Commands/cs_ban.cpp b/src/server/scripts/Commands/cs_ban.cpp index 585e58ae6..4d972d352 100644 --- a/src/server/scripts/Commands/cs_ban.cpp +++ b/src/server/scripts/Commands/cs_ban.cpp @@ -18,6 +18,15 @@ EndScriptData */ #include "ObjectMgr.h" #include "Player.h" #include "ScriptMgr.h" +#include "BanManager.h" + +/// Ban function modes +enum BanMode +{ + BAN_ACCOUNT, + BAN_CHARACTER, + BAN_IP +}; class ban_commandscript : public CommandScript { @@ -33,18 +42,21 @@ public: { "playeraccount", SEC_GAMEMASTER, true, &HandleUnBanAccountByCharCommand, "" }, { "ip", SEC_GAMEMASTER, true, &HandleUnBanIPCommand, "" } }; + static std::vector banlistCommandTable = { { "account", SEC_GAMEMASTER, true, &HandleBanListAccountCommand, "" }, { "character", SEC_GAMEMASTER, true, &HandleBanListCharacterCommand, "" }, { "ip", SEC_GAMEMASTER, true, &HandleBanListIPCommand, "" } }; + static std::vector baninfoCommandTable = { { "account", SEC_GAMEMASTER, true, &HandleBanInfoAccountCommand, "" }, { "character", SEC_GAMEMASTER, true, &HandleBanInfoCharacterCommand, "" }, { "ip", SEC_GAMEMASTER, true, &HandleBanInfoIPCommand, "" } }; + static std::vector banCommandTable = { { "account", SEC_GAMEMASTER, true, &HandleBanAccountCommand, "" }, @@ -52,6 +64,7 @@ public: { "playeraccount", SEC_GAMEMASTER, true, &HandleBanAccountByCharCommand, "" }, { "ip", SEC_GAMEMASTER, true, &HandleBanIPCommand, "" } }; + static std::vector commandTable = { { "ban", SEC_GAMEMASTER, true, nullptr, "", banCommandTable }, @@ -59,6 +72,7 @@ public: { "banlist", SEC_GAMEMASTER, true, nullptr, "", banlistCommandTable }, { "unban", SEC_GAMEMASTER, true, nullptr, "", unbanCommandTable } }; + return commandTable; } @@ -93,24 +107,28 @@ public: return false; } - switch (sWorld->BanCharacter(name, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName() : "")) + switch (sBan->BanCharacter(name, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName() : "")) { - case BAN_SUCCESS: + case BAN_SUCCESS: + if (atoi(durationStr) > 0) { - if (atoi(durationStr) > 0) + if (!sWorld->getBoolConfig(CONFIG_SHOW_BAN_IN_WORLD)) handler->PSendSysMessage(LANG_BAN_YOUBANNED, name.c_str(), secsToTimeString(TimeStringToSecs(durationStr), true).c_str(), reasonStr); - else - handler->PSendSysMessage(LANG_BAN_YOUPERMBANNED, name.c_str(), reasonStr); - break; } - case BAN_NOTFOUND: + else { - handler->PSendSysMessage(LANG_BAN_NOTFOUND, "character", name.c_str()); - handler->SetSentErrorMessage(true); - return false; + if (!sWorld->getBoolConfig(CONFIG_SHOW_BAN_IN_WORLD)) + handler->PSendSysMessage(LANG_BAN_YOUPERMBANNED, name.c_str(), reasonStr); } - default: - break; + break; + case BAN_NOTFOUND: + { + handler->PSendSysMessage(LANG_BAN_NOTFOUND, "character", name.c_str()); + handler->SetSentErrorMessage(true); + return false; + } + default: + break; } return true; @@ -169,13 +187,34 @@ public: break; } - switch (sWorld->BanAccount(mode, nameOrIP, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName() : "")) + BanReturn banReturn; + + switch (mode) + { + case BAN_ACCOUNT: + banReturn = sBan->BanAccount(nameOrIP, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName() : ""); + break; + case BAN_CHARACTER: + banReturn = sBan->BanAccountByPlayerName(nameOrIP, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName() : ""); + break; + case BAN_IP: + banReturn = sBan->BanIP(nameOrIP, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName() : ""); + break; + } + + switch (banReturn) { case BAN_SUCCESS: if (atoi(durationStr) > 0) - handler->PSendSysMessage(LANG_BAN_YOUBANNED, nameOrIP.c_str(), secsToTimeString(TimeStringToSecs(durationStr), true).c_str(), reasonStr); + { + if (!sWorld->getBoolConfig(CONFIG_SHOW_BAN_IN_WORLD)) + handler->PSendSysMessage(LANG_BAN_YOUBANNED, nameOrIP.c_str(), secsToTimeString(TimeStringToSecs(durationStr), true).c_str(), reasonStr); + } else - handler->PSendSysMessage(LANG_BAN_YOUPERMBANNED, nameOrIP.c_str(), reasonStr); + { + if (!sWorld->getBoolConfig(CONFIG_SHOW_BAN_IN_WORLD)) + handler->PSendSysMessage(LANG_BAN_YOUPERMBANNED, nameOrIP.c_str(), reasonStr); + } break; case BAN_SYNTAX_ERROR: return false; @@ -197,6 +236,8 @@ public: case BAN_LONGER_EXISTS: handler->PSendSysMessage("Unsuccessful! A longer ban is already present on this account!"); break; + default: + break; } return true; @@ -629,16 +670,16 @@ public: if (!nameStr) return false; - std::string name = nameStr; + std::string CharacterName = nameStr; - if (!normalizePlayerName(name)) + if (!normalizePlayerName(CharacterName)) { handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); handler->SetSentErrorMessage(true); return false; } - if (!sWorld->RemoveBanCharacter(name)) + if (!sBan->RemoveBanCharacter(CharacterName)) { handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); handler->SetSentErrorMessage(true); @@ -693,10 +734,29 @@ public: break; } - if (sWorld->RemoveBanAccount(mode, nameOrIP)) - handler->PSendSysMessage(LANG_UNBAN_UNBANNED, nameOrIP.c_str()); - else - handler->PSendSysMessage(LANG_UNBAN_ERROR, nameOrIP.c_str()); + switch (mode) + { + case BAN_ACCOUNT: + if (sBan->RemoveBanAccount(nameOrIP)) + handler->PSendSysMessage(LANG_UNBAN_UNBANNED, nameOrIP.c_str()); + else + handler->PSendSysMessage(LANG_UNBAN_ERROR, nameOrIP.c_str()); + break; + case BAN_CHARACTER: + if (sBan->RemoveBanAccountByPlayerName(nameOrIP)) + handler->PSendSysMessage(LANG_UNBAN_UNBANNED, nameOrIP.c_str()); + else + handler->PSendSysMessage(LANG_UNBAN_ERROR, nameOrIP.c_str()); + break; + case BAN_IP: + if (sBan->RemoveBanIP(nameOrIP)) + handler->PSendSysMessage(LANG_UNBAN_UNBANNED, nameOrIP.c_str()); + else + handler->PSendSysMessage(LANG_UNBAN_ERROR, nameOrIP.c_str()); + break; + default: + break; + } return true; } diff --git a/src/server/scripts/Kalimdor/zone_silithus.cpp b/src/server/scripts/Kalimdor/zone_silithus.cpp index 7ff522658..1fe059791 100644 --- a/src/server/scripts/Kalimdor/zone_silithus.cpp +++ b/src/server/scripts/Kalimdor/zone_silithus.cpp @@ -24,6 +24,7 @@ EndContentData */ #include "AccountMgr.h" #include "SpellInfo.h" #include "Spell.h" +#include "BanManager.h" /*### ## npcs_rutgar_and_frankal @@ -1263,7 +1264,7 @@ class go_wind_stone : public GameObjectScript { std::string accountName; AccountMgr::GetName(player->GetSession()->GetAccountId(), accountName); - sWorld->BanAccount(BAN_ACCOUNT, accountName, "0s", "Wind Stone exploit", "Server"); + sBan->BanAccount(accountName, "0s", "Wind Stone exploit", "Server"); } return; } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp index b94967b71..326f2eb8e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp @@ -10,6 +10,7 @@ #include "PassiveAI.h" #include "Player.h" #include "WorldSession.h" +#include "BanManager.h" enum VezaxSpellData { @@ -682,7 +683,7 @@ public: { std::string accountName; AccountMgr::GetName(plr->GetSession()->GetAccountId(), accountName); - sWorld->BanAccount(BAN_ACCOUNT, accountName, "0s", "Tele hack", "Server"); + sBan->BanAccount(accountName, "0s", "Tele hack", "Server"); return true; } diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 097f75663..5e0cf33c9 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3015,6 +3015,15 @@ Guild.AllowMultipleGuildMaster = 0 ShowKickInWorld = 0 +# +# ShowBanInWorld +# Description: Determines whether a message is broadcasted to the entire server when a +# player gets banned. +# Default: 0 - (Disabled) +# 1 - (Enabled) + +ShowBanInWorld = 0 + # # RecordUpdateTimeDiffInterval # Description: Time (in milliseconds) update time diff is written to the log file.