From 02afbec99d92660c86d37d14d2226a0dabd6ccc5 Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Sat, 18 Jul 2026 14:39:44 -0300 Subject: [PATCH] feat(Core/Commands): add ".server set security" to set realm security level (#26649) Co-authored-by: Claude Opus 4.8 --- .../rev_1784190761123425500.sql | 8 +++++++ .../rev_1784190992977546300.sql | 10 ++++++++ .../Database/Implementation/LoginDatabase.cpp | 1 + .../Database/Implementation/LoginDatabase.h | 1 + src/server/game/Accounts/RBAC.h | 1 + src/server/game/Miscellaneous/Language.h | 4 ++++ src/server/scripts/Commands/cs_server.cpp | 23 +++++++++++++++++++ 7 files changed, 48 insertions(+) create mode 100644 data/sql/updates/pending_db_auth/rev_1784190761123425500.sql create mode 100644 data/sql/updates/pending_db_world/rev_1784190992977546300.sql diff --git a/data/sql/updates/pending_db_auth/rev_1784190761123425500.sql b/data/sql/updates/pending_db_auth/rev_1784190761123425500.sql new file mode 100644 index 000000000..54224c3c9 --- /dev/null +++ b/data/sql/updates/pending_db_auth/rev_1784190761123425500.sql @@ -0,0 +1,8 @@ +-- +DELETE FROM `rbac_permissions` WHERE `id` = 939; +INSERT INTO `rbac_permissions` (`id`, `name`) VALUES +(939, 'Command: server set security'); + +DELETE FROM `rbac_linked_permissions` WHERE `id` = 196 AND `linkedId` = 939; +INSERT INTO `rbac_linked_permissions` (`id`, `linkedId`) VALUES +(196, 939); diff --git a/data/sql/updates/pending_db_world/rev_1784190992977546300.sql b/data/sql/updates/pending_db_world/rev_1784190992977546300.sql new file mode 100644 index 000000000..8e3364ea6 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1784190992977546300.sql @@ -0,0 +1,10 @@ +-- +DELETE FROM `acore_string` WHERE `entry` IN (11020, 11021, 11022); +INSERT INTO `acore_string` (`entry`, `content_default`, `locale_koKR`, `locale_frFR`, `locale_deDE`, `locale_zhCN`, `locale_zhTW`, `locale_esES`, `locale_esMX`, `locale_ruRU`) VALUES +(11020, 'Realm security level set to {}. Only accounts with this level or higher may log in.', '렐름 보안 등급이 {}(으)로 설정되었습니다. 이 등급 이상의 계정만 로그인할 수 있습니다.', 'Niveau de sécurité du royaume défini sur {}. Seuls les comptes de ce niveau ou supérieur peuvent se connecter.', 'Sicherheitsstufe des Realms auf {} gesetzt. Nur Konten mit dieser Stufe oder höher können sich anmelden.', '服务器安全等级已设置为 {}。只有该等级或更高等级的账号才能登录。', '伺服器安全等級已設定為 {}。只有該等級或更高等級的帳號才能登入。', 'Nivel de seguridad del reino establecido en {}. Solo las cuentas con este nivel o superior pueden iniciar sesión.', 'Nivel de seguridad del reino establecido en {}. Solo las cuentas con este nivel o superior pueden iniciar sesión.', 'Уровень безопасности игрового мира установлен на {}. Войти могут только учётные записи с этим уровнем или выше.'), +(11021, 'Security level must be between {} (player) and {} (administrator).', '보안 등급은 {}(플레이어)에서 {}(관리자) 사이여야 합니다.', 'Le niveau de sécurité doit être compris entre {} (joueur) et {} (administrateur).', 'Die Sicherheitsstufe muss zwischen {} (Spieler) und {} (Administrator) liegen.', '安全等级必须介于 {}(玩家)和 {}(管理员)之间。', '安全等級必須介於 {}(玩家)和 {}(管理員)之間。', 'El nivel de seguridad debe estar entre {} (jugador) y {} (administrador).', 'El nivel de seguridad debe estar entre {} (jugador) y {} (administrador).', 'Уровень безопасности должен быть от {} (игрок) до {} (администратор).'), +(11022, 'Minimum account security level to log in: {}.', '로그인에 필요한 최소 계정 보안 등급: {}.', 'Niveau de sécurité de compte minimum pour se connecter : {}.', 'Mindest-Sicherheitsstufe des Kontos zum Anmelden: {}.', '登录所需的最低账号安全等级:{}。', '登入所需的最低帳號安全等級:{}。', 'Nivel de seguridad de cuenta mínimo para iniciar sesión: {}.', 'Nivel de seguridad de cuenta mínimo para iniciar sesión: {}.', 'Минимальный уровень безопасности учётной записи для входа: {}.'); + +DELETE FROM `command` WHERE `name` = 'server set security'; +INSERT INTO `command` (`name`, `security`, `help`) VALUES +('server set security', 4, 'Syntax: .server set security $level\r\n\r\nSets the minimum account security level (0 = player, 1 = moderator, 2 = gamemaster, 3 = administrator) allowed to log into the current realm. Updates realmlist.allowedSecurityLevel and applies immediately.'); diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index 1629b7a69..fa589fa23 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -116,6 +116,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_LAST_ATTEMPT_IP, "SELECT last_attempt_ip FROM account WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_LAST_IP, "SELECT last_ip FROM account WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL, "SELECT allowedSecurityLevel from realmlist WHERE id = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_REALMLIST_SECURITY_LEVEL, "UPDATE realmlist SET allowedSecurityLevel = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_ACCOUNT, "DELETE FROM account WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_AUTOBROADCAST, "SELECT id, weight, text FROM autobroadcast WHERE realmid = ? OR realmid = -1", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_AUTOBROADCAST_LOCALIZED, "SELECT id, locale, text FROM autobroadcast_locale WHERE realmid = ? OR realmid = -1", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h index a91f3dbe0..99e057b0c 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.h +++ b/src/server/database/Database/Implementation/LoginDatabase.h @@ -98,6 +98,7 @@ enum LoginDatabaseStatements : uint32 LOGIN_SEL_BANS, LOGIN_SEL_ACCOUNT_WHOIS, LOGIN_SEL_REALMLIST_SECURITY_LEVEL, + LOGIN_UPD_REALMLIST_SECURITY_LEVEL, LOGIN_DEL_ACCOUNT, LOGIN_SEL_AUTOBROADCAST, LOGIN_SEL_AUTOBROADCAST_LOCALIZED, diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 8a2a77585..aecb77882 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -700,6 +700,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_SPELLINFO_EFFECTS = 936, RBAC_PERM_COMMAND_SPELLINFO_TARGETS = 937, RBAC_PERM_COMMAND_SPELLINFO_ALL = 938, + RBAC_PERM_COMMAND_SERVER_SET_SECURITY = 939, // custom permissions 1000+ RBAC_PERM_MAX }; diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index ef158770b..e645954fb 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1400,6 +1400,10 @@ enum AcoreStrings LANG_LFG_COOLDOWN_CLEARED = 11019, + LANG_COMMAND_SERVER_SET_SECURITY = 11020, + LANG_COMMAND_SERVER_SET_SECURITY_ERROR = 11021, + LANG_COMMAND_SERVER_INFO_SECURITY = 11022, + LANG_MUTED_PLAYER = 30000, // Mute for player 2 hour // Instant Flight diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp index fd4c51e72..05370ba02 100644 --- a/src/server/scripts/Commands/cs_server.cpp +++ b/src/server/scripts/Commands/cs_server.cpp @@ -76,6 +76,7 @@ public: { "loglevel", HandleServerSetLogLevelCommand, rbac::RBAC_PERM_COMMAND_SERVER_SET_LOGLEVEL, Console::Yes }, { "motd", HandleServerSetMotdCommand, rbac::RBAC_PERM_COMMAND_SERVER_SET_MOTD, Console::Yes }, { "closed", HandleServerSetClosedCommand, rbac::RBAC_PERM_COMMAND_SERVER_SET_CLOSED, Console::Yes }, + { "security", HandleServerSetSecurityCommand, rbac::RBAC_PERM_COMMAND_SERVER_SET_SECURITY, Console::Yes }, }; static ChatCommandTable serverCommandTable = @@ -270,6 +271,7 @@ public: handler->PSendSysMessage("Connected players: {}. Characters in world: {}. Queue: {}.", activeSessionCount, playerCount, queuedSessionCount); handler->PSendSysMessage("Connection peak: {}.", connPeak); + handler->PSendSysMessage(LANG_COMMAND_SERVER_INFO_SECURITY, uint32(sWorld->GetPlayerSecurityLimit())); handler->PSendSysMessage(LANG_UPTIME, secsToTimeString(GameTime::GetUptime().count())); handler->PSendSysMessage("Update time diff: {}ms. Last {} diffs summary:", sWorldUpdateTime.GetLastUpdateTime(), sWorldUpdateTime.GetDatasetSize()); handler->PSendSysMessage("|- Mean: {}ms", sWorldUpdateTime.GetAverageUpdateTime()); @@ -600,6 +602,27 @@ public: return false; } + // Set the minimum security level allowed to log into this realm (realmlist.allowedSecurityLevel) + static bool HandleServerSetSecurityCommand(ChatHandler* handler, uint8 level) + { + if (level > SEC_ADMINISTRATOR) + { + handler->SendErrorMessage(LANG_COMMAND_SERVER_SET_SECURITY_ERROR, SEC_PLAYER, SEC_ADMINISTRATOR); + return false; + } + + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_REALMLIST_SECURITY_LEVEL); + stmt->SetData(0, level); + stmt->SetData(1, realm.Id.Realm); + LoginDatabase.Execute(stmt); + + // Apply live; raising the limit kicks any now-disallowed sessions. + sWorld->SetPlayerSecurityLimit(AccountTypes(level)); + + handler->PSendSysMessage(LANG_COMMAND_SERVER_SET_SECURITY, level); + return true; + } + // Set the level of logging static bool HandleServerSetLogLevelCommand(ChatHandler* /*handler*/, bool isLogger, std::string const& name, int32 level) {