2010-11-09 10:15:35 -05:00
/*
2020-01-02 06:44:10 +01:00
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
2010-11-09 10:15:35 -05:00
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
Name: account_commandscript
%Complete: 100
Comment: All account related commands
Category: commandscripts
EndScriptData */
#include "AccountMgr.h"
2019-08-10 21:34:51 +02:00
#include "AES.h"
#include "Base32.h"
2010-11-13 22:29:46 +01:00
#include "Chat.h"
2019-08-10 21:34:51 +02:00
#include "CryptoGenerics.h"
2017-05-18 23:52:58 +02:00
#include "DatabaseEnv.h"
2018-01-06 01:21:59 +01:00
#include "IpAddress.h"
2018-06-22 17:32:39 -06:00
#include "IPLocation.h"
2012-11-20 12:30:30 +01:00
#include "Language.h"
2017-05-12 18:49:51 +02:00
#include "Log.h"
2012-11-17 05:18:37 +01:00
#include "Player.h"
2012-11-20 12:30:30 +01:00
#include "ScriptMgr.h"
2019-08-10 21:34:51 +02:00
#include "SecretMgr.h"
#include "TOTP.h"
2017-05-18 23:52:58 +02:00
#include "World.h"
2017-06-04 01:00:45 +02:00
#include "WorldSession.h"
2019-08-10 21:34:51 +02:00
#include <unordered_map>
#include <openssl/rand.h>
2010-11-09 10:15:35 -05:00
2018-09-08 19:46:56 +02:00
using namespace Trinity :: ChatCommands ;
2010-11-09 10:15:35 -05:00
class account_commandscript : public CommandScript
{
2010-11-19 14:04:21 +01:00
public :
account_commandscript () : CommandScript ( "account_commandscript" ) { }
2010-11-09 10:15:35 -05:00
2015-10-22 20:26:56 +02:00
std :: vector < ChatCommand > GetCommands () const override
2010-11-19 14:04:21 +01:00
{
2015-10-22 20:26:56 +02:00
static std :: vector < ChatCommand > accountSetSecTable =
2013-07-25 01:49:04 +02:00
{
2015-10-22 20:26:56 +02:00
{ "regmail" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_SET_SEC_REGMAIL , true , & HandleAccountSetRegEmailCommand , "" },
{ "email" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_SET_SEC_EMAIL , true , & HandleAccountSetEmailCommand , "" },
2013-07-25 01:49:04 +02:00
};
2015-10-22 20:26:56 +02:00
static std :: vector < ChatCommand > accountSetCommandTable =
2010-11-09 10:15:35 -05:00
{
2015-10-22 20:26:56 +02:00
{ "addon" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_SET_ADDON , true , & HandleAccountSetAddonCommand , "" },
2020-08-14 17:06:03 +02:00
{ "sec" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_SET_SEC , true , nullptr , "" , accountSetSecTable },
2020-06-20 23:49:18 +04:00
{ "gmlevel" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_SET_SECLEVEL , true , & HandleAccountSetSecLevelCommand , "" }, // temp for a transition period
{ "seclevel" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_SET_SECLEVEL , true , & HandleAccountSetSecLevelCommand , "" },
2015-10-22 20:26:56 +02:00
{ "password" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_SET_PASSWORD , true , & HandleAccountSetPasswordCommand , "" },
2019-08-10 21:34:51 +02:00
{ "2fa" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_SET_2FA , true , & HandleAccountSet2FACommand , "" },
};
static std :: vector < ChatCommand > account2FACommandTable =
{
{ "setup" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_2FA_SETUP , false , & HandleAccount2FASetupCommand , "" },
{ "remove" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_2FA_REMOVE , false , & HandleAccount2FARemoveCommand , "" },
2010-11-19 14:04:21 +01:00
};
2015-10-22 20:26:56 +02:00
static std :: vector < ChatCommand > accountLockCommandTable =
2013-04-15 14:56:00 +03:00
{
2015-10-22 20:26:56 +02:00
{ "country" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_LOCK_COUNTRY , false , & HandleAccountLockCountryCommand , "" },
{ "ip" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_LOCK_IP , false , & HandleAccountLockIpCommand , "" },
2013-04-15 14:56:00 +03:00
};
2015-10-22 20:26:56 +02:00
static std :: vector < ChatCommand > accountCommandTable =
2010-11-09 10:15:35 -05:00
{
2019-08-10 21:34:51 +02:00
{ "2fa" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_2FA , false , nullptr , "" , account2FACommandTable },
2015-10-22 20:26:56 +02:00
{ "addon" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_ADDON , false , & HandleAccountAddonCommand , "" },
{ "create" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_CREATE , true , & HandleAccountCreateCommand , "" },
{ "delete" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_DELETE , true , & HandleAccountDeleteCommand , "" },
{ "email" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_EMAIL , false , & HandleAccountEmailCommand , "" },
{ "onlinelist" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_ONLINE_LIST , true , & HandleAccountOnlineListCommand , "" },
2020-08-14 17:06:03 +02:00
{ "lock" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_LOCK , false , nullptr , "" , accountLockCommandTable },
{ "set" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_SET , true , nullptr , "" , accountSetCommandTable },
2015-10-22 20:26:56 +02:00
{ "password" , rbac :: RBAC_PERM_COMMAND_ACCOUNT_PASSWORD , false , & HandleAccountPasswordCommand , "" },
{ "" , rbac :: RBAC_PERM_COMMAND_ACCOUNT , false , & HandleAccountCommand , "" },
2010-11-19 14:04:21 +01:00
};
2015-10-22 20:26:56 +02:00
static std :: vector < ChatCommand > commandTable =
2010-11-19 14:04:21 +01:00
{
2020-08-14 17:06:03 +02:00
{ "account" , rbac :: RBAC_PERM_COMMAND_ACCOUNT , true , nullptr , "" , accountCommandTable },
2010-11-19 14:04:21 +01:00
};
return commandTable ;
}
2019-08-10 21:34:51 +02:00
static bool HandleAccount2FASetupCommand ( ChatHandler * handler , Optional < uint32 > token )
{
auto const & masterKey = sSecretMgr -> GetSecret ( SECRET_TOTP_MASTER_KEY );
if ( ! masterKey . IsAvailable ())
{
handler -> SendSysMessage ( LANG_2FA_COMMANDS_NOT_SETUP );
handler -> SetSentErrorMessage ( true );
return false ;
}
uint32 const accountId = handler -> GetSession () -> GetAccountId ();
{ // check if 2FA already enabled
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_ACCOUNT_TOTP_SECRET );
stmt -> setUInt32 ( 0 , accountId );
PreparedQueryResult result = LoginDatabase . Query ( stmt );
if ( ! result )
{
TC_LOG_ERROR ( "misc" , "Account %u not found in login database when processing .account 2fa setup command." , accountId );
handler -> SendSysMessage ( LANG_UNKNOWN_ERROR );
handler -> SetSentErrorMessage ( true );
return false ;
}
if ( ! result -> Fetch () -> IsNull ())
{
handler -> SendSysMessage ( LANG_2FA_ALREADY_SETUP );
handler -> SetSentErrorMessage ( true );
return false ;
}
}
// store random suggested secrets
static std :: unordered_map < uint32 , Trinity :: Crypto :: TOTP :: Secret > suggestions ;
auto pair = suggestions . emplace ( std :: piecewise_construct , std :: make_tuple ( accountId ), std :: make_tuple ( Trinity :: Crypto :: TOTP :: RECOMMENDED_SECRET_LENGTH )); // std::vector 1-argument size_t constructor invokes resize
if ( pair . second ) // no suggestion yet, generate random secret
RAND_bytes ( pair . first -> second . data (), pair . first -> second . size ());
if ( ! pair . second && token ) // suggestion already existed and token specified - validate
{
if ( Trinity :: Crypto :: TOTP :: ValidateToken ( pair . first -> second , * token ))
{
if ( masterKey )
Trinity :: Crypto :: AEEncryptWithRandomIV < Trinity :: Crypto :: AES > ( pair . first -> second , * masterKey );
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_ACCOUNT_TOTP_SECRET );
stmt -> setBinary ( 0 , pair . first -> second );
stmt -> setUInt32 ( 1 , accountId );
LoginDatabase . Execute ( stmt );
suggestions . erase ( pair . first );
handler -> SendSysMessage ( LANG_2FA_SETUP_COMPLETE );
return true ;
}
else
handler -> SendSysMessage ( LANG_2FA_INVALID_TOKEN );
}
// new suggestion, or no token specified, output TOTP parameters
handler -> PSendSysMessage ( LANG_2FA_SECRET_SUGGESTION , Trinity :: Encoding :: Base32 :: Encode ( pair . first -> second ));
handler -> SetSentErrorMessage ( true );
return false ;
}
static bool HandleAccount2FARemoveCommand ( ChatHandler * handler , Optional < uint32 > token )
{
auto const & masterKey = sSecretMgr -> GetSecret ( SECRET_TOTP_MASTER_KEY );
if ( ! masterKey . IsAvailable ())
{
handler -> SendSysMessage ( LANG_2FA_COMMANDS_NOT_SETUP );
handler -> SetSentErrorMessage ( true );
return false ;
}
uint32 const accountId = handler -> GetSession () -> GetAccountId ();
Trinity :: Crypto :: TOTP :: Secret secret ;
{ // get current TOTP secret
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_ACCOUNT_TOTP_SECRET );
stmt -> setUInt32 ( 0 , accountId );
PreparedQueryResult result = LoginDatabase . Query ( stmt );
if ( ! result )
{
TC_LOG_ERROR ( "misc" , "Account %u not found in login database when processing .account 2fa setup command." , accountId );
handler -> SendSysMessage ( LANG_UNKNOWN_ERROR );
handler -> SetSentErrorMessage ( true );
return false ;
}
Field * field = result -> Fetch ();
if ( field -> IsNull ())
{ // 2FA not enabled
handler -> SendSysMessage ( LANG_2FA_NOT_SETUP );
handler -> SetSentErrorMessage ( true );
return false ;
}
secret = field -> GetBinary ();
}
if ( token )
{
if ( masterKey )
{
bool success = Trinity :: Crypto :: AEDecrypt < Trinity :: Crypto :: AES > ( secret , * masterKey );
if ( ! success )
{
TC_LOG_ERROR ( "misc" , "Account %u has invalid ciphertext in TOTP token." , accountId );
handler -> SendSysMessage ( LANG_UNKNOWN_ERROR );
handler -> SetSentErrorMessage ( true );
return false ;
}
}
if ( Trinity :: Crypto :: TOTP :: ValidateToken ( secret , * token ))
{
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_ACCOUNT_TOTP_SECRET );
stmt -> setNull ( 0 );
stmt -> setUInt32 ( 1 , accountId );
LoginDatabase . Execute ( stmt );
handler -> SendSysMessage ( LANG_2FA_REMOVE_COMPLETE );
return true ;
}
else
handler -> SendSysMessage ( LANG_2FA_INVALID_TOKEN );
}
handler -> SendSysMessage ( LANG_2FA_REMOVE_NEED_TOKEN );
handler -> SetSentErrorMessage ( true );
return false ;
}
2018-09-08 19:46:56 +02:00
static bool HandleAccountAddonCommand ( ChatHandler * handler , uint8 expansion )
2010-11-19 14:04:21 +01:00
{
2018-09-08 19:46:56 +02:00
if ( expansion > sWorld -> getIntConfig ( CONFIG_EXPANSION ))
2010-11-09 10:15:35 -05:00
{
2010-11-19 14:04:21 +01:00
handler -> SendSysMessage ( LANG_IMPROPER_VALUE );
handler -> SetSentErrorMessage ( true );
return false ;
}
2010-11-09 10:15:35 -05:00
2019-07-27 01:00:37 +02:00
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_EXPANSION );
2011-12-25 18:12:58 +01:00
2018-09-08 19:46:56 +02:00
stmt -> setUInt8 ( 0 , expansion );
stmt -> setUInt32 ( 1 , handler -> GetSession () -> GetAccountId ());
2011-12-25 18:12:58 +01:00
LoginDatabase . Execute ( stmt );
2010-11-19 14:04:21 +01:00
handler -> PSendSysMessage ( LANG_ACCOUNT_ADDON , expansion );
return true ;
}
2010-11-09 10:15:35 -05:00
2010-11-19 14:04:21 +01:00
/// Create an account
2018-09-08 19:46:56 +02:00
static bool HandleAccountCreateCommand ( ChatHandler * handler , std :: string const & accountName , std :: string const & password , Optional < std :: string > const & email )
2010-11-19 14:04:21 +01:00
{
2018-09-08 19:46:56 +02:00
if ( accountName . find ( '@' ) != std :: string :: npos )
2016-03-28 19:40:15 +02:00
{
handler -> PSendSysMessage ( LANG_ACCOUNT_USE_BNET_COMMANDS );
handler -> SetSentErrorMessage ( true );
return false ;
}
2018-09-08 19:46:56 +02:00
switch ( sAccountMgr -> CreateAccount ( accountName , password , email . get_value_or ( "" )))
2010-11-09 10:15:35 -05:00
{
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_OK :
2011-10-10 10:33:13 -03:00
handler -> PSendSysMessage ( LANG_ACCOUNT_CREATED , accountName );
2012-01-06 17:49:15 +01:00
if ( handler -> GetSession ())
2012-08-03 14:20:18 +02:00
{
2014-10-22 18:12:51 +02:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s) Character:[%s] (%s) created Account %s (Email: '%s')" ,
2012-10-24 13:29:34 +02:00
handler -> GetSession () -> GetAccountId (), handler -> GetSession () -> GetRemoteAddress (). c_str (),
2014-10-22 18:12:51 +02:00
handler -> GetSession () -> GetPlayer () -> GetName (). c_str (), handler -> GetSession () -> GetPlayer () -> GetGUID (). ToString (). c_str (),
2018-09-08 19:46:56 +02:00
accountName . c_str (), email . get_value_or ( "" ). c_str ());
2012-08-03 14:20:18 +02:00
}
2011-10-10 10:33:13 -03:00
break ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_NAME_TOO_LONG :
2016-08-11 13:32:52 +02:00
handler -> SendSysMessage ( LANG_ACCOUNT_NAME_TOO_LONG );
handler -> SetSentErrorMessage ( true );
return false ;
case AccountOpResult :: AOR_PASS_TOO_LONG :
handler -> SendSysMessage ( LANG_ACCOUNT_PASS_TOO_LONG );
2011-10-10 10:33:13 -03:00
handler -> SetSentErrorMessage ( true );
return false ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_NAME_ALREADY_EXIST :
2011-10-10 10:33:13 -03:00
handler -> SendSysMessage ( LANG_ACCOUNT_ALREADY_EXIST );
handler -> SetSentErrorMessage ( true );
return false ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_DB_INTERNAL_ERROR :
2011-10-10 10:33:13 -03:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_CREATED_SQL_ERROR , accountName );
handler -> SetSentErrorMessage ( true );
return false ;
default :
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_CREATED , accountName );
handler -> SetSentErrorMessage ( true );
return false ;
2010-11-19 14:04:21 +01:00
}
2010-11-09 10:15:35 -05:00
2010-11-19 14:04:21 +01:00
return true ;
}
2010-11-09 10:15:35 -05:00
2010-11-19 14:04:21 +01:00
/// Delete a user account and all associated characters in this realm
2013-03-08 21:41:30 +01:00
/// @todo This function has to be enhanced to respect the login/realm split (delete char, delete account chars in realm then delete account)
2018-09-08 19:46:56 +02:00
static bool HandleAccountDeleteCommand ( ChatHandler * handler , std :: string accountName )
2010-11-19 14:04:21 +01:00
{
2014-05-06 23:43:29 +02:00
if ( ! Utf8ToUpperOnlyLatin ( accountName ))
2010-11-19 14:04:21 +01:00
{
2011-10-10 10:33:13 -03:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
2010-11-19 14:04:21 +01:00
handler -> SetSentErrorMessage ( true );
return false ;
}
2010-11-09 10:15:35 -05:00
2011-10-10 10:33:13 -03:00
uint32 accountId = AccountMgr :: GetId ( accountName );
if ( ! accountId )
2010-11-19 14:04:21 +01:00
{
2011-10-10 10:33:13 -03:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
2010-11-19 14:04:21 +01:00
handler -> SetSentErrorMessage ( true );
return false ;
2010-11-09 10:15:35 -05:00
}
2010-11-19 14:04:21 +01:00
/// Commands not recommended call from chat, but support anyway
/// can delete only for account with less security
/// This is also reject self apply in fact
2020-08-14 17:06:03 +02:00
if ( handler -> HasLowerSecurityAccount ( nullptr , accountId , true ))
2010-11-19 14:04:21 +01:00
return false ;
2011-10-10 10:33:13 -03:00
AccountOpResult result = AccountMgr :: DeleteAccount ( accountId );
2011-09-29 12:43:05 +02:00
switch ( result )
2010-11-09 10:15:35 -05:00
{
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_OK :
2011-10-10 10:33:13 -03:00
handler -> PSendSysMessage ( LANG_ACCOUNT_DELETED , accountName . c_str ());
break ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_NAME_NOT_EXIST :
2011-10-10 10:33:13 -03:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_DB_INTERNAL_ERROR :
2011-10-10 10:33:13 -03:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_DELETED_SQL_ERROR , accountName . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
default :
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_DELETED , accountName . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
2010-11-19 14:04:21 +01:00
}
2010-11-09 10:15:35 -05:00
2010-11-19 14:04:21 +01:00
return true ;
}
2010-11-09 10:15:35 -05:00
2010-11-19 14:04:21 +01:00
/// Display info on users currently in the realm
2018-09-08 19:46:56 +02:00
static bool HandleAccountOnlineListCommand ( ChatHandler * handler )
2010-11-19 14:04:21 +01:00
{
///- Get the list of accounts ID logged to the realm
2019-07-27 01:00:37 +02:00
PreparedQueryResult result = CharacterDatabase . Query ( CharacterDatabase . GetPreparedStatement ( CHAR_SEL_CHARACTER_ONLINE ));
2012-03-24 01:25:08 +01:00
if ( ! result )
2010-11-19 14:04:21 +01:00
{
handler -> SendSysMessage ( LANG_ACCOUNT_LIST_EMPTY );
2010-11-09 10:15:35 -05:00
return true ;
}
2010-11-19 14:04:21 +01:00
///- Display the list of account/characters online
handler -> SendSysMessage ( LANG_ACCOUNT_LIST_BAR_HEADER );
handler -> SendSysMessage ( LANG_ACCOUNT_LIST_HEADER );
handler -> SendSysMessage ( LANG_ACCOUNT_LIST_BAR );
///- Cycle through accounts
do
2010-11-09 10:15:35 -05:00
{
2012-03-24 01:25:08 +01:00
Field * fieldsDB = result -> Fetch ();
2010-11-19 14:04:21 +01:00
std :: string name = fieldsDB [ 0 ]. GetString ();
uint32 account = fieldsDB [ 1 ]. GetUInt32 ();
///- Get the username, last IP and GM level of each account
// No SQL injection. account is uint32.
2019-07-27 01:00:37 +02:00
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_ACCOUNT_INFO );
2012-03-24 01:25:08 +01:00
stmt -> setUInt32 ( 0 , account );
PreparedQueryResult resultLogin = LoginDatabase . Query ( stmt );
2011-10-10 10:33:13 -03:00
2010-11-19 14:04:21 +01:00
if ( resultLogin )
2010-11-09 10:15:35 -05:00
{
2011-09-15 14:08:17 +02:00
Field * fieldsLogin = resultLogin -> Fetch ();
2010-11-19 14:04:21 +01:00
handler -> PSendSysMessage ( LANG_ACCOUNT_LIST_LINE ,
2011-09-13 14:15:35 +02:00
fieldsLogin [ 0 ]. GetCString (), name . c_str (), fieldsLogin [ 1 ]. GetCString (),
2012-03-24 23:05:00 +00:00
fieldsDB [ 2 ]. GetUInt16 (), fieldsDB [ 3 ]. GetUInt16 (), fieldsLogin [ 3 ]. GetUInt8 (),
fieldsLogin [ 2 ]. GetUInt8 ());
2010-11-09 10:15:35 -05:00
}
2010-11-19 14:04:21 +01:00
else
2011-04-29 20:47:02 +02:00
handler -> PSendSysMessage ( LANG_ACCOUNT_LIST_ERROR , name . c_str ());
2012-08-03 14:20:18 +02:00
}
while ( result -> NextRow ());
2010-11-09 10:15:35 -05:00
2010-11-19 14:04:21 +01:00
handler -> SendSysMessage ( LANG_ACCOUNT_LIST_BAR );
return true ;
}
2010-11-09 10:15:35 -05:00
2018-09-08 19:46:56 +02:00
static bool HandleAccountLockCountryCommand ( ChatHandler * handler , bool state )
2013-04-15 14:56:00 +03:00
{
2018-09-08 19:46:56 +02:00
if ( state )
2013-04-15 14:56:00 +03:00
{
2018-09-08 19:46:56 +02:00
if ( IpLocationRecord const * location = sIPLocation -> GetLocationRecord ( handler -> GetSession () -> GetRemoteAddress ()))
2013-04-15 14:56:00 +03:00
{
2019-07-27 01:00:37 +02:00
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_ACCOUNT_LOCK_COUNTRY );
2018-09-08 19:46:56 +02:00
stmt -> setString ( 0 , location -> CountryCode );
2013-04-15 14:56:00 +03:00
stmt -> setUInt32 ( 1 , handler -> GetSession () -> GetAccountId ());
LoginDatabase . Execute ( stmt );
2011-12-25 18:12:58 +01:00
handler -> PSendSysMessage ( LANG_COMMAND_ACCLOCKLOCKED );
}
2018-09-08 19:46:56 +02:00
else
2011-12-25 18:12:58 +01:00
{
2018-09-08 19:46:56 +02:00
handler -> PSendSysMessage ( "No IP2Location information - account not locked" );
handler -> SetSentErrorMessage ( true );
return false ;
2011-12-25 18:12:58 +01:00
}
2018-09-08 19:46:56 +02:00
}
else
{
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_ACCOUNT_LOCK_COUNTRY );
stmt -> setString ( 0 , "00" );
2011-12-25 18:12:58 +01:00
stmt -> setUInt32 ( 1 , handler -> GetSession () -> GetAccountId ());
LoginDatabase . Execute ( stmt );
2018-09-08 19:46:56 +02:00
handler -> PSendSysMessage ( LANG_COMMAND_ACCLOCKUNLOCKED );
2010-11-19 14:04:21 +01:00
}
2018-09-08 19:46:56 +02:00
return true ;
2010-11-19 14:04:21 +01:00
}
2010-11-09 10:15:35 -05:00
2018-09-08 19:46:56 +02:00
static bool HandleAccountLockIpCommand ( ChatHandler * handler , bool state )
2013-07-25 01:49:04 +02:00
{
2018-09-08 19:46:56 +02:00
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_ACCOUNT_LOCK );
if ( state )
2013-07-25 01:49:04 +02:00
{
2018-09-08 19:46:56 +02:00
stmt -> setBool ( 0 , true ); // locked
handler -> PSendSysMessage ( LANG_COMMAND_ACCLOCKLOCKED );
2013-07-25 01:49:04 +02:00
}
2018-09-08 19:46:56 +02:00
else
2013-07-25 01:49:04 +02:00
{
2018-09-08 19:46:56 +02:00
stmt -> setBool ( 0 , false ); // unlocked
handler -> PSendSysMessage ( LANG_COMMAND_ACCLOCKUNLOCKED );
2013-07-25 01:49:04 +02:00
}
2018-09-08 19:46:56 +02:00
stmt -> setUInt32 ( 1 , handler -> GetSession () -> GetAccountId ());
LoginDatabase . Execute ( stmt );
return true ;
}
static bool HandleAccountEmailCommand ( ChatHandler * handler , std :: string const & oldEmail , std :: string const & password , std :: string const & email , std :: string const & emailConfirm )
{
if ( ! AccountMgr :: CheckEmail ( handler -> GetSession () -> GetAccountId (), oldEmail ))
2013-07-25 01:49:04 +02:00
{
handler -> SendSysMessage ( LANG_COMMAND_WRONGEMAIL );
2014-05-02 03:44:21 +02:00
sScriptMgr -> OnFailedEmailChange ( handler -> GetSession () -> GetAccountId ());
2013-07-25 01:49:04 +02:00
handler -> SetSentErrorMessage ( true );
2014-10-22 18:12:51 +02:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s) Character:[%s] (%s) Tried to change email, but the provided email [%s] is not equal to registration email [%s]." ,
2013-07-25 01:49:04 +02:00
handler -> GetSession () -> GetAccountId (), handler -> GetSession () -> GetRemoteAddress (). c_str (),
2014-10-22 18:12:51 +02:00
handler -> GetSession () -> GetPlayer () -> GetName (). c_str (), handler -> GetSession () -> GetPlayer () -> GetGUID (). ToString (). c_str (),
2018-09-08 19:46:56 +02:00
email . c_str (), oldEmail . c_str ());
2013-07-25 01:49:04 +02:00
return false ;
}
2018-09-08 19:46:56 +02:00
if ( ! AccountMgr :: CheckPassword ( handler -> GetSession () -> GetAccountId (), password ))
2013-07-25 01:49:04 +02:00
{
handler -> SendSysMessage ( LANG_COMMAND_WRONGOLDPASSWORD );
2014-05-02 03:44:21 +02:00
sScriptMgr -> OnFailedEmailChange ( handler -> GetSession () -> GetAccountId ());
2013-07-25 01:49:04 +02:00
handler -> SetSentErrorMessage ( true );
2014-10-22 18:12:51 +02:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s) Character:[%s] (%s) Tried to change email, but the provided password is wrong." ,
2013-07-25 01:49:04 +02:00
handler -> GetSession () -> GetAccountId (), handler -> GetSession () -> GetRemoteAddress (). c_str (),
2014-10-22 18:12:51 +02:00
handler -> GetSession () -> GetPlayer () -> GetName (). c_str (), handler -> GetSession () -> GetPlayer () -> GetGUID (). ToString (). c_str ());
2013-07-25 01:49:04 +02:00
return false ;
}
2018-09-08 19:46:56 +02:00
if ( email == oldEmail )
2013-07-25 01:49:04 +02:00
{
handler -> SendSysMessage ( LANG_OLD_EMAIL_IS_NEW_EMAIL );
2014-05-02 03:44:21 +02:00
sScriptMgr -> OnFailedEmailChange ( handler -> GetSession () -> GetAccountId ());
2013-07-25 01:49:04 +02:00
handler -> SetSentErrorMessage ( true );
return false ;
}
2018-09-08 19:46:56 +02:00
if ( email != emailConfirm )
2013-07-25 01:49:04 +02:00
{
handler -> SendSysMessage ( LANG_NEW_EMAILS_NOT_MATCH );
2014-05-02 03:44:21 +02:00
sScriptMgr -> OnFailedEmailChange ( handler -> GetSession () -> GetAccountId ());
2013-07-25 01:49:04 +02:00
handler -> SetSentErrorMessage ( true );
2018-09-08 19:46:56 +02:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s) Character:[%s] (%s) Tried to change email, but the confirm email does not match." ,
2013-07-25 01:49:04 +02:00
handler -> GetSession () -> GetAccountId (), handler -> GetSession () -> GetRemoteAddress (). c_str (),
2014-10-22 18:12:51 +02:00
handler -> GetSession () -> GetPlayer () -> GetName (). c_str (), handler -> GetSession () -> GetPlayer () -> GetGUID (). ToString (). c_str ());
2013-07-25 01:49:04 +02:00
return false ;
}
2018-09-08 19:46:56 +02:00
AccountOpResult result = AccountMgr :: ChangeEmail ( handler -> GetSession () -> GetAccountId (), email );
2013-07-25 01:49:04 +02:00
switch ( result )
{
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_OK :
2013-07-25 01:49:04 +02:00
handler -> SendSysMessage ( LANG_COMMAND_EMAIL );
2014-05-02 03:44:21 +02:00
sScriptMgr -> OnEmailChange ( handler -> GetSession () -> GetAccountId ());
2014-10-22 18:12:51 +02:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s) Character:[%s] (%s) Changed Email from [%s] to [%s]." ,
2013-07-25 01:49:04 +02:00
handler -> GetSession () -> GetAccountId (), handler -> GetSession () -> GetRemoteAddress (). c_str (),
2014-10-22 18:12:51 +02:00
handler -> GetSession () -> GetPlayer () -> GetName (). c_str (), handler -> GetSession () -> GetPlayer () -> GetGUID (). ToString (). c_str (),
2018-09-08 19:46:56 +02:00
oldEmail . c_str (), email . c_str ());
2013-07-25 01:49:04 +02:00
break ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_EMAIL_TOO_LONG :
2013-07-25 01:49:04 +02:00
handler -> SendSysMessage ( LANG_EMAIL_TOO_LONG );
2014-05-02 03:44:21 +02:00
sScriptMgr -> OnFailedEmailChange ( handler -> GetSession () -> GetAccountId ());
2013-07-25 01:49:04 +02:00
handler -> SetSentErrorMessage ( true );
return false ;
default :
handler -> SendSysMessage ( LANG_COMMAND_NOTCHANGEEMAIL );
handler -> SetSentErrorMessage ( true );
return false ;
}
return true ;
}
2018-09-08 19:46:56 +02:00
static bool HandleAccountPasswordCommand ( ChatHandler * handler , std :: string const & oldPassword , std :: string const & newPassword , std :: string const & confirmPassword , Optional < std :: string > const & confirmEmail )
2010-11-19 14:04:21 +01:00
{
2013-09-12 16:39:41 +02:00
// First, we check config. What security type (sec type) is it ? Depending on it, the command branches out
2018-09-08 19:46:56 +02:00
uint32 const pwConfig = sWorld -> getIntConfig ( CONFIG_ACC_PASSCHANGESEC ); // 0 - PW_NONE, 1 - PW_EMAIL, 2 - PW_RBAC
2010-11-09 10:15:35 -05:00
2013-09-12 16:39:41 +02:00
// We compare the old, saved password to the entered old password - no chance for the unauthorized.
2018-09-08 19:46:56 +02:00
if ( ! AccountMgr :: CheckPassword ( handler -> GetSession () -> GetAccountId (), oldPassword ))
2010-11-19 14:04:21 +01:00
{
handler -> SendSysMessage ( LANG_COMMAND_WRONGOLDPASSWORD );
2014-05-02 03:44:21 +02:00
sScriptMgr -> OnFailedPasswordChange ( handler -> GetSession () -> GetAccountId ());
2010-11-19 14:04:21 +01:00
handler -> SetSentErrorMessage ( true );
2014-10-22 18:12:51 +02:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s) Character:[%s] (%s) Tried to change password, but the provided old password is wrong." ,
2012-12-18 01:57:04 +01:00
handler -> GetSession () -> GetAccountId (), handler -> GetSession () -> GetRemoteAddress (). c_str (),
2014-10-22 18:12:51 +02:00
handler -> GetSession () -> GetPlayer () -> GetName (). c_str (), handler -> GetSession () -> GetPlayer () -> GetGUID (). ToString (). c_str ());
2010-11-19 14:04:21 +01:00
return false ;
2010-11-09 10:15:35 -05:00
}
2013-09-12 16:39:41 +02:00
// This compares the old, current email to the entered email - however, only...
2013-09-27 12:46:01 +02:00
if (( pwConfig == PW_EMAIL || ( pwConfig == PW_RBAC && handler -> HasPermission ( rbac :: RBAC_PERM_EMAIL_CONFIRM_FOR_PASS_CHANGE ))) // ...if either PW_EMAIL or PW_RBAC with the Permission is active...
2018-09-08 19:46:56 +02:00
&& ! AccountMgr :: CheckEmail ( handler -> GetSession () -> GetAccountId (), confirmEmail . get_value_or ( "" ))) // ... and returns false if the comparison fails.
2013-07-25 01:49:04 +02:00
{
handler -> SendSysMessage ( LANG_COMMAND_WRONGEMAIL );
2014-05-02 03:44:21 +02:00
sScriptMgr -> OnFailedPasswordChange ( handler -> GetSession () -> GetAccountId ());
2013-07-25 01:49:04 +02:00
handler -> SetSentErrorMessage ( true );
2014-10-22 18:12:51 +02:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s) Character:[%s] (%s) Tried to change password, but the entered email [%s] is wrong." ,
2013-07-25 01:49:04 +02:00
handler -> GetSession () -> GetAccountId (), handler -> GetSession () -> GetRemoteAddress (). c_str (),
2014-10-22 18:12:51 +02:00
handler -> GetSession () -> GetPlayer () -> GetName (). c_str (), handler -> GetSession () -> GetPlayer () -> GetGUID (). ToString (). c_str (),
2018-09-08 19:46:56 +02:00
confirmEmail . get_value_or ( "" ). c_str ());
2013-09-11 20:54:04 +02:00
return false ;
2013-07-25 01:49:04 +02:00
}
2013-09-12 16:39:41 +02:00
// Making sure that newly entered password is correctly entered.
2018-09-08 19:46:56 +02:00
if ( newPassword != confirmPassword )
2010-11-09 10:15:35 -05:00
{
2010-11-19 14:04:21 +01:00
handler -> SendSysMessage ( LANG_NEW_PASSWORDS_NOT_MATCH );
2014-05-02 03:44:21 +02:00
sScriptMgr -> OnFailedPasswordChange ( handler -> GetSession () -> GetAccountId ());
2010-11-19 14:04:21 +01:00
handler -> SetSentErrorMessage ( true );
return false ;
2010-11-09 10:15:35 -05:00
}
2013-09-12 16:39:41 +02:00
// Changes password and prints result.
2018-09-08 19:46:56 +02:00
AccountOpResult result = AccountMgr :: ChangePassword ( handler -> GetSession () -> GetAccountId (), newPassword );
2011-09-29 12:43:05 +02:00
switch ( result )
2010-11-09 10:15:35 -05:00
{
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_OK :
2011-10-10 10:33:13 -03:00
handler -> SendSysMessage ( LANG_COMMAND_PASSWORD );
2014-05-02 03:44:21 +02:00
sScriptMgr -> OnPasswordChange ( handler -> GetSession () -> GetAccountId ());
2018-09-08 19:46:56 +02:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s) Character:[%s] (%s) changed cassword." ,
2012-12-18 01:57:04 +01:00
handler -> GetSession () -> GetAccountId (), handler -> GetSession () -> GetRemoteAddress (). c_str (),
2014-10-22 18:12:51 +02:00
handler -> GetSession () -> GetPlayer () -> GetName (). c_str (), handler -> GetSession () -> GetPlayer () -> GetGUID (). ToString (). c_str ());
2011-10-10 10:33:13 -03:00
break ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_PASS_TOO_LONG :
2011-10-10 10:33:13 -03:00
handler -> SendSysMessage ( LANG_PASSWORD_TOO_LONG );
2014-05-02 03:44:21 +02:00
sScriptMgr -> OnFailedPasswordChange ( handler -> GetSession () -> GetAccountId ());
2011-10-10 10:33:13 -03:00
handler -> SetSentErrorMessage ( true );
return false ;
default :
handler -> SendSysMessage ( LANG_COMMAND_NOTCHANGEPASSWORD );
handler -> SetSentErrorMessage ( true );
return false ;
2010-11-19 14:04:21 +01:00
}
2010-11-09 10:15:35 -05:00
2010-11-19 14:04:21 +01:00
return true ;
}
2010-11-09 10:15:35 -05:00
2018-09-08 19:46:56 +02:00
static bool HandleAccountCommand ( ChatHandler * handler )
2010-11-19 14:04:21 +01:00
{
2013-07-25 01:49:04 +02:00
// GM Level
2020-06-20 23:49:18 +04:00
AccountTypes securityLevel = handler -> GetSession () -> GetSecurity ();
handler -> PSendSysMessage ( LANG_ACCOUNT_LEVEL , uint32 ( securityLevel ));
2013-07-25 01:49:04 +02:00
// Security level required
2013-09-27 12:46:01 +02:00
bool hasRBAC = ( handler -> HasPermission ( rbac :: RBAC_PERM_EMAIL_CONFIRM_FOR_PASS_CHANGE ) ? true : false );
2013-07-25 01:49:04 +02:00
uint32 pwConfig = sWorld -> getIntConfig ( CONFIG_ACC_PASSCHANGESEC ); // 0 - PW_NONE, 1 - PW_EMAIL, 2 - PW_RBAC
handler -> PSendSysMessage ( LANG_ACCOUNT_SEC_TYPE , ( pwConfig == PW_NONE ? "Lowest level: No Email input required." :
pwConfig == PW_EMAIL ? "Highest level: Email input required." :
2018-09-08 19:46:56 +02:00
pwConfig == PW_RBAC ? "Special level: Your account may require email input depending on settings. That is the case if another line is printed." :
"Unknown security level: Config error?" ));
2013-07-25 01:49:04 +02:00
// RBAC required display - is not displayed for console
if ( pwConfig == PW_RBAC && handler -> GetSession () && hasRBAC )
handler -> PSendSysMessage ( LANG_RBAC_EMAIL_REQUIRED );
// Email display if sufficient rights
2013-09-27 12:46:01 +02:00
if ( handler -> HasPermission ( rbac :: RBAC_PERM_MAY_CHECK_OWN_EMAIL ))
2013-07-25 01:49:04 +02:00
{
std :: string emailoutput ;
uint32 accountId = handler -> GetSession () -> GetAccountId ();
2019-07-27 01:00:37 +02:00
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_GET_EMAIL_BY_ID );
2013-07-25 01:49:04 +02:00
stmt -> setUInt32 ( 0 , accountId );
PreparedQueryResult result = LoginDatabase . Query ( stmt );
2013-09-02 16:18:55 +01:00
2013-07-25 01:49:04 +02:00
if ( result )
{
emailoutput = ( * result )[ 0 ]. GetString ();
handler -> PSendSysMessage ( LANG_COMMAND_EMAIL_OUTPUT , emailoutput . c_str ());
}
}
2010-11-19 14:04:21 +01:00
return true ;
}
2010-11-09 10:15:35 -05:00
2010-11-19 14:04:21 +01:00
/// Set/Unset the expansion level for an account
2018-09-08 19:46:56 +02:00
static bool HandleAccountSetAddonCommand ( ChatHandler * handler , Optional < std :: string > accountName , uint8 expansion )
2010-11-19 14:04:21 +01:00
{
2011-10-10 10:33:13 -03:00
uint32 accountId ;
2018-09-08 19:46:56 +02:00
if ( accountName )
2010-11-09 10:15:35 -05:00
{
2010-11-19 14:04:21 +01:00
///- Convert Account name to Upper Format
2018-09-08 19:46:56 +02:00
if ( ! Utf8ToUpperOnlyLatin ( * accountName ))
2010-11-09 10:15:35 -05:00
{
2018-09-08 19:46:56 +02:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName -> c_str ());
2010-11-19 14:04:21 +01:00
handler -> SetSentErrorMessage ( true );
2010-11-09 10:15:35 -05:00
return false ;
}
2018-09-08 19:46:56 +02:00
accountId = AccountMgr :: GetId ( * accountName );
2011-10-10 10:33:13 -03:00
if ( ! accountId )
2010-11-09 10:15:35 -05:00
{
2018-09-08 19:46:56 +02:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName -> c_str ());
2010-11-09 10:15:35 -05:00
handler -> SetSentErrorMessage ( true );
return false ;
}
2010-11-19 14:04:21 +01:00
}
2018-09-08 19:46:56 +02:00
else
{
Player * player = handler -> getSelectedPlayer ();
if ( ! player )
return false ;
accountId = player -> GetSession () -> GetAccountId ();
accountName . emplace ();
AccountMgr :: GetName ( accountId , * accountName );
}
2010-11-09 10:15:35 -05:00
2010-11-19 14:04:21 +01:00
// Let set addon state only for lesser (strong) security level
// or to self account
2012-03-16 19:40:57 +08:00
if ( handler -> GetSession () && handler -> GetSession () -> GetAccountId () != accountId &&
2020-08-14 17:06:03 +02:00
handler -> HasLowerSecurityAccount ( nullptr , accountId , true ))
2010-11-19 14:04:21 +01:00
return false ;
2010-11-09 10:15:35 -05:00
2017-07-22 10:22:17 +03:00
if ( expansion > sWorld -> getIntConfig ( CONFIG_EXPANSION ))
2010-11-19 14:04:21 +01:00
return false ;
2010-11-09 10:15:35 -05:00
2019-07-27 01:00:37 +02:00
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_EXPANSION );
2011-12-31 00:32:05 +01:00
stmt -> setUInt8 ( 0 , expansion );
stmt -> setUInt32 ( 1 , accountId );
LoginDatabase . Execute ( stmt );
2018-09-08 19:46:56 +02:00
handler -> PSendSysMessage ( LANG_ACCOUNT_SETADDON , accountName -> c_str (), accountId , expansion );
2010-11-19 14:04:21 +01:00
return true ;
}
2010-11-09 10:15:35 -05:00
2018-09-08 19:46:56 +02:00
static bool HandleAccountSetSecLevelCommand ( ChatHandler * handler , Optional < std :: string > accountName , uint8 securityLevel , int32 realmId )
2010-11-19 14:04:21 +01:00
{
2018-09-08 19:46:56 +02:00
uint32 accountId ;
if ( accountName )
2010-11-19 14:04:21 +01:00
{
2019-04-03 23:36:26 -03:00
if ( ! Utf8ToUpperOnlyLatin ( * accountName ))
{
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName -> c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
accountId = AccountMgr :: GetId ( * accountName );
if ( ! accountId )
2010-11-09 10:15:35 -05:00
{
2018-09-08 19:46:56 +02:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName -> c_str ());
2010-11-09 10:15:35 -05:00
handler -> SetSentErrorMessage ( true );
return false ;
}
2010-11-19 14:04:21 +01:00
}
2018-09-08 19:46:56 +02:00
else
{
Player * player = handler -> getSelectedPlayer ();
if ( ! player )
return false ;
accountId = player -> GetSession () -> GetAccountId ();
accountName . emplace ();
AccountMgr :: GetName ( accountId , * accountName );
}
2010-11-19 14:04:21 +01:00
2018-09-08 19:46:56 +02:00
if ( securityLevel >= SEC_CONSOLE )
2010-11-19 14:04:21 +01:00
{
handler -> SendSysMessage ( LANG_BAD_VALUE );
handler -> SetSentErrorMessage ( true );
return false ;
}
2020-09-04 13:38:24 +02:00
// handler->getSession() == nullptr only for console
2011-10-10 10:33:13 -03:00
uint32 playerSecurity ;
2010-11-19 14:04:21 +01:00
if ( handler -> GetSession ())
2018-09-08 19:46:56 +02:00
playerSecurity = AccountMgr :: GetSecurity ( handler -> GetSession () -> GetAccountId (), realmId );
2010-11-19 14:04:21 +01:00
else
2011-10-10 10:33:13 -03:00
playerSecurity = SEC_CONSOLE ;
2010-11-19 14:04:21 +01:00
// can set security level only for target with less security and to less security that we have
2013-07-25 01:49:04 +02:00
// This also restricts setting handler's own security.
2018-09-08 19:46:56 +02:00
uint32 targetSecurity = AccountMgr :: GetSecurity ( accountId , realmId );
2020-06-20 23:49:18 +04:00
if ( targetSecurity >= playerSecurity || securityLevel >= playerSecurity )
2010-11-19 14:04:21 +01:00
{
handler -> SendSysMessage ( LANG_YOURS_SECURITY_IS_LOW );
handler -> SetSentErrorMessage ( true );
return false ;
}
2010-11-09 10:15:35 -05:00
2010-11-19 14:04:21 +01:00
// Check and abort if the target gm has a higher rank on one of the realms and the new realm is -1
2018-09-08 19:46:56 +02:00
if ( realmId == - 1 && ! AccountMgr :: IsConsoleAccount ( playerSecurity ))
2010-11-19 14:04:21 +01:00
{
2020-06-20 23:49:18 +04:00
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_ACCOUNT_ACCESS_SECLEVEL_TEST );
2012-03-24 01:25:08 +01:00
2020-06-20 23:49:18 +04:00
stmt -> setUInt32 ( 0 , accountId );
stmt -> setUInt8 ( 1 , securityLevel );
2012-03-24 01:25:08 +01:00
PreparedQueryResult result = LoginDatabase . Query ( stmt );
2010-11-19 14:04:21 +01:00
if ( result )
2010-11-09 10:15:35 -05:00
{
2010-11-19 14:04:21 +01:00
handler -> SendSysMessage ( LANG_YOURS_SECURITY_IS_LOW );
2010-11-09 10:15:35 -05:00
handler -> SetSentErrorMessage ( true );
return false ;
}
2010-11-19 14:04:21 +01:00
}
2010-11-09 10:15:35 -05:00
2010-11-19 14:04:21 +01:00
// Check if provided realmID has a negative value other than -1
2018-09-08 19:46:56 +02:00
if ( realmId < - 1 )
2010-11-19 14:04:21 +01:00
{
handler -> SendSysMessage ( LANG_INVALID_REALMID );
handler -> SetSentErrorMessage ( true );
return false ;
}
2010-11-09 10:15:35 -05:00
2018-09-08 19:46:56 +02:00
sAccountMgr -> UpdateAccountAccess ( nullptr , accountId , securityLevel , realmId );
2011-10-10 10:33:13 -03:00
2018-09-08 19:46:56 +02:00
handler -> PSendSysMessage ( LANG_YOU_CHANGE_SECURITY , accountName -> c_str (), securityLevel );
2010-11-19 14:04:21 +01:00
return true ;
}
/// Set password for account
2018-09-08 19:46:56 +02:00
static bool HandleAccountSetPasswordCommand ( ChatHandler * handler , std :: string accountName , std :: string const & password , std :: string const & confirmPassword )
2010-11-19 14:04:21 +01:00
{
2014-05-06 23:43:29 +02:00
if ( ! Utf8ToUpperOnlyLatin ( accountName ))
2010-11-19 14:04:21 +01:00
{
2011-10-10 10:33:13 -03:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
2010-11-19 14:04:21 +01:00
handler -> SetSentErrorMessage ( true );
return false ;
}
2011-10-10 10:33:13 -03:00
uint32 targetAccountId = AccountMgr :: GetId ( accountName );
2010-11-19 14:04:21 +01:00
if ( ! targetAccountId )
{
2011-10-10 10:33:13 -03:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
2010-11-19 14:04:21 +01:00
handler -> SetSentErrorMessage ( true );
return false ;
}
/// can set password only for target with less security
2013-07-25 01:49:04 +02:00
/// This also restricts setting handler's own password
2020-08-14 17:06:03 +02:00
if ( handler -> HasLowerSecurityAccount ( nullptr , targetAccountId , true ))
2010-11-19 14:04:21 +01:00
return false ;
2018-09-08 19:46:56 +02:00
if ( password != confirmPassword )
2010-11-19 14:04:21 +01:00
{
2011-10-10 10:33:13 -03:00
handler -> SendSysMessage ( LANG_NEW_PASSWORDS_NOT_MATCH );
handler -> SetSentErrorMessage ( true );
2010-11-19 14:04:21 +01:00
return false ;
}
2011-10-10 10:33:13 -03:00
AccountOpResult result = AccountMgr :: ChangePassword ( targetAccountId , password );
2010-11-19 14:04:21 +01:00
switch ( result )
{
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_OK :
2011-10-10 10:33:13 -03:00
handler -> SendSysMessage ( LANG_COMMAND_PASSWORD );
break ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_NAME_NOT_EXIST :
2011-10-10 10:33:13 -03:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_PASS_TOO_LONG :
2011-10-10 10:33:13 -03:00
handler -> SendSysMessage ( LANG_PASSWORD_TOO_LONG );
handler -> SetSentErrorMessage ( true );
return false ;
default :
handler -> SendSysMessage ( LANG_COMMAND_NOTCHANGEPASSWORD );
handler -> SetSentErrorMessage ( true );
return false ;
2010-11-09 10:15:35 -05:00
}
2010-11-19 14:04:21 +01:00
return true ;
}
2013-07-25 01:49:04 +02:00
2019-08-10 21:34:51 +02:00
static bool HandleAccountSet2FACommand ( ChatHandler * handler , std :: string accountName , std :: string secret )
{
if ( ! Utf8ToUpperOnlyLatin ( accountName ))
{
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
uint32 targetAccountId = AccountMgr :: GetId ( accountName );
if ( ! targetAccountId )
{
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
if ( handler -> HasLowerSecurityAccount ( nullptr , targetAccountId , true ))
return false ;
if ( secret == "off" )
{
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_ACCOUNT_TOTP_SECRET );
stmt -> setNull ( 0 );
stmt -> setUInt32 ( 1 , targetAccountId );
LoginDatabase . Execute ( stmt );
handler -> PSendSysMessage ( LANG_2FA_REMOVE_COMPLETE );
return true ;
}
auto const & masterKey = sSecretMgr -> GetSecret ( SECRET_TOTP_MASTER_KEY );
if ( ! masterKey . IsAvailable ())
{
handler -> SendSysMessage ( LANG_2FA_COMMANDS_NOT_SETUP );
handler -> SetSentErrorMessage ( true );
return false ;
}
Optional < std :: vector < uint8 >> decoded = Trinity :: Encoding :: Base32 :: Decode ( secret );
if ( ! decoded )
{
handler -> SendSysMessage ( LANG_2FA_SECRET_INVALID );
handler -> SetSentErrorMessage ( true );
return false ;
}
if ( 128 < ( decoded -> size () + Trinity :: Crypto :: AES :: IV_SIZE_BYTES + Trinity :: Crypto :: AES :: TAG_SIZE_BYTES ))
{
handler -> SendSysMessage ( LANG_2FA_SECRET_TOO_LONG );
handler -> SetSentErrorMessage ( true );
return false ;
}
if ( masterKey )
Trinity :: Crypto :: AEEncryptWithRandomIV < Trinity :: Crypto :: AES > ( * decoded , * masterKey );
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_UPD_ACCOUNT_TOTP_SECRET );
stmt -> setBinary ( 0 , * decoded );
stmt -> setUInt32 ( 1 , targetAccountId );
LoginDatabase . Execute ( stmt );
handler -> PSendSysMessage ( LANG_2FA_SECRET_SET_COMPLETE , accountName . c_str ());
return true ;
}
2013-07-25 01:49:04 +02:00
/// Set normal email for account
2018-09-08 19:46:56 +02:00
static bool HandleAccountSetEmailCommand ( ChatHandler * handler , std :: string accountName , std :: string const & email , std :: string const & confirmEmail )
2013-07-25 01:49:04 +02:00
{
2014-05-06 23:43:29 +02:00
if ( ! Utf8ToUpperOnlyLatin ( accountName ))
2013-07-25 01:49:04 +02:00
{
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
2013-09-02 16:18:55 +01:00
2013-07-25 01:49:04 +02:00
uint32 targetAccountId = AccountMgr :: GetId ( accountName );
if ( ! targetAccountId )
{
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
2013-09-02 16:18:55 +01:00
2013-07-25 01:49:04 +02:00
/// can set email only for target with less security
/// This also restricts setting handler's own email.
2020-08-14 17:06:03 +02:00
if ( handler -> HasLowerSecurityAccount ( nullptr , targetAccountId , true ))
2013-07-25 01:49:04 +02:00
return false ;
2013-09-02 16:18:55 +01:00
2018-09-08 19:46:56 +02:00
if ( email != confirmEmail )
2013-07-25 01:49:04 +02:00
{
handler -> SendSysMessage ( LANG_NEW_EMAILS_NOT_MATCH );
handler -> SetSentErrorMessage ( true );
return false ;
}
AccountOpResult result = AccountMgr :: ChangeEmail ( targetAccountId , email );
switch ( result )
{
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_OK :
2013-07-25 01:49:04 +02:00
handler -> SendSysMessage ( LANG_COMMAND_EMAIL );
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "entities.player.character" , "ChangeEmail: Account %s [Id: %u] had it's email changed to %s." ,
2018-09-08 19:46:56 +02:00
accountName . c_str (), targetAccountId , email . c_str ());
2013-07-25 01:49:04 +02:00
break ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_NAME_NOT_EXIST :
2013-07-25 01:49:04 +02:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_EMAIL_TOO_LONG :
2013-07-25 01:49:04 +02:00
handler -> SendSysMessage ( LANG_EMAIL_TOO_LONG );
handler -> SetSentErrorMessage ( true );
return false ;
default :
handler -> SendSysMessage ( LANG_COMMAND_NOTCHANGEEMAIL );
handler -> SetSentErrorMessage ( true );
return false ;
}
return true ;
}
/// Change registration email for account
2018-09-08 19:46:56 +02:00
static bool HandleAccountSetRegEmailCommand ( ChatHandler * handler , std :: string accountName , std :: string const & email , std :: string const & confirmEmail )
2013-07-25 01:49:04 +02:00
{
2014-05-06 23:43:29 +02:00
if ( ! Utf8ToUpperOnlyLatin ( accountName ))
2013-07-25 01:49:04 +02:00
{
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
uint32 targetAccountId = AccountMgr :: GetId ( accountName );
if ( ! targetAccountId )
{
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
/// can set email only for target with less security
/// This also restricts setting handler's own email.
2020-08-14 17:06:03 +02:00
if ( handler -> HasLowerSecurityAccount ( nullptr , targetAccountId , true ))
2013-07-25 01:49:04 +02:00
return false ;
2018-09-08 19:46:56 +02:00
if ( email != confirmEmail )
2013-07-25 01:49:04 +02:00
{
handler -> SendSysMessage ( LANG_NEW_EMAILS_NOT_MATCH );
handler -> SetSentErrorMessage ( true );
return false ;
}
AccountOpResult result = AccountMgr :: ChangeRegEmail ( targetAccountId , email );
switch ( result )
{
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_OK :
2013-07-25 01:49:04 +02:00
handler -> SendSysMessage ( LANG_COMMAND_EMAIL );
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "entities.player.character" , "ChangeRegEmail: Account %s [Id: %u] had it's Registration Email changed to %s." ,
2018-09-08 19:46:56 +02:00
accountName . c_str (), targetAccountId , email . c_str ());
2013-07-25 01:49:04 +02:00
break ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_NAME_NOT_EXIST :
2013-07-25 01:49:04 +02:00
handler -> PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , accountName . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
2014-05-06 23:43:29 +02:00
case AccountOpResult :: AOR_EMAIL_TOO_LONG :
2013-07-25 01:49:04 +02:00
handler -> SendSysMessage ( LANG_EMAIL_TOO_LONG );
handler -> SetSentErrorMessage ( true );
return false ;
default :
handler -> SendSysMessage ( LANG_COMMAND_NOTCHANGEEMAIL );
handler -> SetSentErrorMessage ( true );
return false ;
}
return true ;
}
2010-11-09 10:15:35 -05:00
};
void AddSC_account_commandscript ()
{
new account_commandscript ();
}