TrinityCore
cs_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/* ScriptData
19Name: account_commandscript
20%Complete: 100
21Comment: All account related commands
22Category: commandscripts
23EndScriptData */
24
25#include "AccountMgr.h"
26#include "AES.h"
27#include "Base32.h"
28#include "Chat.h"
29#include "ChatCommand.h"
30#include "CryptoGenerics.h"
31#include "CryptoRandom.h"
32#include "DatabaseEnv.h"
33#include "IpAddress.h"
34#include "IPLocation.h"
35#include "Language.h"
36#include "Log.h"
37#include "Player.h"
38#include "ScriptMgr.h"
39#include "SecretMgr.h"
40#include "TOTP.h"
41#include "World.h"
42#include "WorldSession.h"
43#include <unordered_map>
44
45using namespace Trinity::ChatCommands;
46
48{
49public:
50 account_commandscript() : CommandScript("account_commandscript") { }
51
53 {
54 static ChatCommandTable accountSetCommandTable =
55 {
63 };
64 static ChatCommandTable accountOnlinelistCommandTable =
65 {
71 };
72 static ChatCommandTable accountCommandTable =
73 {
80 { "onlinelist", accountOnlinelistCommandTable },
83 { "set", accountSetCommandTable },
86 };
87 static ChatCommandTable commandTable =
88 {
89 { "account", accountCommandTable },
90 };
91 return commandTable;
92 }
93
95 {
96 auto const& masterKey = sSecretMgr->GetSecret(SECRET_TOTP_MASTER_KEY);
97 if (!masterKey.IsAvailable())
98 {
100 handler->SetSentErrorMessage(true);
101 return false;
102 }
103
104 uint32 const accountId = handler->GetSession()->GetAccountId();
105
106 { // check if 2FA already enabled
108 stmt->setUInt32(0, accountId);
109 PreparedQueryResult result = LoginDatabase.Query(stmt);
110
111 if (!result)
112 {
113 TC_LOG_ERROR("misc", "Account {} not found in login database when processing .account 2fa setup command.", accountId);
115 handler->SetSentErrorMessage(true);
116 return false;
117 }
118
119 if (!result->Fetch()->IsNull())
120 {
122 handler->SetSentErrorMessage(true);
123 return false;
124 }
125 }
126
127 // store random suggested secrets
128 static std::unordered_map<uint32, Trinity::Crypto::TOTP::Secret> suggestions;
129 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
130 if (pair.second) // no suggestion yet, generate random secret
131 Trinity::Crypto::GetRandomBytes(pair.first->second);
132
133 if (!pair.second && token) // suggestion already existed and token specified - validate
134 {
135 if (Trinity::Crypto::TOTP::ValidateToken(pair.first->second, *token))
136 {
137 if (masterKey)
138 Trinity::Crypto::AEEncryptWithRandomIV<Trinity::Crypto::AES>(pair.first->second, *masterKey);
139
141 stmt->setBinary(0, pair.first->second);
142 stmt->setUInt32(1, accountId);
143 LoginDatabase.Execute(stmt);
144 suggestions.erase(pair.first);
146 return true;
147 }
148 else
150 }
151
152 // new suggestion, or no token specified, output TOTP parameters
154 handler->SetSentErrorMessage(true);
155 return false;
156 }
157
159 {
160 auto const& masterKey = sSecretMgr->GetSecret(SECRET_TOTP_MASTER_KEY);
161 if (!masterKey.IsAvailable())
162 {
164 handler->SetSentErrorMessage(true);
165 return false;
166 }
167
168 uint32 const accountId = handler->GetSession()->GetAccountId();
170 { // get current TOTP secret
172 stmt->setUInt32(0, accountId);
173 PreparedQueryResult result = LoginDatabase.Query(stmt);
174
175 if (!result)
176 {
177 TC_LOG_ERROR("misc", "Account {} not found in login database when processing .account 2fa setup command.", accountId);
179 handler->SetSentErrorMessage(true);
180 return false;
181 }
182
183 Field* field = result->Fetch();
184 if (field->IsNull())
185 { // 2FA not enabled
187 handler->SetSentErrorMessage(true);
188 return false;
189 }
190
191 secret = field->GetBinary();
192 }
193
194 if (token)
195 {
196 if (masterKey)
197 {
198 bool success = Trinity::Crypto::AEDecrypt<Trinity::Crypto::AES>(secret, *masterKey);
199 if (!success)
200 {
201 TC_LOG_ERROR("misc", "Account {} has invalid ciphertext in TOTP token.", accountId);
203 handler->SetSentErrorMessage(true);
204 return false;
205 }
206 }
207
208 if (Trinity::Crypto::TOTP::ValidateToken(secret, *token))
209 {
211 stmt->setNull(0);
212 stmt->setUInt32(1, accountId);
213 LoginDatabase.Execute(stmt);
215 return true;
216 }
217 else
219 }
220
222 handler->SetSentErrorMessage(true);
223 return false;
224 }
225
226 static bool HandleAccountAddonCommand(ChatHandler* handler, uint8 expansion)
227 {
228 if (expansion > sWorld->getIntConfig(CONFIG_EXPANSION))
229 {
231 handler->SetSentErrorMessage(true);
232 return false;
233 }
234
236
237 stmt->setUInt8(0, expansion);
238 stmt->setUInt32(1, handler->GetSession()->GetAccountId());
239
240 LoginDatabase.Execute(stmt);
241
242 handler->PSendSysMessage(LANG_ACCOUNT_ADDON, expansion);
243 return true;
244 }
245
247 static bool HandleAccountCreateCommand(ChatHandler* handler, std::string const& accountName, std::string const& password, Optional<std::string> const& email)
248 {
249 if (accountName.find('@') != std::string::npos)
250 {
252 handler->SetSentErrorMessage(true);
253 return false;
254 }
255
256 switch (sAccountMgr->CreateAccount(accountName, password, email.value_or("")))
257 {
259 handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName.c_str());
260 if (handler->GetSession())
261 {
262 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] {}) created Account {} (Email: '{}')",
263 handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress(),
264 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString(),
265 accountName, email.value_or(""));
266 }
267 break;
270 handler->SetSentErrorMessage(true);
271 return false;
274 handler->SetSentErrorMessage(true);
275 return false;
278 handler->SetSentErrorMessage(true);
279 return false;
281 handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, accountName.c_str());
282 handler->SetSentErrorMessage(true);
283 return false;
284 default:
285 handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED, accountName.c_str());
286 handler->SetSentErrorMessage(true);
287 return false;
288 }
289
290 return true;
291 }
292
295 static bool HandleAccountDeleteCommand(ChatHandler* handler, std::string accountName)
296 {
297 if (!Utf8ToUpperOnlyLatin(accountName))
298 {
299 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
300 handler->SetSentErrorMessage(true);
301 return false;
302 }
303
304 uint32 accountId = AccountMgr::GetId(accountName);
305 if (!accountId)
306 {
307 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
308 handler->SetSentErrorMessage(true);
309 return false;
310 }
311
315 if (handler->HasLowerSecurityAccount(nullptr, accountId, true))
316 return false;
317
318 AccountOpResult result = AccountMgr::DeleteAccount(accountId);
319 switch (result)
320 {
322 handler->PSendSysMessage(LANG_ACCOUNT_DELETED, accountName.c_str());
323 break;
325 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
326 handler->SetSentErrorMessage(true);
327 return false;
329 handler->PSendSysMessage(LANG_ACCOUNT_NOT_DELETED_SQL_ERROR, accountName.c_str());
330 handler->SetSentErrorMessage(true);
331 return false;
332 default:
333 handler->PSendSysMessage(LANG_ACCOUNT_NOT_DELETED, accountName.c_str());
334 handler->SetSentErrorMessage(true);
335 return false;
336 }
337
338 return true;
339 }
340
343 {
344 return HandleAccountOnlineListCommandWithParameters(handler, {}, {}, {}, {});
345 }
346
347 static bool HandleAccountOnlineListWithIpFilterCommand(ChatHandler* handler, std::string ipAddress)
348 {
349 return HandleAccountOnlineListCommandWithParameters(handler, ipAddress, {}, {}, {});
350 }
351
353 {
354 return HandleAccountOnlineListCommandWithParameters(handler, {}, limit, {}, {});
355 }
356
358 {
359 return HandleAccountOnlineListCommandWithParameters(handler, {}, {}, mapId, {});
360 }
361
363 {
364 return HandleAccountOnlineListCommandWithParameters(handler, {}, {}, {}, zoneId);
365 }
366
368 {
369 size_t sessionsMatchCount = 0;
370
371 SessionMap const& sessionsMap = sWorld->GetAllSessions();
372 for (SessionMap::value_type const& sessionPair : sessionsMap)
373 {
374 WorldSession* session = sessionPair.second;
375 Player* player = session->GetPlayer();
376
377 // Ignore sessions on character selection screen
378 if (!player)
379 continue;
380
381 uint32 playerMapId = player->GetMapId();
382 uint32 playerZoneId = player->GetZoneId();
383
384 // Apply optional ipAddress filter
385 if (ipAddress && ipAddress != session->GetRemoteAddress())
386 continue;
387
388 // Apply optional mapId filter
389 if (mapId && mapId != playerMapId)
390 continue;
391
392 // Apply optional zoneId filter
393 if (zoneId && zoneId != playerZoneId)
394 continue;
395
396 if (!sessionsMatchCount)
397 {
402 }
403
405 session->GetAccountName().c_str(),
406 session->GetPlayerName().c_str(),
407 session->GetRemoteAddress().c_str(),
408 playerMapId,
409 playerZoneId,
410 session->GetAccountExpansion(),
411 int32(session->GetSecurity()));
412
413 ++sessionsMatchCount;
414
415 // Apply optional count limit
416 if (limit && sessionsMatchCount >= limit)
417 break;
418 }
419
420 // Header is printed on first matched session. If it wasn't printed then no sessions matched the criteria
421 if (!sessionsMatchCount)
422 {
424 return true;
425 }
426
428 return true;
429 }
430
431 static bool HandleAccountLockCountryCommand(ChatHandler* handler, bool state)
432 {
433 if (state)
434 {
435 if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(handler->GetSession()->GetRemoteAddress()))
436 {
438 stmt->setString(0, location->CountryCode);
439 stmt->setUInt32(1, handler->GetSession()->GetAccountId());
440 LoginDatabase.Execute(stmt);
442 }
443 else
444 {
445 handler->PSendSysMessage("No IP2Location information - account not locked");
446 handler->SetSentErrorMessage(true);
447 return false;
448 }
449 }
450 else
451 {
453 stmt->setString(0, "00");
454 stmt->setUInt32(1, handler->GetSession()->GetAccountId());
455 LoginDatabase.Execute(stmt);
457 }
458 return true;
459 }
460
461 static bool HandleAccountLockIpCommand(ChatHandler* handler, bool state)
462 {
464
465 if (state)
466 {
467 stmt->setBool(0, true); // locked
469 }
470 else
471 {
472 stmt->setBool(0, false); // unlocked
474 }
475
476 stmt->setUInt32(1, handler->GetSession()->GetAccountId());
477
478 LoginDatabase.Execute(stmt);
479 return true;
480 }
481
482 static bool HandleAccountEmailCommand(ChatHandler* handler, std::string const& oldEmail, std::string const& password, std::string const& email, std::string const& emailConfirm)
483 {
484 if (!AccountMgr::CheckEmail(handler->GetSession()->GetAccountId(), oldEmail))
485 {
487 sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId());
488 handler->SetSentErrorMessage(true);
489 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] {} Tried to change email, but the provided email [{}] is not equal to registration email [{}].",
490 handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress(),
491 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString(),
492 email, oldEmail);
493 return false;
494 }
495
496 if (!AccountMgr::CheckPassword(handler->GetSession()->GetAccountId(), password))
497 {
499 sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId());
500 handler->SetSentErrorMessage(true);
501 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] {} Tried to change email, but the provided password is wrong.",
502 handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress(),
503 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString());
504 return false;
505 }
506
507 if (email == oldEmail)
508 {
510 sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId());
511 handler->SetSentErrorMessage(true);
512 return false;
513 }
514
515 if (email != emailConfirm)
516 {
518 sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId());
519 handler->SetSentErrorMessage(true);
520 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] {} Tried to change email, but the confirm email does not match.",
521 handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress(),
522 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString());
523 return false;
524 }
525
526 AccountOpResult result = AccountMgr::ChangeEmail(handler->GetSession()->GetAccountId(), email);
527 switch (result)
528 {
531 sScriptMgr->OnEmailChange(handler->GetSession()->GetAccountId());
532 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] {} Changed Email from [{}] to [{}].",
533 handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress(),
534 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString(),
535 oldEmail, email);
536 break;
539 sScriptMgr->OnFailedEmailChange(handler->GetSession()->GetAccountId());
540 handler->SetSentErrorMessage(true);
541 return false;
542 default:
544 handler->SetSentErrorMessage(true);
545 return false;
546 }
547
548 return true;
549 }
550
551 static bool HandleAccountPasswordCommand(ChatHandler* handler, std::string const& oldPassword, std::string const& newPassword, std::string const& confirmPassword, Optional<std::string> const& confirmEmail)
552 {
553 // First, we check config. What security type (sec type) is it ? Depending on it, the command branches out
554 uint32 const pwConfig = sWorld->getIntConfig(CONFIG_ACC_PASSCHANGESEC); // 0 - PW_NONE, 1 - PW_EMAIL, 2 - PW_RBAC
555
556 // We compare the old, saved password to the entered old password - no chance for the unauthorized.
557 if (!AccountMgr::CheckPassword(handler->GetSession()->GetAccountId(), oldPassword))
558 {
560 sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId());
561 handler->SetSentErrorMessage(true);
562 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] {} Tried to change password, but the provided old password is wrong.",
563 handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress(),
564 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString());
565 return false;
566 }
567
568 // This compares the old, current email to the entered email - however, only...
569 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...
570 && !AccountMgr::CheckEmail(handler->GetSession()->GetAccountId(), confirmEmail.value_or(""))) // ... and returns false if the comparison fails.
571 {
573 sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId());
574 handler->SetSentErrorMessage(true);
575 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] {} Tried to change password, but the entered email [{}] is wrong.",
576 handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress(),
577 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString(),
578 confirmEmail.value_or(""));
579 return false;
580 }
581
582 // Making sure that newly entered password is correctly entered.
583 if (newPassword != confirmPassword)
584 {
586 sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId());
587 handler->SetSentErrorMessage(true);
588 return false;
589 }
590
591 // Changes password and prints result.
592 AccountOpResult result = AccountMgr::ChangePassword(handler->GetSession()->GetAccountId(), newPassword);
593 switch (result)
594 {
597 sScriptMgr->OnPasswordChange(handler->GetSession()->GetAccountId());
598 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] {} changed password.",
599 handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress(),
600 handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUID().ToString());
601 break;
604 sScriptMgr->OnFailedPasswordChange(handler->GetSession()->GetAccountId());
605 handler->SetSentErrorMessage(true);
606 return false;
607 default:
609 handler->SetSentErrorMessage(true);
610 return false;
611 }
612
613 return true;
614 }
615
616 static bool HandleAccountCommand(ChatHandler* handler)
617 {
618 // GM Level
619 AccountTypes securityLevel = handler->GetSession()->GetSecurity();
620 handler->PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(securityLevel));
621
622 // Security level required
623 bool hasRBAC = (handler->HasPermission(rbac::RBAC_PERM_EMAIL_CONFIRM_FOR_PASS_CHANGE) ? true : false);
624 uint32 pwConfig = sWorld->getIntConfig(CONFIG_ACC_PASSCHANGESEC); // 0 - PW_NONE, 1 - PW_EMAIL, 2 - PW_RBAC
625
626 handler->PSendSysMessage(LANG_ACCOUNT_SEC_TYPE, (pwConfig == PW_NONE ? "Lowest level: No Email input required." :
627 pwConfig == PW_EMAIL ? "Highest level: Email input required." :
628 pwConfig == PW_RBAC ? "Special level: Your account may require email input depending on settings. That is the case if another line is printed." :
629 "Unknown security level: Config error?"));
630
631 // RBAC required display - is not displayed for console
632 if (pwConfig == PW_RBAC && handler->GetSession() && hasRBAC)
634
635 // Email display if sufficient rights
637 {
638 std::string emailoutput;
639 uint32 accountId = handler->GetSession()->GetAccountId();
640
642 stmt->setUInt32(0, accountId);
643 PreparedQueryResult result = LoginDatabase.Query(stmt);
644
645 if (result)
646 {
647 emailoutput = (*result)[0].GetString();
648 handler->PSendSysMessage(LANG_COMMAND_EMAIL_OUTPUT, emailoutput.c_str());
649 }
650 }
651
652 return true;
653 }
654
656 static bool HandleAccountSetAddonCommand(ChatHandler* handler, Optional<std::string> accountName, uint8 expansion)
657 {
658 uint32 accountId;
659 if (accountName)
660 {
662 if (!Utf8ToUpperOnlyLatin(*accountName))
663 {
664 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName->c_str());
665 handler->SetSentErrorMessage(true);
666 return false;
667 }
668
669 accountId = AccountMgr::GetId(*accountName);
670 if (!accountId)
671 {
672 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName->c_str());
673 handler->SetSentErrorMessage(true);
674 return false;
675 }
676 }
677 else
678 {
679 Player* player = handler->getSelectedPlayer();
680 if (!player)
681 return false;
682
683 accountId = player->GetSession()->GetAccountId();
684 accountName.emplace();
685 AccountMgr::GetName(accountId, *accountName);
686 }
687
688 // Let set addon state only for lesser (strong) security level
689 // or to self account
690 if (handler->GetSession() && handler->GetSession()->GetAccountId() != accountId &&
691 handler->HasLowerSecurityAccount(nullptr, accountId, true))
692 return false;
693
694 if (expansion > sWorld->getIntConfig(CONFIG_EXPANSION))
695 return false;
696
698
699 stmt->setUInt8(0, expansion);
700 stmt->setUInt32(1, accountId);
701
702 LoginDatabase.Execute(stmt);
703
704 handler->PSendSysMessage(LANG_ACCOUNT_SETADDON, accountName->c_str(), accountId, expansion);
705 return true;
706 }
707
708 static bool HandleAccountSetSecLevelCommand(ChatHandler* handler, Optional<std::string> accountName, uint8 securityLevel, Optional<int32> realmId)
709 {
710 uint32 accountId;
711 if (accountName)
712 {
713 if (!Utf8ToUpperOnlyLatin(*accountName))
714 {
715 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName->c_str());
716 handler->SetSentErrorMessage(true);
717 return false;
718 }
719
720 accountId = AccountMgr::GetId(*accountName);
721 if (!accountId)
722 {
723 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName->c_str());
724 handler->SetSentErrorMessage(true);
725 return false;
726 }
727 }
728 else
729 {
730 Player* player = handler->getSelectedPlayer();
731 if (!player)
732 return false;
733 accountId = player->GetSession()->GetAccountId();
734 accountName.emplace();
735 AccountMgr::GetName(accountId, *accountName);
736 }
737
738 if (securityLevel >= SEC_CONSOLE)
739 {
741 handler->SetSentErrorMessage(true);
742 return false;
743 }
744
745 int32 realmID = -1;
746 if (realmId)
747 realmID = *realmId;
748
749 uint32 playerSecurity;
750 if (handler->IsConsole())
751 playerSecurity = SEC_CONSOLE;
752 else
753 playerSecurity = AccountMgr::GetSecurity(handler->GetSession()->GetAccountId(), realmID);
754
755 // can set security level only for target with less security and to less security that we have
756 // This also restricts setting handler's own security.
757 uint32 targetSecurity = AccountMgr::GetSecurity(accountId, realmID);
758 if (targetSecurity >= playerSecurity || securityLevel >= playerSecurity)
759 {
761 handler->SetSentErrorMessage(true);
762 return false;
763 }
764
765 // Check and abort if the target gm has a higher rank on one of the realms and the new realm is -1
766 if (realmID == -1 && !AccountMgr::IsConsoleAccount(playerSecurity))
767 {
769
770 stmt->setUInt32(0, accountId);
771 stmt->setUInt8(1, securityLevel);
772
773 PreparedQueryResult result = LoginDatabase.Query(stmt);
774
775 if (result)
776 {
778 handler->SetSentErrorMessage(true);
779 return false;
780 }
781 }
782
783 // Check if provided realmID has a negative value other than -1
784 if (realmID < -1)
785 {
787 handler->SetSentErrorMessage(true);
788 return false;
789 }
790
791 sAccountMgr->UpdateAccountAccess(nullptr, accountId, securityLevel, realmID);
792
793 handler->PSendSysMessage(LANG_YOU_CHANGE_SECURITY, accountName->c_str(), securityLevel);
794 return true;
795 }
796
798 static bool HandleAccountSetPasswordCommand(ChatHandler* handler, std::string accountName, std::string const& password, std::string const& confirmPassword)
799 {
800 if (!Utf8ToUpperOnlyLatin(accountName))
801 {
802 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
803 handler->SetSentErrorMessage(true);
804 return false;
805 }
806
807 uint32 targetAccountId = AccountMgr::GetId(accountName);
808 if (!targetAccountId)
809 {
810 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
811 handler->SetSentErrorMessage(true);
812 return false;
813 }
814
817 if (handler->HasLowerSecurityAccount(nullptr, targetAccountId, true))
818 return false;
819
820 if (password != confirmPassword)
821 {
823 handler->SetSentErrorMessage(true);
824 return false;
825 }
826
827 AccountOpResult result = AccountMgr::ChangePassword(targetAccountId, password);
828 switch (result)
829 {
832 break;
834 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
835 handler->SetSentErrorMessage(true);
836 return false;
839 handler->SetSentErrorMessage(true);
840 return false;
841 default:
843 handler->SetSentErrorMessage(true);
844 return false;
845 }
846 return true;
847 }
848
849 static bool HandleAccountSet2FACommand(ChatHandler* handler, std::string accountName, std::string secret)
850 {
851 if (!Utf8ToUpperOnlyLatin(accountName))
852 {
853 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
854 handler->SetSentErrorMessage(true);
855 return false;
856 }
857
858 uint32 targetAccountId = AccountMgr::GetId(accountName);
859 if (!targetAccountId)
860 {
861 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
862 handler->SetSentErrorMessage(true);
863 return false;
864 }
865
866 if (handler->HasLowerSecurityAccount(nullptr, targetAccountId, true))
867 return false;
868
869 if (secret == "off")
870 {
872 stmt->setNull(0);
873 stmt->setUInt32(1, targetAccountId);
874 LoginDatabase.Execute(stmt);
876 return true;
877 }
878
879 auto const& masterKey = sSecretMgr->GetSecret(SECRET_TOTP_MASTER_KEY);
880 if (!masterKey.IsAvailable())
881 {
883 handler->SetSentErrorMessage(true);
884 return false;
885 }
886
888 if (!decoded)
889 {
891 handler->SetSentErrorMessage(true);
892 return false;
893 }
895 {
897 handler->SetSentErrorMessage(true);
898 return false;
899 }
900
901 if (masterKey)
902 Trinity::Crypto::AEEncryptWithRandomIV<Trinity::Crypto::AES>(*decoded, *masterKey);
903
905 stmt->setBinary(0, *decoded);
906 stmt->setUInt32(1, targetAccountId);
907 LoginDatabase.Execute(stmt);
908 handler->PSendSysMessage(LANG_2FA_SECRET_SET_COMPLETE, accountName.c_str());
909 return true;
910 }
911
913 static bool HandleAccountSetEmailCommand(ChatHandler* handler, std::string accountName, std::string const& email, std::string const& confirmEmail)
914 {
915 if (!Utf8ToUpperOnlyLatin(accountName))
916 {
917 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
918 handler->SetSentErrorMessage(true);
919 return false;
920 }
921
922 uint32 targetAccountId = AccountMgr::GetId(accountName);
923 if (!targetAccountId)
924 {
925 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
926 handler->SetSentErrorMessage(true);
927 return false;
928 }
929
932 if (handler->HasLowerSecurityAccount(nullptr, targetAccountId, true))
933 return false;
934
935 if (email != confirmEmail)
936 {
938 handler->SetSentErrorMessage(true);
939 return false;
940 }
941
942 AccountOpResult result = AccountMgr::ChangeEmail(targetAccountId, email);
943 switch (result)
944 {
947 TC_LOG_INFO("entities.player.character", "ChangeEmail: Account {} [Id: {}] had it's email changed to {}.",
948 accountName, targetAccountId, email);
949 break;
951 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
952 handler->SetSentErrorMessage(true);
953 return false;
956 handler->SetSentErrorMessage(true);
957 return false;
958 default:
960 handler->SetSentErrorMessage(true);
961 return false;
962 }
963
964 return true;
965 }
966
968 static bool HandleAccountSetRegEmailCommand(ChatHandler* handler, std::string accountName, std::string const& email, std::string const& confirmEmail)
969 {
970 if (!Utf8ToUpperOnlyLatin(accountName))
971 {
972 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
973 handler->SetSentErrorMessage(true);
974 return false;
975 }
976
977 uint32 targetAccountId = AccountMgr::GetId(accountName);
978 if (!targetAccountId)
979 {
980 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
981 handler->SetSentErrorMessage(true);
982 return false;
983 }
984
987 if (handler->HasLowerSecurityAccount(nullptr, targetAccountId, true))
988 return false;
989
990 if (email != confirmEmail)
991 {
993 handler->SetSentErrorMessage(true);
994 return false;
995 }
996
997 AccountOpResult result = AccountMgr::ChangeRegEmail(targetAccountId, email);
998 switch (result)
999 {
1002 TC_LOG_INFO("entities.player.character", "ChangeRegEmail: Account {} [Id: {}] had it's Registration Email changed to {}.",
1003 accountName, targetAccountId, email);
1004 break;
1006 handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
1007 handler->SetSentErrorMessage(true);
1008 return false;
1011 handler->SetSentErrorMessage(true);
1012 return false;
1013 default:
1015 handler->SetSentErrorMessage(true);
1016 return false;
1017 }
1018
1019 return true;
1020 }
1021};
1022
1024{
1026}
@ PW_EMAIL
Definition: AccountMgr.h:38
@ PW_RBAC
Definition: AccountMgr.h:39
@ PW_NONE
Definition: AccountMgr.h:37
AccountOpResult
Definition: AccountMgr.h:24
#define sAccountMgr
Definition: AccountMgr.h:98
AccountTypes
Definition: Common.h:39
@ SEC_CONSOLE
Definition: Common.h:44
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
int32_t int32
Definition: Define.h:138
uint32_t uint32
Definition: Define.h:142
#define sIPLocation
Definition: IPLocation.h:51
@ LANG_ACCOUNT_ALREADY_EXIST
Definition: Language.h:840
@ LANG_COMMAND_ACC_LOCK_COUNTRY_HELP
Definition: Language.h:435
@ LANG_COMMAND_EMAIL
Definition: Language.h:820
@ LANG_2FA_ALREADY_SETUP
Definition: Language.h:121
@ LANG_COMMAND_ACC_SET_2FA_HELP
Definition: Language.h:425
@ LANG_ACCOUNT_USE_BNET_COMMANDS
Definition: Language.h:864
@ LANG_2FA_SECRET_TOO_LONG
Definition: Language.h:232
@ LANG_COMMAND_NOTCHANGEPASSWORD
Definition: Language.h:57
@ LANG_COMMAND_ACCLOCKLOCKED
Definition: Language.h:60
@ LANG_COMMAND_ACC_SET_SEC_REGMAIL_HELP
Definition: Language.h:423
@ LANG_COMMAND_EMAIL_OUTPUT
Definition: Language.h:824
@ LANG_ACCOUNT_PASS_TOO_LONG
Definition: Language.h:865
@ LANG_IMPROPER_VALUE
Definition: Language.h:94
@ LANG_ACCOUNT_ADDON
Definition: Language.h:93
@ LANG_PASSWORD_TOO_LONG
Definition: Language.h:87
@ LANG_COMMAND_ACC_EMAIL_HELP
Definition: Language.h:433
@ LANG_ACCOUNT_LIST_EMPTY
Definition: Language.h:848
@ LANG_YOU_CHANGE_SECURITY
Definition: Language.h:455
@ LANG_COMMAND_ACC_2FA_REMOVE_HELP
Definition: Language.h:429
@ LANG_ACCOUNT_LIST_LINE
Definition: Language.h:847
@ LANG_2FA_SECRET_INVALID
Definition: Language.h:233
@ LANG_COMMAND_WRONGOLDPASSWORD
Definition: Language.h:59
@ LANG_ACCOUNT_NOT_DELETED_SQL_ERROR
Definition: Language.h:836
@ LANG_ACCOUNT_LIST_HEADER
Definition: Language.h:844
@ LANG_COMMAND_ACC_SET_ADDON_HELP
Definition: Language.h:422
@ LANG_UNKNOWN_ERROR
Definition: Language.h:119
@ LANG_COMMAND_ACCOUNT_HELP
Definition: Language.h:438
@ LANG_2FA_REMOVE_NEED_TOKEN
Definition: Language.h:126
@ LANG_2FA_NOT_SETUP
Definition: Language.h:125
@ LANG_COMMAND_ACC_PASSWORD_HELP
Definition: Language.h:437
@ LANG_2FA_INVALID_TOKEN
Definition: Language.h:122
@ LANG_ACCOUNT_SETADDON
Definition: Language.h:873
@ LANG_COMMAND_WRONGEMAIL
Definition: Language.h:818
@ LANG_COMMAND_ACC_ADDON_HELP
Definition: Language.h:430
@ LANG_ACCOUNT_LIST_BAR
Definition: Language.h:846
@ LANG_COMMAND_ACC_DELETE_HELP
Definition: Language.h:432
@ LANG_COMMAND_ACCLOCKUNLOCKED
Definition: Language.h:61
@ LANG_COMMAND_ACC_2FA_SETUP_HELP
Definition: Language.h:428
@ LANG_COMMAND_ACC_CREATE_HELP
Definition: Language.h:431
@ LANG_ACCOUNT_SEC_TYPE
Definition: Language.h:826
@ LANG_NEW_EMAILS_NOT_MATCH
Definition: Language.h:819
@ LANG_ACCOUNT_NOT_CREATED_SQL_ERROR
Definition: Language.h:841
@ LANG_2FA_COMMANDS_NOT_SETUP
Definition: Language.h:120
@ LANG_2FA_SECRET_SET_COMPLETE
Definition: Language.h:234
@ LANG_ACCOUNT_NOT_CREATED
Definition: Language.h:842
@ LANG_COMMAND_NOTCHANGEEMAIL
Definition: Language.h:822
@ LANG_YOURS_SECURITY_IS_LOW
Definition: Language.h:457
@ LANG_INVALID_REALMID
Definition: Language.h:1215
@ LANG_ACCOUNT_CREATED
Definition: Language.h:838
@ LANG_BAD_VALUE
Definition: Language.h:149
@ LANG_NEW_PASSWORDS_NOT_MATCH
Definition: Language.h:86
@ LANG_2FA_SECRET_SUGGESTION
Definition: Language.h:123
@ LANG_OLD_EMAIL_IS_NEW_EMAIL
Definition: Language.h:823
@ LANG_ACCOUNT_NOT_EXIST
Definition: Language.h:470
@ LANG_ACCOUNT_LIST_BAR_HEADER
Definition: Language.h:849
@ LANG_2FA_SETUP_COMPLETE
Definition: Language.h:124
@ LANG_COMMAND_ACC_SET_SEC_EMAIL_HELP
Definition: Language.h:424
@ LANG_COMMAND_ACC_SET_PASSWORD_HELP
Definition: Language.h:427
@ LANG_ACCOUNT_NOT_DELETED
Definition: Language.h:837
@ LANG_COMMAND_ACC_SET_SECLEVEL_HELP
Definition: Language.h:426
@ LANG_ACCOUNT_LEVEL
Definition: Language.h:43
@ LANG_RBAC_EMAIL_REQUIRED
Definition: Language.h:827
@ LANG_ACCOUNT_DELETED
Definition: Language.h:835
@ LANG_COMMAND_PASSWORD
Definition: Language.h:58
@ LANG_EMAIL_TOO_LONG
Definition: Language.h:821
@ LANG_COMMAND_ACC_LOCK_IP_HELP
Definition: Language.h:436
@ LANG_ACCOUNT_NAME_TOO_LONG
Definition: Language.h:839
@ LANG_2FA_REMOVE_COMPLETE
Definition: Language.h:127
@ LANG_COMMAND_ACC_ONLINELIST_HELP
Definition: Language.h:434
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
@ LOGIN_GET_EMAIL_BY_ID
Definition: LoginDatabase.h:94
@ LOGIN_SEL_ACCOUNT_ACCESS_SECLEVEL_TEST
Definition: LoginDatabase.h:86
@ LOGIN_UPD_ACCOUNT_TOTP_SECRET
@ LOGIN_UPD_EXPANSION
Definition: LoginDatabase.h:60
@ LOGIN_UPD_ACCOUNT_LOCK_COUNTRY
Definition: LoginDatabase.h:62
@ LOGIN_SEL_ACCOUNT_TOTP_SECRET
@ LOGIN_UPD_ACCOUNT_LOCK
Definition: LoginDatabase.h:61
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
#define sScriptMgr
Definition: ScriptMgr.h:1418
#define sSecretMgr
Definition: SecretMgr.h:83
@ SECRET_TOTP_MASTER_KEY
Definition: SecretMgr.h:31
bool Utf8ToUpperOnlyLatin(std::string &utf8String)
Definition: Util.cpp:795
static AccountOpResult ChangeRegEmail(uint32 accountId, std::string newEmail)
Definition: AccountMgr.cpp:259
static AccountOpResult DeleteAccount(uint32 accountId)
Definition: AccountMgr.cpp:90
static AccountOpResult ChangeEmail(uint32 accountId, std::string newEmail)
Definition: AccountMgr.cpp:229
static uint32 GetSecurity(uint32 accountId, int32 realmId)
Definition: AccountMgr.cpp:298
static AccountOpResult ChangePassword(uint32 accountId, std::string newPassword)
Definition: AccountMgr.cpp:199
static bool IsConsoleAccount(uint32 gmlevel)
Definition: AccountMgr.cpp:441
static bool CheckPassword(std::string username, std::string password)
Definition: AccountMgr.cpp:349
static bool CheckEmail(uint32 accountId, std::string newEmail)
Definition: AccountMgr.cpp:392
static uint32 GetId(std::string_view username)
Definition: AccountMgr.cpp:289
static bool GetName(uint32 accountId, std::string &name)
Definition: AccountMgr.cpp:319
virtual bool HasPermission(uint32 permission) const
Definition: Chat.cpp:53
Player * getSelectedPlayer()
Definition: Chat.cpp:200
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
bool IsConsole() const
Definition: Chat.h:41
bool HasLowerSecurityAccount(WorldSession *target, uint32 account, bool strong=false)
Definition: Chat.cpp:83
Class used to access individual fields of database query result.
Definition: Field.h:90
bool IsNull() const
Definition: Field.h:125
std::vector< uint8 > GetBinary() const
Definition: Field.cpp:142
std::string ToString() const
Definition: ObjectGuid.cpp:554
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
WorldSession * GetSession() const
Definition: Player.h:2101
void setUInt8(const uint8 index, const uint8 value)
void setBool(const uint8 index, const bool value)
void setBinary(const uint8 index, const std::vector< uint8 > &value)
void setUInt32(const uint8 index, const uint32 value)
void setNull(const uint8 index)
void setString(const uint8 index, const std::string &value)
static constexpr size_t IV_SIZE_BYTES
Definition: AES.h:30
static constexpr size_t TAG_SIZE_BYTES
Definition: AES.h:32
constexpr uint32 GetMapId() const
Definition: Position.h:201
std::string const & GetName() const
Definition: Object.h:555
uint32 GetZoneId() const
Definition: Object.h:545
Player session in the World.
Definition: WorldSession.h:963
AccountTypes GetSecurity() const
Definition: WorldSession.h:999
Player * GetPlayer() const
std::string const & GetAccountName() const
std::string const & GetRemoteAddress() const
uint32 GetAccountId() const
uint8 GetAccountExpansion() const
std::string const & GetPlayerName() const
static bool HandleAccountPasswordCommand(ChatHandler *handler, std::string const &oldPassword, std::string const &newPassword, std::string const &confirmPassword, Optional< std::string > const &confirmEmail)
Definition: cs_account.cpp:551
static bool HandleAccount2FASetupCommand(ChatHandler *handler, Optional< uint32 > token)
Definition: cs_account.cpp:94
ChatCommandTable GetCommands() const override
Definition: cs_account.cpp:52
static bool HandleAccountCreateCommand(ChatHandler *handler, std::string const &accountName, std::string const &password, Optional< std::string > const &email)
Create an account.
Definition: cs_account.cpp:247
static bool HandleAccountSetRegEmailCommand(ChatHandler *handler, std::string accountName, std::string const &email, std::string const &confirmEmail)
Change registration email for account.
Definition: cs_account.cpp:968
static bool HandleAccountSetEmailCommand(ChatHandler *handler, std::string accountName, std::string const &email, std::string const &confirmEmail)
Set normal email for account.
Definition: cs_account.cpp:913
static bool HandleAccountSetPasswordCommand(ChatHandler *handler, std::string accountName, std::string const &password, std::string const &confirmPassword)
Set password for account.
Definition: cs_account.cpp:798
static bool HandleAccountSet2FACommand(ChatHandler *handler, std::string accountName, std::string secret)
Definition: cs_account.cpp:849
static bool HandleAccountAddonCommand(ChatHandler *handler, uint8 expansion)
Definition: cs_account.cpp:226
static bool HandleAccountOnlineListWithMapFilterCommand(ChatHandler *handler, uint32 mapId)
Definition: cs_account.cpp:357
static bool HandleAccountEmailCommand(ChatHandler *handler, std::string const &oldEmail, std::string const &password, std::string const &email, std::string const &emailConfirm)
Definition: cs_account.cpp:482
static bool HandleAccountOnlineListCommandWithParameters(ChatHandler *handler, Optional< std::string > ipAddress, Optional< uint32 > limit, Optional< uint32 > mapId, Optional< uint32 > zoneId)
Definition: cs_account.cpp:367
static bool HandleAccountLockIpCommand(ChatHandler *handler, bool state)
Definition: cs_account.cpp:461
static bool HandleAccount2FARemoveCommand(ChatHandler *handler, Optional< uint32 > token)
Definition: cs_account.cpp:158
static bool HandleAccountOnlineListWithZoneFilterCommand(ChatHandler *handler, uint32 zoneId)
Definition: cs_account.cpp:362
static bool HandleAccountOnlineListCommand(ChatHandler *handler)
Display info on users currently in the realm.
Definition: cs_account.cpp:342
static bool HandleAccountOnlineListWithIpFilterCommand(ChatHandler *handler, std::string ipAddress)
Definition: cs_account.cpp:347
static bool HandleAccountLockCountryCommand(ChatHandler *handler, bool state)
Definition: cs_account.cpp:431
static bool HandleAccountSetAddonCommand(ChatHandler *handler, Optional< std::string > accountName, uint8 expansion)
Set/Unset the expansion level for an account.
Definition: cs_account.cpp:656
static bool HandleAccountOnlineListWithLimitCommand(ChatHandler *handler, uint32 limit)
Definition: cs_account.cpp:352
static bool HandleAccountDeleteCommand(ChatHandler *handler, std::string accountName)
Definition: cs_account.cpp:295
static bool HandleAccountCommand(ChatHandler *handler)
Definition: cs_account.cpp:616
static bool HandleAccountSetSecLevelCommand(ChatHandler *handler, Optional< std::string > accountName, uint8 securityLevel, Optional< int32 > realmId)
Definition: cs_account.cpp:708
void AddSC_account_commandscript()
#define sWorld
Definition: World.h:931
std::unordered_map< uint32, WorldSession * > SessionMap
Definition: World.h:559
@ CONFIG_ACC_PASSCHANGESEC
Definition: World.h:408
@ CONFIG_EXPANSION
Definition: World.h:308
std::vector< ChatCommandBuilder > ChatCommandTable
Definition: ChatCommand.h:49
void TC_COMMON_API GetRandomBytes(uint8 *buf, size_t len)
@ RBAC_PERM_MAY_CHECK_OWN_EMAIL
Definition: RBAC.h:103
@ RBAC_PERM_COMMAND_ACCOUNT_DELETE
Definition: RBAC.h:134
@ RBAC_PERM_COMMAND_ACCOUNT_2FA_REMOVE
Definition: RBAC.h:252
@ RBAC_PERM_COMMAND_ACCOUNT_SET_ADDON
Definition: RBAC.h:141
@ RBAC_PERM_COMMAND_ACCOUNT_SET_SECLEVEL
Definition: RBAC.h:142
@ RBAC_PERM_COMMAND_ACCOUNT_ADDON
Definition: RBAC.h:132
@ RBAC_PERM_COMMAND_ACCOUNT_ONLINE_LIST
Definition: RBAC.h:138
@ RBAC_PERM_COMMAND_ACCOUNT
Definition: RBAC.h:131
@ RBAC_PERM_COMMAND_ACCOUNT_2FA_SETUP
Definition: RBAC.h:251
@ RBAC_PERM_COMMAND_ACCOUNT_CREATE
Definition: RBAC.h:133
@ RBAC_PERM_COMMAND_ACCOUNT_SET_SEC_EMAIL
Definition: RBAC.h:179
@ RBAC_PERM_COMMAND_ACCOUNT_EMAIL
Definition: RBAC.h:177
@ RBAC_PERM_COMMAND_ACCOUNT_PASSWORD
Definition: RBAC.h:139
@ RBAC_PERM_COMMAND_ACCOUNT_LOCK_COUNTRY
Definition: RBAC.h:136
@ RBAC_PERM_COMMAND_ACCOUNT_LOCK_IP
Definition: RBAC.h:137
@ RBAC_PERM_COMMAND_ACCOUNT_SET_2FA
Definition: RBAC.h:253
@ RBAC_PERM_COMMAND_ACCOUNT_SET_PASSWORD
Definition: RBAC.h:143
@ RBAC_PERM_EMAIL_CONFIRM_FOR_PASS_CHANGE
Definition: RBAC.h:102
@ RBAC_PERM_COMMAND_ACCOUNT_SET_SEC_REGMAIL
Definition: RBAC.h:180
std::vector< uint8 > Secret
Definition: TOTP.h:30
static bool ValidateToken(Secret const &key, uint32 token)
Definition: TOTP.cpp:41
static constexpr size_t RECOMMENDED_SECRET_LENGTH
Definition: TOTP.h:29
static Optional< std::vector< uint8 > > Decode(std::string_view data)
Definition: Base32.cpp:52
static std::string Encode(std::vector< uint8 > const &data)
Definition: Base32.cpp:47