TrinityCore
cs_battlenet_account.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "AccountMgr.h"
19#include "BattlenetAccountMgr.h"
20#include "Chat.h"
21#include "ChatCommand.h"
22#include "CryptoRandom.h"
23#include "DatabaseEnv.h"
24#include "IpAddress.h"
25#include "IPLocation.h"
26#include "Language.h"
27#include "Log.h"
28#include "Player.h"
29#include "ScriptMgr.h"
30#include "Util.h"
31#include "WorldSession.h"
32
33using namespace Trinity::ChatCommands;
34
36{
37public:
38 battlenet_account_commandscript() : CommandScript("battlenet_account_commandscript") { }
39
41 {
42 static ChatCommandTable accountSetCommandTable =
43 {
45 };
46 static ChatCommandTable accountLockCommandTable =
47 {
50 };
51 static ChatCommandTable accountCommandTable =
52 {
55 { "lock", accountLockCommandTable },
56 { "set", accountSetCommandTable },
61 };
62 static ChatCommandTable commandTable =
63 {
64 { "bnetaccount", accountCommandTable },
65 };
66
67 return commandTable;
68 }
69
71 static bool HandleAccountCreateCommand(ChatHandler* handler, std::string const& accountName, std::string const& password, Optional<bool> createGameAccount)
72 {
73 if (accountName.find('@') == std::string::npos)
74 {
76 handler->SetSentErrorMessage(true);
77 return false;
78 }
79
80 std::string gameAccountName;
81 switch (Battlenet::AccountMgr::CreateBattlenetAccount(accountName, password, createGameAccount.value_or(true), &gameAccountName))
82 {
84 {
85 if (createGameAccount != false)
86 handler->PSendSysMessage(LANG_ACCOUNT_CREATED_BNET_WITH_GAME, accountName.c_str(), gameAccountName.c_str());
87 else
88 handler->PSendSysMessage(LANG_ACCOUNT_CREATED_BNET, accountName.c_str());
89
90 if (handler->GetSession())
91 {
92 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] ({}) created Battle.net account {}{}{}",
93 handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress(),
94 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString(),
95 accountName, createGameAccount != false ? " with game account " : "", createGameAccount != false ? gameAccountName.c_str() : "");
96 }
97 break;
98 }
101 handler->SetSentErrorMessage(true);
102 return false;
105 handler->SetSentErrorMessage(true);
106 return false;
109 handler->SetSentErrorMessage(true);
110 return false;
111 default:
112 break;
113 }
114
115 return true;
116 }
117
118 // Sets country lock on own account
119 static bool HandleAccountLockCountryCommand(ChatHandler* handler, bool state)
120 {
121 if (state)
122 {
123 if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(handler->GetSession()->GetRemoteAddress()))
124 {
126 stmt->setString(0, location->CountryCode);
127 stmt->setUInt32(1, handler->GetSession()->GetBattlenetAccountId());
128 LoginDatabase.Execute(stmt);
130 }
131 else
132 {
133 handler->PSendSysMessage("IP2Location] No information");
134 TC_LOG_DEBUG("server.bnetserver", "IP2Location] No information");
135 }
136 }
137 else
138 {
140 stmt->setString(0, "00");
141 stmt->setUInt32(1, handler->GetSession()->GetBattlenetAccountId());
142 LoginDatabase.Execute(stmt);
144 }
145 return true;
146 }
147
148 // Sets ip lock on own account
149 static bool HandleAccountLockIpCommand(ChatHandler* handler, bool state)
150 {
152
153 if (state)
154 {
155 stmt->setBool(0, true); // locked
157 }
158 else
159 {
160 stmt->setBool(0, false); // unlocked
162 }
163
164 stmt->setUInt32(1, handler->GetSession()->GetBattlenetAccountId());
165
166 LoginDatabase.Execute(stmt);
167 return true;
168 }
169
170 static bool HandleAccountPasswordCommand(ChatHandler* handler, std::string const& oldPassword, std::string const& newPassword, std::string const& passwordConfirmation)
171 {
172 // We compare the old, saved password to the entered old password - no chance for the unauthorized.
173 if (!Battlenet::AccountMgr::CheckPassword(handler->GetSession()->GetBattlenetAccountId(), std::string(oldPassword)))
174 {
176 handler->SetSentErrorMessage(true);
177 TC_LOG_INFO("entities.player.character", "Battle.net account: {} (IP: {}) Character:[{}] ({}) Tried to change password, but the provided old password is wrong.",
178 handler->GetSession()->GetBattlenetAccountId(), handler->GetSession()->GetRemoteAddress(),
179 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString());
180 return false;
181 }
182
183 // Making sure that newly entered password is correctly entered.
184 if (newPassword != passwordConfirmation)
185 {
187 handler->SetSentErrorMessage(true);
188 return false;
189 }
190
191 // Changes password and prints result.
192 AccountOpResult result = Battlenet::AccountMgr::ChangePassword(handler->GetSession()->GetBattlenetAccountId(), std::string(newPassword));
193 switch (result)
194 {
197 TC_LOG_INFO("entities.player.character", "Battle.net account: {} (IP: {}) Character:[{}] ({}) Changed Password.",
198 handler->GetSession()->GetBattlenetAccountId(), handler->GetSession()->GetRemoteAddress(),
199 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString());
200 break;
203 handler->SetSentErrorMessage(true);
204 return false;
205 default:
207 handler->SetSentErrorMessage(true);
208 return false;
209 }
210
211 return true;
212 }
213
215 static bool HandleAccountSetPasswordCommand(ChatHandler* handler, std::string accountName, std::string const& password, std::string const& passwordConfirmation)
216 {
217 if (!Utf8ToUpperOnlyLatin(accountName))
218 {
219 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
220 handler->SetSentErrorMessage(true);
221 return false;
222 }
223
224 uint32 targetAccountId = Battlenet::AccountMgr::GetId(accountName);
225 if (!targetAccountId)
226 {
227 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
228 handler->SetSentErrorMessage(true);
229 return false;
230 }
231
232 if (password != passwordConfirmation)
233 {
235 handler->SetSentErrorMessage(true);
236 return false;
237 }
238
239 AccountOpResult result = Battlenet::AccountMgr::ChangePassword(targetAccountId, password);
240 switch (result)
241 {
244 break;
246 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
247 handler->SetSentErrorMessage(true);
248 return false;
251 handler->SetSentErrorMessage(true);
252 return false;
253 default:
254 break;
255 }
256 return true;
257 }
258
259 static bool HandleAccountLinkCommand(ChatHandler* handler, std::string const& bnetAccountName, std::string const& gameAccountName)
260 {
261 switch (Battlenet::AccountMgr::LinkWithGameAccount(bnetAccountName, gameAccountName))
262 {
264 handler->PSendSysMessage(LANG_ACCOUNT_BNET_LINKED, bnetAccountName.c_str(), gameAccountName.c_str());
265 break;
267 handler->PSendSysMessage(LANG_ACCOUNT_OR_BNET_DOES_NOT_EXIST, bnetAccountName.c_str(), gameAccountName.c_str());
268 handler->SetSentErrorMessage(true);
269 break;
271 handler->PSendSysMessage(LANG_ACCOUNT_ALREADY_LINKED, gameAccountName.c_str());
272 handler->SetSentErrorMessage(true);
273 break;
274 default:
275 break;
276 }
277
278 return true;
279 }
280
281 static bool HandleAccountUnlinkCommand(ChatHandler* handler, std::string const& gameAccountName)
282 {
283 switch (Battlenet::AccountMgr::UnlinkGameAccount(gameAccountName))
284 {
286 handler->PSendSysMessage(LANG_ACCOUNT_BNET_UNLINKED, gameAccountName.c_str());
287 break;
289 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, gameAccountName.c_str());
290 handler->SetSentErrorMessage(true);
291 break;
293 handler->PSendSysMessage(LANG_ACCOUNT_BNET_NOT_LINKED, gameAccountName.c_str());
294 handler->SetSentErrorMessage(true);
295 break;
296 default:
297 break;
298 }
299
300 return true;
301 }
302
303 static bool HandleGameAccountCreateCommand(ChatHandler* handler, std::string const& bnetAccountName)
304 {
305 uint32 accountId = Battlenet::AccountMgr::GetId(bnetAccountName);
306 if (!accountId)
307 {
308 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, bnetAccountName.c_str());
309 handler->SetSentErrorMessage(true);
310 return false;
311 }
312
313 uint8 index = Battlenet::AccountMgr::GetMaxIndex(accountId) + 1;
314 std::string accountName = std::to_string(accountId) + '#' + std::to_string(uint32(index));
315
316 // Generate random hex string for password, these accounts must not be logged on with GRUNT
317 std::array<uint8, 8> randPassword = Trinity::Crypto::GetRandomBytes<8>();
318
319 switch (sAccountMgr->CreateAccount(accountName, ByteArrayToHexStr(randPassword), bnetAccountName, accountId, index))
320 {
322 handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName.c_str());
323 if (handler->GetSession())
324 {
325 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] ({}) created Account {} (Email: '{}')",
326 handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress(),
327 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString(),
328 accountName, bnetAccountName);
329 }
330 break;
333 handler->SetSentErrorMessage(true);
334 return false;
337 handler->SetSentErrorMessage(true);
338 return false;
341 handler->SetSentErrorMessage(true);
342 return false;
344 handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, accountName.c_str());
345 handler->SetSentErrorMessage(true);
346 return false;
347 default:
348 handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED, accountName.c_str());
349 handler->SetSentErrorMessage(true);
350 return false;
351 }
352
353 return true;
354 }
355
356 static bool HandleListGameAccountsCommand(ChatHandler* handler, std::string const& battlenetAccountName)
357 {
359 stmt->setStringView(0, battlenetAccountName);
360 if (PreparedQueryResult accountList = LoginDatabase.Query(stmt))
361 {
362 auto formatDisplayName = [](char const* name) -> std::string
363 {
364 if (char const* hashPos = strchr(name, '#'))
365 return std::string("WoW") + ++hashPos;
366 else
367 return name;
368 };
369
370 handler->SendSysMessage("----------------------------------------------------");
372 handler->SendSysMessage("----------------------------------------------------");
373 do
374 {
375 Field* fields = accountList->Fetch();
376 handler->PSendSysMessage("| %10u | %-16.16s | %-16.16s |", fields[0].GetUInt32(), fields[1].GetCString(), formatDisplayName(fields[1].GetCString()).c_str());
377 } while (accountList->NextRow());
378 handler->SendSysMessage("----------------------------------------------------");
379 }
380 else
381 handler->PSendSysMessage(LANG_ACCOUNT_BNET_LIST_NO_ACCOUNTS, battlenetAccountName);
382
383 return true;
384 }
385};
386
388{
390}
AccountOpResult
Definition: AccountMgr.h:24
#define sAccountMgr
Definition: AccountMgr.h:98
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
uint8_t uint8
Definition: Define.h:144
uint32_t uint32
Definition: Define.h:142
#define sIPLocation
Definition: IPLocation.h:51
@ LANG_ACCOUNT_ALREADY_EXIST
Definition: Language.h:840
@ LANG_ACCOUNT_CREATED_BNET
Definition: Language.h:867
@ LANG_COMMAND_NOTCHANGEPASSWORD
Definition: Language.h:57
@ LANG_COMMAND_ACCLOCKLOCKED
Definition: Language.h:60
@ LANG_ACCOUNT_PASS_TOO_LONG
Definition: Language.h:865
@ LANG_ACCOUNT_OR_BNET_DOES_NOT_EXIST
Definition: Language.h:990
@ LANG_ACCOUNT_BNET_NOT_LINKED
Definition: Language.h:993
@ LANG_PASSWORD_TOO_LONG
Definition: Language.h:87
@ LANG_ACCOUNT_BNET_LIST_HEADER
Definition: Language.h:868
@ LANG_COMMAND_WRONGOLDPASSWORD
Definition: Language.h:59
@ LANG_ACCOUNT_ALREADY_LINKED
Definition: Language.h:991
@ LANG_ACCOUNT_CREATED_BNET_WITH_GAME
Definition: Language.h:866
@ LANG_COMMAND_ACCLOCKUNLOCKED
Definition: Language.h:61
@ LANG_ACCOUNT_BNET_LIST_NO_ACCOUNTS
Definition: Language.h:869
@ LANG_ACCOUNT_BNET_LINKED
Definition: Language.h:989
@ LANG_ACCOUNT_NOT_CREATED_SQL_ERROR
Definition: Language.h:841
@ LANG_ACCOUNT_NOT_CREATED
Definition: Language.h:842
@ LANG_ACCOUNT_INVALID_BNET_NAME
Definition: Language.h:863
@ LANG_ACCOUNT_CREATED
Definition: Language.h:838
@ LANG_ACCOUNT_BNET_UNLINKED
Definition: Language.h:992
@ LANG_NEW_PASSWORDS_NOT_MATCH
Definition: Language.h:86
@ LANG_ACCOUNT_NOT_EXIST
Definition: Language.h:470
@ LANG_COMMAND_PASSWORD
Definition: Language.h:58
@ LANG_ACCOUNT_NAME_TOO_LONG
Definition: Language.h:839
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
@ LOGIN_UPD_BNET_ACCOUNT_LOCK
@ LOGIN_SEL_BNET_GAME_ACCOUNT_LIST_SMALL
@ LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
bool Utf8ToUpperOnlyLatin(std::string &utf8String)
Definition: Util.cpp:795
std::string ByteArrayToHexStr(Container const &c, bool reverse=false)
Definition: Util.h:368
WorldSession * GetSession()
Definition: Chat.h:42
void PSendSysMessage(const char *fmt, Args &&... args)
Definition: Chat.h:57
void SetSentErrorMessage(bool val)
Definition: Chat.h:114
virtual void SendSysMessage(std::string_view str, bool escapeCharacters=false)
Definition: Chat.cpp:113
Class used to access individual fields of database query result.
Definition: Field.h:90
char const * GetCString() const
Definition: Field.cpp:110
std::string ToString() const
Definition: ObjectGuid.cpp:554
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
void setStringView(const uint8 index, const std::string_view value)
void setBool(const uint8 index, const bool value)
void setUInt32(const uint8 index, const uint32 value)
void setString(const uint8 index, const std::string &value)
std::string const & GetName() const
Definition: Object.h:555
Player * GetPlayer() const
std::string const & GetRemoteAddress() const
uint32 GetBattlenetAccountId() const
uint32 GetAccountId() const
static bool HandleAccountPasswordCommand(ChatHandler *handler, std::string const &oldPassword, std::string const &newPassword, std::string const &passwordConfirmation)
static bool HandleAccountLockIpCommand(ChatHandler *handler, bool state)
static bool HandleListGameAccountsCommand(ChatHandler *handler, std::string const &battlenetAccountName)
static bool HandleAccountSetPasswordCommand(ChatHandler *handler, std::string accountName, std::string const &password, std::string const &passwordConfirmation)
Set password for account.
ChatCommandTable GetCommands() const override
static bool HandleAccountLockCountryCommand(ChatHandler *handler, bool state)
static bool HandleAccountLinkCommand(ChatHandler *handler, std::string const &bnetAccountName, std::string const &gameAccountName)
static bool HandleAccountCreateCommand(ChatHandler *handler, std::string const &accountName, std::string const &password, Optional< bool > createGameAccount)
Create an account.
static bool HandleAccountUnlinkCommand(ChatHandler *handler, std::string const &gameAccountName)
static bool HandleGameAccountCreateCommand(ChatHandler *handler, std::string const &bnetAccountName)
void AddSC_battlenet_account_commandscript()
TC_GAME_API AccountOpResult LinkWithGameAccount(std::string_view email, std::string_view gameAccountName)
TC_GAME_API AccountOpResult ChangePassword(uint32 accountId, std::string newPassword)
TC_GAME_API uint8 GetMaxIndex(uint32 accountId)
TC_GAME_API AccountOpResult CreateBattlenetAccount(std::string email, std::string password, bool withGameAccount, std::string *gameAccountName)
TC_GAME_API uint32 GetId(std::string_view username)
TC_GAME_API bool CheckPassword(uint32 accountId, std::string password)
TC_GAME_API AccountOpResult UnlinkGameAccount(std::string_view gameAccountName)
std::vector< ChatCommandBuilder > ChatCommandTable
Definition: ChatCommand.h:49
@ RBAC_PERM_COMMAND_BNET_ACCOUNT_LOCK_COUNTRY
Definition: RBAC.h:123
@ RBAC_PERM_COMMAND_BNET_ACCOUNT_SET_PASSWORD
Definition: RBAC.h:127
@ RBAC_PERM_COMMAND_BNET_ACCOUNT_LIST_GAME_ACCOUTNS
Definition: RBAC.h:702
@ RBAC_PERM_COMMAND_BNET_ACCOUNT_PASSWORD
Definition: RBAC.h:125
@ RBAC_PERM_COMMAND_BNET_ACCOUNT_LOCK_IP
Definition: RBAC.h:124
@ RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE
Definition: RBAC.h:122
@ RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE_GAME
Definition: RBAC.h:130
@ RBAC_PERM_COMMAND_BNET_ACCOUNT_LINK
Definition: RBAC.h:128
@ RBAC_PERM_COMMAND_BNET_ACCOUNT_UNLINK
Definition: RBAC.h:129