TrinityCore
Loading...
Searching...
No Matches
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 "IPLocation.h"
25#include "Language.h"
26#include "Log.h"
27#include "Player.h"
28#include "ScriptMgr.h"
29#include "Util.h"
30#include "WorldSession.h"
31
32using namespace Trinity::ChatCommands;
33
35{
36public:
37 battlenet_account_commandscript() : CommandScript("battlenet_account_commandscript") { }
38
39 std::span<ChatCommandBuilder const> GetCommands() const override
40 {
41 static ChatCommandTable accountSetCommandTable =
42 {
44 };
45 static ChatCommandTable accountLockCommandTable =
46 {
49 };
50 static ChatCommandTable accountCommandTable =
51 {
54 { "lock", accountLockCommandTable },
55 { "set", accountSetCommandTable },
60 };
61 static ChatCommandTable commandTable =
62 {
63 { "bnetaccount", accountCommandTable },
64 };
65
66 return commandTable;
67 }
68
70 static bool HandleAccountCreateCommand(ChatHandler* handler, std::string const& accountName, std::string const& password, Optional<bool> createGameAccount)
71 {
72 if (accountName.find('@') == std::string::npos)
73 {
75 handler->SetSentErrorMessage(true);
76 return false;
77 }
78
79 std::string gameAccountName;
80 switch (Battlenet::AccountMgr::CreateBattlenetAccount(accountName, password, createGameAccount.value_or(true), &gameAccountName))
81 {
83 {
84 if (createGameAccount != false)
85 handler->PSendSysMessage(LANG_ACCOUNT_CREATED_BNET_WITH_GAME, accountName.c_str(), gameAccountName.c_str());
86 else
87 handler->PSendSysMessage(LANG_ACCOUNT_CREATED_BNET, accountName.c_str());
88
89 if (handler->GetSession())
90 {
91 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] ({}) created Battle.net account {}{}{}",
92 handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress(),
93 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString(),
94 accountName, createGameAccount != false ? " with game account " : "", createGameAccount != false ? gameAccountName.c_str() : "");
95 }
96 break;
97 }
100 handler->SetSentErrorMessage(true);
101 return false;
104 handler->SetSentErrorMessage(true);
105 return false;
108 handler->SetSentErrorMessage(true);
109 return false;
110 default:
111 break;
112 }
113
114 return true;
115 }
116
117 // Sets country lock on own account
118 static bool HandleAccountLockCountryCommand(ChatHandler* handler, bool state)
119 {
120 if (state)
121 {
122 if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(handler->GetSession()->GetRemoteAddress()))
123 {
125 stmt->setString(0, location->CountryCode);
126 stmt->setUInt32(1, handler->GetSession()->GetBattlenetAccountId());
127 LoginDatabase.Execute(stmt);
129 }
130 else
131 {
132 handler->PSendSysMessage("IP2Location] No information");
133 TC_LOG_DEBUG("server.bnetserver", "IP2Location] No information");
134 }
135 }
136 else
137 {
139 stmt->setString(0, "00"sv);
140 stmt->setUInt32(1, handler->GetSession()->GetBattlenetAccountId());
141 LoginDatabase.Execute(stmt);
143 }
144 return true;
145 }
146
147 // Sets ip lock on own account
148 static bool HandleAccountLockIpCommand(ChatHandler* handler, bool state)
149 {
151
152 if (state)
153 {
154 stmt->setBool(0, true); // locked
156 }
157 else
158 {
159 stmt->setBool(0, false); // unlocked
161 }
162
163 stmt->setUInt32(1, handler->GetSession()->GetBattlenetAccountId());
164
165 LoginDatabase.Execute(stmt);
166 return true;
167 }
168
169 static bool HandleAccountPasswordCommand(ChatHandler* handler, std::string const& oldPassword, std::string const& newPassword, std::string const& passwordConfirmation)
170 {
171 // We compare the old, saved password to the entered old password - no chance for the unauthorized.
172 if (!Battlenet::AccountMgr::CheckPassword(handler->GetSession()->GetBattlenetAccountId(), std::string(oldPassword)))
173 {
175 handler->SetSentErrorMessage(true);
176 TC_LOG_INFO("entities.player.character", "Battle.net account: {} (IP: {}) Character:[{}] ({}) Tried to change password, but the provided old password is wrong.",
177 handler->GetSession()->GetBattlenetAccountId(), handler->GetSession()->GetRemoteAddress(),
178 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString());
179 return false;
180 }
181
182 // Making sure that newly entered password is correctly entered.
183 if (newPassword != passwordConfirmation)
184 {
186 handler->SetSentErrorMessage(true);
187 return false;
188 }
189
190 // Changes password and prints result.
191 AccountOpResult result = Battlenet::AccountMgr::ChangePassword(handler->GetSession()->GetBattlenetAccountId(), std::string(newPassword));
192 switch (result)
193 {
196 TC_LOG_INFO("entities.player.character", "Battle.net account: {} (IP: {}) Character:[{}] ({}) Changed Password.",
197 handler->GetSession()->GetBattlenetAccountId(), handler->GetSession()->GetRemoteAddress(),
198 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString());
199 break;
202 handler->SetSentErrorMessage(true);
203 return false;
204 default:
206 handler->SetSentErrorMessage(true);
207 return false;
208 }
209
210 return true;
211 }
212
214 static bool HandleAccountSetPasswordCommand(ChatHandler* handler, std::string accountName, std::string const& password, std::string const& passwordConfirmation)
215 {
216 if (!Utf8ToUpperOnlyLatin(accountName))
217 {
218 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
219 handler->SetSentErrorMessage(true);
220 return false;
221 }
222
223 uint32 targetAccountId = Battlenet::AccountMgr::GetId(accountName);
224 if (!targetAccountId)
225 {
226 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
227 handler->SetSentErrorMessage(true);
228 return false;
229 }
230
231 if (password != passwordConfirmation)
232 {
234 handler->SetSentErrorMessage(true);
235 return false;
236 }
237
238 AccountOpResult result = Battlenet::AccountMgr::ChangePassword(targetAccountId, password);
239 switch (result)
240 {
243 break;
245 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
246 handler->SetSentErrorMessage(true);
247 return false;
250 handler->SetSentErrorMessage(true);
251 return false;
252 default:
253 break;
254 }
255 return true;
256 }
257
258 static bool HandleAccountLinkCommand(ChatHandler* handler, std::string const& bnetAccountName, std::string const& gameAccountName)
259 {
260 switch (Battlenet::AccountMgr::LinkWithGameAccount(bnetAccountName, gameAccountName))
261 {
263 handler->PSendSysMessage(LANG_ACCOUNT_BNET_LINKED, bnetAccountName.c_str(), gameAccountName.c_str());
264 break;
266 handler->PSendSysMessage(LANG_ACCOUNT_OR_BNET_DOES_NOT_EXIST, bnetAccountName.c_str(), gameAccountName.c_str());
267 handler->SetSentErrorMessage(true);
268 break;
270 handler->PSendSysMessage(LANG_ACCOUNT_ALREADY_LINKED, gameAccountName.c_str());
271 handler->SetSentErrorMessage(true);
272 break;
273 default:
274 break;
275 }
276
277 return true;
278 }
279
280 static bool HandleAccountUnlinkCommand(ChatHandler* handler, std::string const& gameAccountName)
281 {
282 switch (Battlenet::AccountMgr::UnlinkGameAccount(gameAccountName))
283 {
285 handler->PSendSysMessage(LANG_ACCOUNT_BNET_UNLINKED, gameAccountName.c_str());
286 break;
288 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, gameAccountName.c_str());
289 handler->SetSentErrorMessage(true);
290 break;
292 handler->PSendSysMessage(LANG_ACCOUNT_BNET_NOT_LINKED, gameAccountName.c_str());
293 handler->SetSentErrorMessage(true);
294 break;
295 default:
296 break;
297 }
298
299 return true;
300 }
301
302 static bool HandleGameAccountCreateCommand(ChatHandler* handler, std::string const& bnetAccountName)
303 {
304 uint32 accountId = Battlenet::AccountMgr::GetId(bnetAccountName);
305 if (!accountId)
306 {
307 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, bnetAccountName.c_str());
308 handler->SetSentErrorMessage(true);
309 return false;
310 }
311
312 uint8 index = Battlenet::AccountMgr::GetMaxIndex(accountId) + 1;
313 std::string accountName = std::to_string(accountId) + '#' + std::to_string(uint32(index));
314
315 // Generate random hex string for password, these accounts must not be logged on with GRUNT
316 std::array<uint8, 8> randPassword = Trinity::Crypto::GetRandomBytes<8>();
317
318 switch (sAccountMgr->CreateAccount(accountName, ByteArrayToHexStr(randPassword), bnetAccountName, accountId, index))
319 {
321 handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName.c_str());
322 if (handler->GetSession())
323 {
324 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] ({}) created Account {} (Email: '{}')",
325 handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress(),
326 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString(),
327 accountName, bnetAccountName);
328 }
329 break;
332 handler->SetSentErrorMessage(true);
333 return false;
336 handler->SetSentErrorMessage(true);
337 return false;
340 handler->SetSentErrorMessage(true);
341 return false;
343 handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, accountName.c_str());
344 handler->SetSentErrorMessage(true);
345 return false;
346 default:
347 handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED, accountName.c_str());
348 handler->SetSentErrorMessage(true);
349 return false;
350 }
351
352 return true;
353 }
354
355 static bool HandleListGameAccountsCommand(ChatHandler* handler, std::string const& battlenetAccountName)
356 {
358 stmt->setString(0, battlenetAccountName);
359 if (PreparedQueryResult accountList = LoginDatabase.Query(stmt))
360 {
361 auto formatDisplayName = [](char const* name) -> std::string
362 {
363 if (char const* hashPos = strchr(name, '#'))
364 return std::string("WoW") + ++hashPos;
365 else
366 return name;
367 };
368
369 handler->SendSysMessage("----------------------------------------------------");
371 handler->SendSysMessage("----------------------------------------------------");
372 do
373 {
374 Field* fields = accountList->Fetch();
375 handler->PSendSysMessage("| %10u | %-16.16s | %-16.16s |", fields[0].GetUInt32(), fields[1].GetCString(), formatDisplayName(fields[1].GetCString()).c_str());
376 } while (accountList->NextRow());
377 handler->SendSysMessage("----------------------------------------------------");
378 }
379 else
380 handler->PSendSysMessage(LANG_ACCOUNT_BNET_LIST_NO_ACCOUNTS, battlenetAccountName);
381
382 return true;
383 }
384};
385
AccountOpResult
Definition AccountMgr.h:25
#define sAccountMgr
Definition AccountMgr.h:104
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
uint8_t uint8
Definition Define.h:156
uint32_t uint32
Definition Define.h:154
#define sIPLocation
Definition IPLocation.h:56
@ LANG_ACCOUNT_ALREADY_EXIST
Definition Language.h:843
@ LANG_ACCOUNT_CREATED_BNET
Definition Language.h:870
@ LANG_COMMAND_NOTCHANGEPASSWORD
Definition Language.h:57
@ LANG_COMMAND_ACCLOCKLOCKED
Definition Language.h:60
@ LANG_ACCOUNT_PASS_TOO_LONG
Definition Language.h:868
@ LANG_ACCOUNT_OR_BNET_DOES_NOT_EXIST
Definition Language.h:993
@ LANG_ACCOUNT_BNET_NOT_LINKED
Definition Language.h:996
@ LANG_PASSWORD_TOO_LONG
Definition Language.h:87
@ LANG_ACCOUNT_BNET_LIST_HEADER
Definition Language.h:871
@ LANG_COMMAND_WRONGOLDPASSWORD
Definition Language.h:59
@ LANG_ACCOUNT_ALREADY_LINKED
Definition Language.h:994
@ LANG_ACCOUNT_CREATED_BNET_WITH_GAME
Definition Language.h:869
@ LANG_COMMAND_ACCLOCKUNLOCKED
Definition Language.h:61
@ LANG_ACCOUNT_BNET_LIST_NO_ACCOUNTS
Definition Language.h:872
@ LANG_ACCOUNT_BNET_LINKED
Definition Language.h:992
@ LANG_ACCOUNT_NOT_CREATED_SQL_ERROR
Definition Language.h:844
@ LANG_ACCOUNT_NOT_CREATED
Definition Language.h:845
@ LANG_ACCOUNT_INVALID_BNET_NAME
Definition Language.h:866
@ LANG_ACCOUNT_CREATED
Definition Language.h:841
@ LANG_ACCOUNT_BNET_UNLINKED
Definition Language.h:995
@ LANG_NEW_PASSWORDS_NOT_MATCH
Definition Language.h:86
@ LANG_ACCOUNT_NOT_EXIST
Definition Language.h:473
@ LANG_COMMAND_PASSWORD
Definition Language.h:58
@ LANG_ACCOUNT_NAME_TOO_LONG
Definition Language.h:842
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
@ 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:752
std::string ByteArrayToHexStr(Container const &c, bool reverse=false)
Definition Util.h:431
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
WorldSession * GetSession()
Definition Chat.h:42
void SetSentErrorMessage(bool val)
Definition Chat.h:127
void PSendSysMessage(char const *fmt, Args &&... args)
Definition Chat.h:62
virtual void SendSysMessage(std::string_view str, bool escapeCharacters=false)
Definition Chat.cpp:111
Class used to access individual fields of database query result.
Definition Field.h:94
char const * GetCString() const noexcept
Definition Field.cpp:106
std::string ToString() const
void setString(uint8 index, std::string &&value)
void setUInt32(uint8 index, uint32 value)
void setBool(uint8 index, bool value)
std::string const & GetName() const
Definition Object.h:342
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)
std::span< ChatCommandBuilder const > GetCommands() const override
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.
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)
ChatCommandBuilder const [] 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