9
9
#include < cstring>
10
10
#include < istream>
11
11
#include < string>
12
+ #include < openssl/sha.h>
12
13
#include < unordered_set>
14
+ #include < iomanip>
13
15
14
16
#include " ChannelMgr.h"
15
17
#include " CharacterCache.h"
@@ -93,21 +95,22 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
93
95
uint32 accountId = sCharacterCache ->GetCharacterAccountIdByGuid (playerGuid);
94
96
if (!accountId)
95
97
return ;
96
-
98
+
97
99
WorldSession* masterSession = masterAccountId ? sWorldSessionMgr ->FindSession (masterAccountId) : nullptr ;
98
100
Player* masterPlayer = masterSession ? masterSession->GetPlayer () : nullptr ;
99
101
100
102
bool isRndbot = !masterAccountId;
101
103
bool sameAccount = sPlayerbotAIConfig ->allowAccountBots && accountId == masterAccountId;
102
104
Guild* guild = masterPlayer ? sGuildMgr ->GetGuildById (masterPlayer->GetGuildId ()) : nullptr ;
103
- bool sameGuild = sPlayerbotAIConfig ->allowGuildBots && guild && guild->GetMember (playerGuid);
105
+ bool sameGuild = sPlayerbotAIConfig ->allowGuildBots && guild && guild->GetMember (playerGuid);
104
106
bool addClassBot = sRandomPlayerbotMgr ->IsAddclassBot (playerGuid.GetCounter ());
107
+ bool linkedAccount = sPlayerbotAIConfig ->allowTrustedAccountBots && IsAccountLinked (accountId, masterAccountId);
105
108
106
109
bool allowed = true ;
107
110
std::ostringstream out;
108
111
std::string botName;
109
112
sCharacterCache ->GetCharacterNameByGuid (playerGuid, botName);
110
- if (!isRndbot && !sameAccount && !sameGuild && !addClassBot)
113
+ if (!isRndbot && !sameAccount && !sameGuild && !addClassBot && !linkedAccount )
111
114
{
112
115
allowed = false ;
113
116
out << " Failure: You are not allowed to control bot " << botName.c_str ();
@@ -144,13 +147,20 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
144
147
}
145
148
146
149
botLoading.insert (playerGuid);
147
-
150
+
148
151
// Always login in with world session to avoid race condition
149
152
sWorld ->AddQueryHolderCallback (CharacterDatabase.DelayQueryHolder (holder))
150
153
.AfterComplete ([this ](SQLQueryHolderBase const & holder)
151
154
{ HandlePlayerBotLoginCallback (static_cast <PlayerbotLoginQueryHolder const &>(holder)); });
152
155
}
153
156
157
+ bool PlayerbotHolder::IsAccountLinked (uint32 accountId, uint32 linkedAccountId)
158
+ {
159
+ QueryResult result = PlayerbotsDatabase.Query (
160
+ " SELECT 1 FROM playerbot_account_links WHERE account_id = {} AND linked_account_id = {}" , accountId, linkedAccountId);
161
+ return result != nullptr ;
162
+ }
163
+
154
164
void PlayerbotHolder::HandlePlayerBotLoginCallback (PlayerbotLoginQueryHolder const & holder)
155
165
{
156
166
uint32 botAccountId = holder.GetAccountId ();
@@ -181,7 +191,7 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
181
191
{
182
192
LOG_DEBUG (" mod-playerbots" , " Master session found but no player is associated for master account ID: {}" , masterAccount);
183
193
}
184
-
194
+
185
195
sRandomPlayerbotMgr ->OnPlayerLogin (bot);
186
196
OnBotLogin (bot);
187
197
@@ -425,7 +435,7 @@ void PlayerbotHolder::DisablePlayerBot(ObjectGuid guid)
425
435
426
436
void PlayerbotHolder::RemoveFromPlayerbotsMap (ObjectGuid guid)
427
437
{
428
- playerBots.erase (guid);
438
+ playerBots.erase (guid);
429
439
}
430
440
431
441
Player* PlayerbotHolder::GetPlayerBot (ObjectGuid playerGuid) const
@@ -451,7 +461,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
451
461
452
462
sPlayerbotsMgr ->AddPlayerbotData (bot, true );
453
463
playerBots[bot->GetGUID ()] = bot;
454
-
464
+
455
465
OnBotLoginInternal (bot);
456
466
457
467
PlayerbotAI* botAI = GET_PLAYERBOT_AI (bot);
@@ -674,8 +684,11 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
674
684
if (!accountId)
675
685
return " character not found" ;
676
686
677
- if (!sPlayerbotAIConfig ->allowAccountBots && accountId != masterAccountId)
678
- return " you can only add bots from your own account" ;
687
+ if (!sPlayerbotAIConfig ->allowAccountBots && accountId != masterAccountId &&
688
+ !(sPlayerbotAIConfig ->allowTrustedAccountBots && IsAccountLinked (accountId, masterAccountId)))
689
+ {
690
+ return " you can only add bots from your own account or linked accounts" ;
691
+ }
679
692
}
680
693
681
694
AddPlayerBot (guid, masterAccountId);
@@ -701,12 +714,12 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
701
714
702
715
if (!bot)
703
716
return " bot not found" ;
704
-
717
+
705
718
bool addClassBot = sRandomPlayerbotMgr ->IsAddclassBot (guid.GetCounter ());
706
719
707
720
if (!addClassBot)
708
721
return " ERROR: You can not use this command on non-addclass bot." ;
709
-
722
+
710
723
if (!admin)
711
724
{
712
725
Player* master = ObjectAccessor::FindConnectedPlayer (masterguid);
@@ -732,7 +745,7 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
732
745
{
733
746
return " Initialization already in progress, please wait." ;
734
747
}
735
-
748
+
736
749
int gs;
737
750
if (cmd == " init=white" || cmd == " init=common" )
738
751
{
@@ -1705,3 +1718,121 @@ PlayerbotMgr* PlayerbotsMgr::GetPlayerbotMgr(Player* player)
1705
1718
1706
1719
return nullptr ;
1707
1720
}
1721
+
1722
+ void PlayerbotMgr::HandleSetSecurityKeyCommand (Player* player, const std::string& key)
1723
+ {
1724
+ uint32 accountId = player->GetSession ()->GetAccountId ();
1725
+
1726
+ // Hash the security key using SHA-256
1727
+ unsigned char hash[SHA256_DIGEST_LENGTH];
1728
+ SHA256 ((unsigned char *)key.c_str (), key.size (), hash);
1729
+
1730
+ // Convert the hash to a hexadecimal string
1731
+ std::ostringstream hashedKey;
1732
+ for (int i = 0 ; i < SHA256_DIGEST_LENGTH; ++i)
1733
+ hashedKey << std::hex << std::setw (2 ) << std::setfill (' 0' ) << (int )hash[i];
1734
+
1735
+ // Store the hashed key in the database
1736
+ PlayerbotsDatabase.Execute (
1737
+ " REPLACE INTO playerbot_account_keys (account_id, security_key) VALUES ({}, '{}')" ,
1738
+ accountId, hashedKey.str ());
1739
+
1740
+ ChatHandler (player->GetSession ()).PSendSysMessage (" Security key set successfully." );
1741
+ }
1742
+
1743
+ void PlayerbotMgr::HandleLinkAccountCommand (Player* player, const std::string& accountName, const std::string& key)
1744
+ {
1745
+ QueryResult result = LoginDatabase.Query (" SELECT id FROM account WHERE username = '{}'" , accountName);
1746
+ if (!result)
1747
+ {
1748
+ ChatHandler (player->GetSession ()).PSendSysMessage (" Account not found." );
1749
+ return ;
1750
+ }
1751
+
1752
+ Field* fields = result->Fetch ();
1753
+ uint32 linkedAccountId = fields[0 ].Get <uint32>();
1754
+
1755
+ result = PlayerbotsDatabase.Query (" SELECT security_key FROM playerbot_account_keys WHERE account_id = {}" , linkedAccountId);
1756
+ if (!result)
1757
+ {
1758
+ ChatHandler (player->GetSession ()).PSendSysMessage (" Invalid security key." );
1759
+ return ;
1760
+ }
1761
+
1762
+ // Hash the provided key
1763
+ unsigned char hash[SHA256_DIGEST_LENGTH];
1764
+ SHA256 ((unsigned char *)key.c_str (), key.size (), hash);
1765
+
1766
+ // Convert the hash to a hexadecimal string
1767
+ std::ostringstream hashedKey;
1768
+ for (int i = 0 ; i < SHA256_DIGEST_LENGTH; ++i)
1769
+ hashedKey << std::hex << std::setw (2 ) << std::setfill (' 0' ) << (int )hash[i];
1770
+
1771
+ // Compare the hashed key with the stored hashed key
1772
+ std::string storedKey = result->Fetch ()->Get <std::string>();
1773
+ if (hashedKey.str () != storedKey)
1774
+ {
1775
+ ChatHandler (player->GetSession ()).PSendSysMessage (" Invalid security key." );
1776
+ return ;
1777
+ }
1778
+
1779
+ uint32 accountId = player->GetSession ()->GetAccountId ();
1780
+ PlayerbotsDatabase.Execute (
1781
+ " INSERT IGNORE INTO playerbot_account_links (account_id, linked_account_id) VALUES ({}, {})" ,
1782
+ accountId, linkedAccountId);
1783
+ PlayerbotsDatabase.Execute (
1784
+ " INSERT IGNORE INTO playerbot_account_links (account_id, linked_account_id) VALUES ({}, {})" ,
1785
+ linkedAccountId, accountId);
1786
+
1787
+ ChatHandler (player->GetSession ()).PSendSysMessage (" Account linked successfully." );
1788
+ }
1789
+
1790
+ void PlayerbotMgr::HandleViewLinkedAccountsCommand (Player* player)
1791
+ {
1792
+ uint32 accountId = player->GetSession ()->GetAccountId ();
1793
+ QueryResult result = PlayerbotsDatabase.Query (" SELECT linked_account_id FROM playerbot_account_links WHERE account_id = {}" , accountId);
1794
+
1795
+ if (!result)
1796
+ {
1797
+ ChatHandler (player->GetSession ()).PSendSysMessage (" No linked accounts." );
1798
+ return ;
1799
+ }
1800
+
1801
+ ChatHandler (player->GetSession ()).PSendSysMessage (" Linked accounts:" );
1802
+ do
1803
+ {
1804
+ Field* fields = result->Fetch ();
1805
+ uint32 linkedAccountId = fields[0 ].Get <uint32>();
1806
+
1807
+ QueryResult accountResult = LoginDatabase.Query (" SELECT username FROM account WHERE id = {}" , linkedAccountId);
1808
+ if (accountResult)
1809
+ {
1810
+ Field* accountFields = accountResult->Fetch ();
1811
+ std::string username = accountFields[0 ].Get <std::string>();
1812
+ ChatHandler (player->GetSession ()).PSendSysMessage (" - {}" , username.c_str ());
1813
+ }
1814
+ else
1815
+ {
1816
+ ChatHandler (player->GetSession ()).PSendSysMessage (" - Unknown account" );
1817
+ }
1818
+ } while (result->NextRow ());
1819
+ }
1820
+
1821
+ void PlayerbotMgr::HandleUnlinkAccountCommand (Player* player, const std::string& accountName)
1822
+ {
1823
+ QueryResult result = LoginDatabase.Query (" SELECT id FROM account WHERE username = '{}'" , accountName);
1824
+ if (!result)
1825
+ {
1826
+ ChatHandler (player->GetSession ()).PSendSysMessage (" Account not found." );
1827
+ return ;
1828
+ }
1829
+
1830
+ Field* fields = result->Fetch ();
1831
+ uint32 linkedAccountId = fields[0 ].Get <uint32>();
1832
+ uint32 accountId = player->GetSession ()->GetAccountId ();
1833
+
1834
+ PlayerbotsDatabase.Execute (" DELETE FROM playerbot_account_links WHERE (account_id = {} AND linked_account_id = {}) OR (account_id = {} AND linked_account_id = {})" ,
1835
+ accountId, linkedAccountId, linkedAccountId, accountId);
1836
+
1837
+ ChatHandler (player->GetSession ()).PSendSysMessage (" Account unlinked successfully." );
1838
+ }
0 commit comments