diff options
| author | Shauren <shauren.trinity@gmail.com> | 2017-09-22 18:26:00 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2017-09-22 18:26:00 +0200 |
| commit | 91626f0339486714dc7c0d6f041c83b3ad954497 (patch) | |
| tree | e750edc0e6acea651639a0ef860be2ae21a2f4a7 /src/server/bnetserver/Server/Session.cpp | |
| parent | 0c0f099dd6c7474e57d80e47f6f5a2dd97bf26af (diff) | |
Core/Bnet: Moved loading account info from rest service to session
* This improves concurrency by removes thread synchronization when checking login tickets
* Also allows users to use external (web based) login systems
Diffstat (limited to 'src/server/bnetserver/Server/Session.cpp')
| -rw-r--r-- | src/server/bnetserver/Server/Session.cpp | 183 |
1 files changed, 130 insertions, 53 deletions
diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 1c7d4aed521..bc6c4dfb92a 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -30,14 +30,14 @@ void Battlenet::Session::AccountInfo::LoadResult(PreparedQueryResult result) { - // ba.id, ba.email, ba.locked, ba.lock_country, ba.last_ip, ba.failed_logins, bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, bab.unbandate = bab.bandate FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab WHERE email = ? + // ba.id, ba.email, ba.locked, ba.lock_country, ba.last_ip, ba.LoginTicketExpiry, bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, bab.unbandate = bab.bandate FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab WHERE email = ? Field* fields = result->Fetch(); Id = fields[0].GetUInt32(); Login = fields[1].GetString(); IsLockedToIP = fields[2].GetBool(); LockCountry = fields[3].GetString(); LastIP = fields[4].GetString(); - FailedLogins = fields[5].GetUInt32(); + LoginTicketExpiry = fields[5].GetUInt32(); IsBanned = fields[6].GetUInt64() != 0; IsPermanenetlyBanned = fields[7].GetUInt64() != 0; @@ -206,7 +206,7 @@ void Battlenet::Session::SendRequest(uint32 serviceHash, uint32 methodId, pb::Me AsyncWrite(&packet); } -uint32 Battlenet::Session::HandleLogon(authentication::v1::LogonRequest const* logonRequest) +uint32 Battlenet::Session::HandleLogon(authentication::v1::LogonRequest const* logonRequest, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& /*continuation*/) { if (logonRequest->program() != "WoW") { @@ -228,6 +228,7 @@ uint32 Battlenet::Session::HandleLogon(authentication::v1::LogonRequest const* l _locale = logonRequest->locale(); _os = logonRequest->platform(); + _build = logonRequest->application_version(); boost::asio::ip::tcp::endpoint const& endpoint = sLoginService.GetAddressForClient(GetRemoteIpAddress()); @@ -238,77 +239,152 @@ uint32 Battlenet::Session::HandleLogon(authentication::v1::LogonRequest const* l return ERROR_OK; } -uint32 Battlenet::Session::HandleVerifyWebCredentials(authentication::v1::VerifyWebCredentialsRequest const* verifyWebCredentialsRequest) +uint32 Battlenet::Session::HandleVerifyWebCredentials(authentication::v1::VerifyWebCredentialsRequest const* verifyWebCredentialsRequest, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) { - authentication::v1::LogonResult logonResult; - logonResult.set_error_code(0); - _accountInfo = sLoginService.VerifyLoginTicket(verifyWebCredentialsRequest->web_credentials()); - if (!_accountInfo) - return ERROR_DENIED; + return VerifyWebCredentials(verifyWebCredentialsRequest->web_credentials(), continuation); +} - std::string ip_address = GetRemoteIpAddress().to_string(); +uint32 Battlenet::Session::VerifyWebCredentials(std::string const& webCredentials, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); + stmt->setString(0, webCredentials); - // If the IP is 'locked', check that the player comes indeed from the correct IP address - if (_accountInfo->IsLockedToIP) + std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)> asyncContinuation = std::move(continuation); + std::shared_ptr<AccountInfo> accountInfo = std::make_shared<AccountInfo>(); + _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithChainingPreparedCallback([this, accountInfo, asyncContinuation](QueryCallback& callback, PreparedQueryResult result) { - TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is locked to IP - '%s' is logging in from '%s'", - _accountInfo->Login.c_str(), _accountInfo->LastIP.c_str(), ip_address.c_str()); + if (!result) + { + asyncContinuation(&Battlenet::Services::Authentication(this), ERROR_DENIED, &NoData()); + return; + } - if (_accountInfo->LastIP != ip_address) - return ERROR_RISK_ACCOUNT_LOCKED; - } - else + accountInfo->LoadResult(result); + + if (accountInfo->LoginTicketExpiry < time(nullptr)) + { + asyncContinuation(&Battlenet::Services::Authentication(this), ERROR_TIMED_OUT, &NoData()); + return; + } + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS_BY_BNET_ID); + stmt->setUInt32(0, accountInfo->Id); + callback.SetNextQuery(LoginDatabase.AsyncQuery(stmt)); + }) + .WithChainingPreparedCallback([accountInfo](QueryCallback& callback, PreparedQueryResult characterCountsResult) { - TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is not locked to ip", _accountInfo->Login.c_str()); - if (_accountInfo->LockCountry.empty() || _accountInfo->LockCountry == "00") - TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is not locked to country", _accountInfo->Login.c_str()); - else if (!_accountInfo->LockCountry.empty() && !_ipCountry.empty()) + if (characterCountsResult) { - TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is locked to country: '%s' Player country is '%s'", - _accountInfo->Login.c_str(), _accountInfo->LockCountry.c_str(), _ipCountry.c_str()); + do + { + Field* fields = characterCountsResult->Fetch(); + accountInfo->GameAccounts[fields[0].GetUInt32()] + .CharacterCounts[Battlenet::RealmHandle{ fields[3].GetUInt8(), fields[4].GetUInt8(), fields[2].GetUInt32() }.GetAddress()] = fields[1].GetUInt8(); - if (_ipCountry != _accountInfo->LockCountry) - return ERROR_RISK_ACCOUNT_LOCKED; + } while (characterCountsResult->NextRow()); } - } - // If the account is banned, reject the logon attempt - if (_accountInfo->IsBanned) + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_LAST_PLAYER_CHARACTERS); + stmt->setUInt32(0, accountInfo->Id); + callback.SetNextQuery(LoginDatabase.AsyncQuery(stmt)); + }) + .WithPreparedCallback([this, accountInfo, asyncContinuation](PreparedQueryResult lastPlayerCharactersResult) { - if (_accountInfo->IsPermanenetlyBanned) + if (lastPlayerCharactersResult) + { + do + { + Field* fields = lastPlayerCharactersResult->Fetch(); + Battlenet::RealmHandle realmId{ fields[1].GetUInt8(), fields[2].GetUInt8(), fields[3].GetUInt32() }; + Battlenet::Session::LastPlayedCharacterInfo& lastPlayedCharacter = accountInfo->GameAccounts[fields[0].GetUInt32()] + .LastPlayedCharacters[realmId.GetSubRegionAddress()]; + + lastPlayedCharacter.RealmId = realmId; + lastPlayedCharacter.CharacterName = fields[4].GetString(); + lastPlayedCharacter.CharacterGUID = fields[5].GetUInt64(); + lastPlayedCharacter.LastPlayedTime = fields[6].GetUInt32(); + + } while (lastPlayerCharactersResult->NextRow()); + } + + _accountInfo = accountInfo; + + std::string ip_address = GetRemoteIpAddress().to_string(); + + // If the IP is 'locked', check that the player comes indeed from the correct IP address + if (_accountInfo->IsLockedToIP) { - TC_LOG_DEBUG("session", "%s [Session::HandleVerifyWebCredentials] Banned account %s tried to login!", GetClientInfo().c_str(), _accountInfo->Login.c_str()); - return ERROR_GAME_ACCOUNT_BANNED; + TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is locked to IP - '%s' is logging in from '%s'", + _accountInfo->Login.c_str(), _accountInfo->LastIP.c_str(), ip_address.c_str()); + + if (_accountInfo->LastIP != ip_address) + { + asyncContinuation(&Battlenet::Services::Authentication(this), ERROR_RISK_ACCOUNT_LOCKED, &NoData()); + return; + } } else { - TC_LOG_DEBUG("session", "%s [Session::HandleVerifyWebCredentials] Temporarily banned account %s tried to login!", GetClientInfo().c_str(), _accountInfo->Login.c_str()); - return ERROR_GAME_ACCOUNT_SUSPENDED; + TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is not locked to ip", _accountInfo->Login.c_str()); + if (_accountInfo->LockCountry.empty() || _accountInfo->LockCountry == "00") + TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is not locked to country", _accountInfo->Login.c_str()); + else if (!_accountInfo->LockCountry.empty() && !_ipCountry.empty()) + { + TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is locked to country: '%s' Player country is '%s'", + _accountInfo->Login.c_str(), _accountInfo->LockCountry.c_str(), _ipCountry.c_str()); + + if (_ipCountry != _accountInfo->LockCountry) + { + asyncContinuation(&Battlenet::Services::Authentication(this), ERROR_RISK_ACCOUNT_LOCKED, &NoData()); + return; + } + } } - } - logonResult.mutable_account_id()->set_low(_accountInfo->Id); - logonResult.mutable_account_id()->set_high(UI64LIT(0x100000000000000)); - for (auto itr = _accountInfo->GameAccounts.begin(); itr != _accountInfo->GameAccounts.end(); ++itr) - { - if (!itr->second.IsBanned) + // If the account is banned, reject the logon attempt + if (_accountInfo->IsBanned) { - EntityId* gameAccountId = logonResult.add_game_account_id(); - gameAccountId->set_low(itr->second.Id); - gameAccountId->set_high(UI64LIT(0x200000200576F57)); + if (_accountInfo->IsPermanenetlyBanned) + { + TC_LOG_DEBUG("session", "%s [Session::HandleVerifyWebCredentials] Banned account %s tried to login!", GetClientInfo().c_str(), _accountInfo->Login.c_str()); + asyncContinuation(&Battlenet::Services::Authentication(this), ERROR_GAME_ACCOUNT_BANNED, &NoData()); + return; + } + else + { + TC_LOG_DEBUG("session", "%s [Session::HandleVerifyWebCredentials] Temporarily banned account %s tried to login!", GetClientInfo().c_str(), _accountInfo->Login.c_str()); + asyncContinuation(&Battlenet::Services::Authentication(this), ERROR_GAME_ACCOUNT_SUSPENDED, &NoData()); + return; + } } - } - if (!_ipCountry.empty()) - logonResult.set_geoip_country(_ipCountry); + authentication::v1::LogonResult logonResult; + logonResult.set_error_code(0); + logonResult.mutable_account_id()->set_low(_accountInfo->Id); + logonResult.mutable_account_id()->set_high(UI64LIT(0x100000000000000)); + for (auto itr = _accountInfo->GameAccounts.begin(); itr != _accountInfo->GameAccounts.end(); ++itr) + { + if (!itr->second.IsBanned) + { + EntityId* gameAccountId = logonResult.add_game_account_id(); + gameAccountId->set_low(itr->second.Id); + gameAccountId->set_high(UI64LIT(0x200000200576F57)); + } + } + + if (!_ipCountry.empty()) + logonResult.set_geoip_country(_ipCountry); + + BigNumber k; + k.SetRand(8 * 64); + logonResult.set_session_key(k.AsByteArray(64).get(), 64); - BigNumber k; - k.SetRand(8 * 64); - logonResult.set_session_key(k.AsByteArray(64).get(), 64); + _authed = true; - _authed = true; + asyncContinuation(&Battlenet::Services::Authentication(this), ERROR_OK, &NoData()); + Service<authentication::v1::AuthenticationListener>(this).OnLogonComplete(&logonResult); + })); - Service<authentication::v1::AuthenticationListener>(this).OnLogonComplete(&logonResult); return ERROR_OK; } @@ -425,6 +501,7 @@ uint32 Battlenet::Session::GetRealmListTicket(std::unordered_map<std::string, Va if (!_gameAccountInfo) return ERROR_UTIL_SERVER_INVALID_IDENTITY_ARGS; + bool clientInfoOk = false; if (Variant const* clientInfo = GetParam(params, "Param_ClientInfo")) { ::JSON::RealmList::RealmListTicketClientInformation data; @@ -433,13 +510,13 @@ uint32 Battlenet::Session::GetRealmListTicket(std::unordered_map<std::string, Va { if (_clientSecret.size() == data.info().secret().size()) { - _build = data.info().version().versionbuild(); + clientInfoOk = true; memcpy(_clientSecret.data(), data.info().secret().data(), _clientSecret.size()); } } } - if (!_build) + if (!clientInfoOk) return ERROR_WOW_SERVICES_DENIED_REALM_LIST_TICKET; PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); |
