From e596504d9335ea5abc08fecc3d1a447b57b03bc1 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 8 Oct 2019 14:43:01 +0200 Subject: [PATCH] * Auth/Battle.net Added missing build check to JoinRequest handler * Core/Commands: Battle.net account command changesisting accounts (6584995c11a02478671656ea6955db7a645b57ce) (0c27ffaa49c7e3e6880051ac74581cae51d83351) --- sql/base/auth_database.sql | 3 + sql/updates/auth/4.3.4/2019_10_08_00_auth.sql | 12 ++ .../world/4.3.4/2019_10_08_00_world.sql | 21 +++ src/server/bnetserver/Server/Session.cpp | 2 +- .../Database/Implementation/LoginDatabase.cpp | 6 +- .../Database/Implementation/LoginDatabase.h | 2 + src/server/game/Accounts/AccountMgr.cpp | 12 +- src/server/game/Accounts/AccountMgr.h | 5 +- .../game/Accounts/BattlenetAccountMgr.cpp | 98 +++++++++++--- .../game/Accounts/BattlenetAccountMgr.h | 3 + src/server/game/Accounts/RBAC.h | 6 +- src/server/game/Miscellaneous/Language.h | 7 +- .../scripts/Commands/cs_battlenet_account.cpp | 123 +++++++++++++++++- 13 files changed, 266 insertions(+), 34 deletions(-) create mode 100644 sql/updates/auth/4.3.4/2019_10_08_00_auth.sql create mode 100644 sql/updates/world/4.3.4/2019_10_08_00_world.sql diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index c870dec2049..cb5b0fc468a 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -570,6 +570,9 @@ INSERT INTO `rbac_linked_permissions` VALUES (196,208), (196,212), (196,213), +(196,214), +(196,215), +(196,216), (196,226), (196,227), (196,230), diff --git a/sql/updates/auth/4.3.4/2019_10_08_00_auth.sql b/sql/updates/auth/4.3.4/2019_10_08_00_auth.sql new file mode 100644 index 00000000000..73697e66834 --- /dev/null +++ b/sql/updates/auth/4.3.4/2019_10_08_00_auth.sql @@ -0,0 +1,12 @@ + +DELETE FROM `rbac_permissions` WHERE `id` IN (214,215,216); +INSERT INTO `rbac_permissions` (`id`, `name`) VALUES +(214, 'Command: bnetaccount link'), +(215, 'Command: bnetaccount unlink'), +(216, 'Command: bnetaccount gameaccountcreate'); + +DELETE FROM `rbac_linked_permissions` WHERE `linkedId` IN (214,215,216); +INSERT INTO `rbac_linked_permissions` (`id`, `linkedId`) VALUES +(196, 214), +(196, 215), +(196, 216); diff --git a/sql/updates/world/4.3.4/2019_10_08_00_world.sql b/sql/updates/world/4.3.4/2019_10_08_00_world.sql new file mode 100644 index 00000000000..2c5f9feb801 --- /dev/null +++ b/sql/updates/world/4.3.4/2019_10_08_00_world.sql @@ -0,0 +1,21 @@ +DELETE FROM `command` WHERE `name` LIKE '%battlenetaccount%'; +DELETE FROM `command` WHERE `name` LIKE '%bnetaccount%'; +INSERT INTO `command` (`name`, `permission`, `help`) VALUES +('bnetaccount', 207, 'Syntax: .bnetaccount $subcommand\nType .bnetaccount to see the list of possible subcommands or .help account set $subcommand to see info on subcommands.'), +('bnetaccount create', 208, 'Syntax: .bnetaccount create $account $password\nCreate battle.net account and set password to it. Account must contain the @ symbol.'), +('bnetaccount lock country', 209, 'Syntax: .bnetaccount lock country [on|off]\nAllow login to account only from current used Country or remove this requirement.'), +('bnetaccount lock ip', 210, 'Syntax: .bnetaccount lock ip [on|off]\nAllow login to account only from current used IP or remove this requirement.'), +('bnetaccount password', 211, 'Syntax: .bnetaccount password $old_password $new_password $new_password\nChange your account password.'), +('bnetaccount set', 212, 'Syntax: .bnetaccount set $subcommand\nType .bnetaccount set to see the list of possible subcommands or .help bnetaccount set $subcommand to see info on subcommands.'), +('bnetaccount set password', 213, 'Syntax: .bnetaccount set password $account $password $password\nSet password for account.'), +('bnetaccount link', 214, 'Syntax: .bnetaccount link $email $login\nLinks battle.net account ($email) to an existing game account ($login).'), +('bnetaccount unlink', 215, 'Syntax: .bnetaccount unlink $gameaccount $password\nRemoves battle.net account link from $gameaccount'), +('bnetaccount gameaccountcreate', 216, 'Syntax: .bnetaccount gameaccountcreate $account\nCreate additional game account for specified battle.net account.'); + +DELETE FROM `trinity_string` WHERE `entry` BETWEEN 1185 AND 1189; +INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES +(1036, 'Battle.net account %s was linked with game account %s.'), +(1037, 'Battle.net account %s or game account %s does not exist.'), +(1038, 'Game account %s is already linked with a battle.net account.'), +(1039, 'Game account %s had its battle.net account link removed.'), +(1040, 'Game account %s is not linked to any battle.net account.'); diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 4da0037fd5c..47181e7aa94 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -472,7 +472,7 @@ void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& join { WoWRealm::JoinResponseV2* joinResponse = new WoWRealm::JoinResponseV2(); Realm const* realm = sBNetRealmList->GetRealm(joinRequest.Realm); - if (!realm || realm->Flags & (REALM_FLAG_VERSION_MISMATCH | REALM_FLAG_OFFLINE)) + if (!realm || realm->Flags & (REALM_FLAG_VERSION_MISMATCH | REALM_FLAG_OFFLINE) || realm->Build != _build) { joinResponse->Response = WoWRealm::JoinResponseV2::FAILURE; AsyncWrite(joinResponse); diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index bbf1ccc53ed..a46d22d3585 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -64,7 +64,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_REALM_CHARACTERS, "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, reg_mail, email, joindate) VALUES(?, ?, ?, ?, NOW())", CONNECTION_SYNCH); + PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, reg_mail, email, joindate, battlenet_account, battlenet_index) VALUES(?, ?, ?, ?, NOW(), ?, ?)", CONNECTION_SYNCH); PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid = account.id WHERE acctid IS NULL", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_EXPANSION, "UPDATE account SET expansion = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK, "UPDATE account SET locked = ? WHERE id = ?", CONNECTION_ASYNC); @@ -138,7 +138,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_UPD_BNET_FAILED_LOGINS, "UPDATE battlenet_accounts SET failed_logins = failed_logins + 1 WHERE email = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS, "SELECT rc.numchars, r.id, r.Region, r.Battlegroup, r.gamebuild FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_INS_BNET_ACCOUNT, "INSERT INTO battlenet_accounts (`email`,`sha_pass_hash`) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_INS_BNET_ACCOUNT, "INSERT INTO battlenet_accounts (`email`,`sha_pass_hash`) VALUES (?, ?)", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID, "SELECT email FROM battlenet_accounts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL, "SELECT id FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_PASSWORD, "UPDATE battlenet_accounts SET v = '', s = '', sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC); @@ -146,6 +146,8 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK, "UPDATE battlenet_accounts SET locked = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK_COUNTRY, "UPDATE battlenet_accounts SET lock_country = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT, "SELECT battlenet_account FROM account WHERE id = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LINK, "UPDATE account SET battlenet_account = ?, battlenet_index = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_MAX_ACCOUNT_INDEX, "SELECT MAX(battlenet_index) FROM account WHERE battlenet_account = ?", CONNECTION_SYNCH); } LoginDatabaseConnection::LoginDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h index 86273c20835..2d2d7920526 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.h +++ b/src/server/database/Database/Implementation/LoginDatabase.h @@ -128,6 +128,8 @@ enum LoginDatabaseStatements : uint32 LOGIN_UPD_BNET_ACCOUNT_LOCK, LOGIN_UPD_BNET_ACCOUNT_LOCK_COUNTRY, LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT, + LOGIN_UPD_BNET_GAME_ACCOUNT_LINK, + LOGIN_SEL_BNET_MAX_ACCOUNT_INDEX, MAX_LOGINDATABASE_STATEMENTS }; diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index b2dc5810709..15291c3ca4c 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -42,7 +42,7 @@ AccountMgr* AccountMgr::instance() return &instance; } -AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email /*= ""*/) +AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email /*= ""*/, uint32 bnetAccountId /*= 0*/, uint8 bnetIndex /*= 0*/) { if (utf8length(username) > MAX_ACCOUNT_STR) return AccountOpResult::AOR_NAME_TOO_LONG; // username's too long @@ -63,6 +63,16 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass stmt->setString(1, CalculateShaPassHash(username, password)); stmt->setString(2, email); stmt->setString(3, email); + if (bnetAccountId && bnetIndex) + { + stmt->setUInt32(4, bnetAccountId); + stmt->setUInt8(5, bnetIndex); + } + else + { + stmt->setNull(4); + stmt->setNull(5); + } LoginDatabase.DirectExecute(stmt); // Enforce saving, otherwise AddGroup can fail diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h index 0a6f6b4c028..ca5ed35943b 100644 --- a/src/server/game/Accounts/AccountMgr.h +++ b/src/server/game/Accounts/AccountMgr.h @@ -29,7 +29,8 @@ enum class AccountOpResult : uint8 AOR_EMAIL_TOO_LONG, AOR_NAME_ALREADY_EXIST, AOR_NAME_NOT_EXIST, - AOR_DB_INTERNAL_ERROR + AOR_DB_INTERNAL_ERROR, + AOR_ACCOUNT_BAD_LINK }; enum PasswordChangeSecurity @@ -58,7 +59,7 @@ class TC_GAME_API AccountMgr public: static AccountMgr* instance(); - AccountOpResult CreateAccount(std::string username, std::string password, std::string email = ""); + AccountOpResult CreateAccount(std::string username, std::string password, std::string email = "", uint32 bnetAccountId = 0, uint8 bnetIndex = 0); static AccountOpResult DeleteAccount(uint32 accountId); static AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); static AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); diff --git a/src/server/game/Accounts/BattlenetAccountMgr.cpp b/src/server/game/Accounts/BattlenetAccountMgr.cpp index 54058624df0..7d9f3fcd2ed 100644 --- a/src/server/game/Accounts/BattlenetAccountMgr.cpp +++ b/src/server/game/Accounts/BattlenetAccountMgr.cpp @@ -21,6 +21,8 @@ #include "Util.h" #include "SHA256.h" +using GameAccountMgr = AccountMgr; + AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, std::string password) { if (utf8length(email) > MAX_BNET_EMAIL_STR) @@ -38,7 +40,12 @@ AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ACCOUNT); stmt->setString(0, email); stmt->setString(1, CalculateShaPassHash(email, password)); - LoginDatabase.Execute(stmt); + LoginDatabase.DirectExecute(stmt); + + uint32 newAccountId = GetId(email); + ASSERT(newAccountId); + + GameAccountMgr::instance()->CreateAccount(std::to_string(newAccountId) + "#1", password, email, newAccountId, 1); return AccountOpResult::AOR_OK; } @@ -62,6 +69,61 @@ AccountOpResult Battlenet::AccountMgr::ChangePassword(uint32 accountId, std::str return AccountOpResult::AOR_OK; } +bool Battlenet::AccountMgr::CheckPassword(uint32 accountId, std::string password) +{ + std::string username; + + if (!GetName(accountId, username)) + return false; + + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHECK_PASSWORD); + stmt->setUInt32(0, accountId); + stmt->setString(1, CalculateShaPassHash(username, password)); + + return LoginDatabase.Query(stmt) != nullptr; +} + +AccountOpResult Battlenet::AccountMgr::LinkWithGameAccount(std::string const& email, std::string const& gameAccountName) +{ + uint32 bnetAccountId = GetId(email); + if (!bnetAccountId) + return AccountOpResult::AOR_NAME_NOT_EXIST; + + uint32 gameAccountId = GameAccountMgr::GetId(gameAccountName); + if (!gameAccountId) + return AccountOpResult::AOR_NAME_NOT_EXIST; + + if (GetIdByGameAccount(gameAccountId)) + return AccountOpResult::AOR_ACCOUNT_BAD_LINK; + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LINK); + stmt->setUInt32(0, bnetAccountId); + stmt->setUInt8(1, GetMaxIndex(bnetAccountId) + 1); + stmt->setUInt32(2, gameAccountId); + LoginDatabase.Execute(stmt); + return AccountOpResult::AOR_OK; +} + +AccountOpResult Battlenet::AccountMgr::UnlinkGameAccount(std::string const& gameAccountName) +{ + uint32 gameAccountId = GameAccountMgr::GetId(gameAccountName); + if (!gameAccountId) + return AccountOpResult::AOR_NAME_NOT_EXIST; + + if (!GetIdByGameAccount(gameAccountId)) + return AccountOpResult::AOR_ACCOUNT_BAD_LINK; + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LINK); + stmt->setNull(0); + stmt->setNull(1); + stmt->setUInt32(2, gameAccountId); + LoginDatabase.Execute(stmt); + return AccountOpResult::AOR_OK; +} + uint32 Battlenet::AccountMgr::GetId(std::string const& username) { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL); @@ -72,16 +134,6 @@ uint32 Battlenet::AccountMgr::GetId(std::string const& username) return 0; } -uint32 Battlenet::AccountMgr::GetIdByGameAccount(uint32 gameAccountId) -{ - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT); - stmt->setUInt32(0, gameAccountId); - if (PreparedQueryResult result = LoginDatabase.Query(stmt)) - return (*result)[0].GetUInt32(); - - return 0; -} - bool Battlenet::AccountMgr::GetName(uint32 accountId, std::string& name) { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID); @@ -95,21 +147,25 @@ bool Battlenet::AccountMgr::GetName(uint32 accountId, std::string& name) return false; } -bool Battlenet::AccountMgr::CheckPassword(uint32 accountId, std::string password) +uint32 Battlenet::AccountMgr::GetIdByGameAccount(uint32 gameAccountId) { - std::string username; + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT); + stmt->setUInt32(0, gameAccountId); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + return (*result)[0].GetUInt32(); - if (!GetName(accountId, username)) - return false; + return 0; +} - Utf8ToUpperOnlyLatin(username); - Utf8ToUpperOnlyLatin(password); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHECK_PASSWORD); +uint8 Battlenet::AccountMgr::GetMaxIndex(uint32 accountId) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_MAX_ACCOUNT_INDEX); stmt->setUInt32(0, accountId); - stmt->setString(1, CalculateShaPassHash(username, password)); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (result) + return (*result)[0].GetUInt8(); - return LoginDatabase.Query(stmt) != nullptr; + return 0; } std::string Battlenet::AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) diff --git a/src/server/game/Accounts/BattlenetAccountMgr.h b/src/server/game/Accounts/BattlenetAccountMgr.h index f41f46bd2f8..78aad83b992 100644 --- a/src/server/game/Accounts/BattlenetAccountMgr.h +++ b/src/server/game/Accounts/BattlenetAccountMgr.h @@ -32,10 +32,13 @@ namespace Battlenet TC_GAME_API AccountOpResult CreateBattlenetAccount(std::string email, std::string password); TC_GAME_API AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); TC_GAME_API bool CheckPassword(uint32 accountId, std::string password); + TC_GAME_API AccountOpResult LinkWithGameAccount(std::string const& email, std::string const& gameAccountName); + TC_GAME_API AccountOpResult UnlinkGameAccount(std::string const& gameAccountName); TC_GAME_API uint32 GetId(std::string const& username); TC_GAME_API bool GetName(uint32 accountId, std::string& name); TC_GAME_API uint32 GetIdByGameAccount(uint32 gameAccountId); + TC_GAME_API uint8 GetMaxIndex(uint32 accountId); std::string CalculateShaPassHash(std::string const& name, std::string const& password); } diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 2c67709d13d..94df020bc43 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -119,9 +119,9 @@ enum RBACPermissions RBAC_PERM_COMMAND_BNET_ACCOUNT_PASSWORD = 211, // not on 3.3.5a RBAC_PERM_COMMAND_BNET_ACCOUNT_SET = 212, // not on 3.3.5a RBAC_PERM_COMMAND_BNET_ACCOUNT_SET_PASSWORD = 213, // not on 3.3.5a - RBAC_PERM_COMMAND_BNET_ACCOUNT_LINK = 214, // not on 3.3.5a or 4.3.4 - RBAC_PERM_COMMAND_BNET_ACCOUNT_UNLINK = 215, // not on 3.3.5a or 4.3.4 - RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE_GAME = 216, // not on 3.3.5a or 4.3.4 + RBAC_PERM_COMMAND_BNET_ACCOUNT_LINK = 214, // not on 3.3.5a + RBAC_PERM_COMMAND_BNET_ACCOUNT_UNLINK = 215, // not on 3.3.5a + RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE_GAME = 216, // not on 3.3.5a RBAC_PERM_COMMAND_ACCOUNT = 217, RBAC_PERM_COMMAND_ACCOUNT_ADDON = 218, RBAC_PERM_COMMAND_ACCOUNT_CREATE = 219, diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index b034f030460..87986d55943 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -837,7 +837,12 @@ enum TrinityStrings LANG_ACCOUNT_CREATED_BNET = 1033, // master branch ONLY LANG_ACCOUNT_BNET_LIST_HEADER = 1034, // master branch ONLY LANG_ACCOUNT_BNET_LIST_NO_ACCOUNTS = 1035, // master branch ONLY - // Room for more level 4 1036-1099 not used + LANG_ACCOUNT_BNET_LINKED = 1036, + LANG_ACCOUNT_OR_BNET_DOES_NOT_EXIST = 1037, + LANG_ACCOUNT_ALREADY_LINKED = 1036, + LANG_ACCOUNT_BNET_UNLINKED = 1039, + LANG_ACCOUNT_BNET_NOT_LINKED = 1040, + // Room for more level 4 1041-1099 not used // Level 3 (continue) LANG_ACCOUNT_SETADDON = 1100, diff --git a/src/server/scripts/Commands/cs_battlenet_account.cpp b/src/server/scripts/Commands/cs_battlenet_account.cpp index a71e30a410b..c5338d5e9ce 100644 --- a/src/server/scripts/Commands/cs_battlenet_account.cpp +++ b/src/server/scripts/Commands/cs_battlenet_account.cpp @@ -49,14 +49,17 @@ public: static std::vector accountCommandTable = { { "create", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE, true, &HandleAccountCreateCommand, "" }, - { "lock", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT, false, nullptr, "", accountLockCommandTable }, - { "set", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_SET, true, nullptr, "", accountSetCommandTable }, + { "gameaccountcreate", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE_GAME, true, &HandleGameAccountCreateCommand, "", }, + { "lock", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT, false, nullptr, "", accountLockCommandTable }, + { "set", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_SET, true, nullptr, "", accountSetCommandTable }, { "password", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_PASSWORD, false, &HandleAccountPasswordCommand, "" }, + { "link", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_LINK, true, &HandleAccountLinkCommand, "", }, + { "unlink", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_UNLINK, true, &HandleAccountUnlinkCommand, "", }, }; static std::vector commandTable = { - { "battlenetaccount", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT, true, nullptr, "", accountCommandTable }, + { "bnetaccount", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT, true, nullptr, "", accountCommandTable }, }; return commandTable; @@ -323,6 +326,120 @@ public: } return true; } + + static bool HandleAccountLinkCommand(ChatHandler* handler, char const* args) + { + Tokenizer tokens(args, ' ', 2); + if (tokens.size() != 2) + { + handler->SendSysMessage(LANG_CMD_SYNTAX); + handler->SetSentErrorMessage(true); + return false; + } + + std::string bnetAccountName = tokens[0]; + std::string gameAccountName = tokens[1]; + + switch (Battlenet::AccountMgr::LinkWithGameAccount(bnetAccountName, gameAccountName)) + { + case AccountOpResult::AOR_OK: + handler->PSendSysMessage(LANG_ACCOUNT_BNET_LINKED, bnetAccountName.c_str(), gameAccountName.c_str()); + break; + case AccountOpResult::AOR_NAME_NOT_EXIST: + handler->PSendSysMessage(LANG_ACCOUNT_OR_BNET_DOES_NOT_EXIST, bnetAccountName.c_str(), gameAccountName.c_str()); + handler->SetSentErrorMessage(true); + break; + case AccountOpResult::AOR_ACCOUNT_BAD_LINK: + handler->PSendSysMessage(LANG_ACCOUNT_ALREADY_LINKED, gameAccountName.c_str()); + handler->SetSentErrorMessage(true); + break; + } + + return true; + } + + static bool HandleAccountUnlinkCommand(ChatHandler* handler, char const* args) + { + if (!*args) + { + handler->SendSysMessage(LANG_CMD_SYNTAX); + handler->SetSentErrorMessage(true); + return false; + } + + std::string gameAccountName = args; + + switch (Battlenet::AccountMgr::UnlinkGameAccount(gameAccountName)) + { + case AccountOpResult::AOR_OK: + handler->PSendSysMessage(LANG_ACCOUNT_BNET_UNLINKED, gameAccountName.c_str()); + break; + case AccountOpResult::AOR_NAME_NOT_EXIST: + handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, gameAccountName.c_str()); + handler->SetSentErrorMessage(true); + break; + case AccountOpResult::AOR_ACCOUNT_BAD_LINK: + handler->PSendSysMessage(LANG_ACCOUNT_BNET_NOT_LINKED, gameAccountName.c_str()); + handler->SetSentErrorMessage(true); + break; + } + + return true; + } + + static bool HandleGameAccountCreateCommand(ChatHandler* handler, char const* args) + { + if (!*args) + { + handler->SendSysMessage(LANG_CMD_SYNTAX); + handler->SetSentErrorMessage(true); + return false; + } + + std::string bnetAccountName = args; + uint32 accountId = Battlenet::AccountMgr::GetId(bnetAccountName); + if (!accountId) + { + handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, bnetAccountName.c_str()); + handler->SetSentErrorMessage(true); + return false; + } + + uint8 index = Battlenet::AccountMgr::GetMaxIndex(accountId) + 1; + std::string accountName = std::to_string(accountId) + '#' + std::to_string(uint32(index)); + + switch (sAccountMgr->CreateAccount(accountName, "DUMMY", bnetAccountName, accountId, index)) + { + case AccountOpResult::AOR_OK: + handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName.c_str()); + if (handler->GetSession()) + { + TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (%s) created Account %s (Email: '%s')", + handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), + handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUID().ToString().c_str(), + accountName.c_str(), bnetAccountName.c_str()); + } + break; + case AccountOpResult::AOR_NAME_TOO_LONG: + handler->SendSysMessage(LANG_ACCOUNT_NAME_TOO_LONG); + handler->SetSentErrorMessage(true); + return false; + case AccountOpResult::AOR_NAME_ALREADY_EXIST: + handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST); + handler->SetSentErrorMessage(true); + return false; + case AccountOpResult::AOR_DB_INTERNAL_ERROR: + handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, accountName.c_str()); + handler->SetSentErrorMessage(true); + return false; + default: + handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED, accountName.c_str()); + handler->SetSentErrorMessage(true); + return false; + } + + return true; + } }; void AddSC_battlenet_account_commandscript()