aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/bnetserver/REST/LoginRESTService.cpp168
-rw-r--r--src/server/bnetserver/REST/LoginRESTService.h21
-rw-r--r--src/server/bnetserver/Server/Session.cpp183
-rw-r--r--src/server/bnetserver/Server/Session.h12
-rw-r--r--src/server/bnetserver/Services/AuthenticationService.cpp11
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.cpp8
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.h2
7 files changed, 186 insertions, 219 deletions
diff --git a/src/server/bnetserver/REST/LoginRESTService.cpp b/src/server/bnetserver/REST/LoginRESTService.cpp
index 8b84b1a86f5..9fd4b246df7 100644
--- a/src/server/bnetserver/REST/LoginRESTService.cpp
+++ b/src/server/bnetserver/REST/LoginRESTService.cpp
@@ -51,13 +51,10 @@ public:
soap* GetClient() const { return _client.get(); }
void SetCallback(std::unique_ptr<QueryCallback> callback) { _callback = std::move(callback); }
- std::unique_ptr<Battlenet::Session::AccountInfo>& GetResult() { return _result; }
- void SetResult(std::unique_ptr<Battlenet::Session::AccountInfo> result) { _result = std::move(result); }
private:
std::shared_ptr<soap> _client;
std::unique_ptr<QueryCallback> _callback;
- std::unique_ptr<Battlenet::Session::AccountInfo> _result;
};
int32 handle_get_plugin(soap* soapClient)
@@ -127,10 +124,6 @@ bool LoginRESTService::Start(boost::asio::io_service* ioService)
input->set_type("submit");
input->set_label("Log In");
- _loginTicketCleanupTimer = new boost::asio::deadline_timer(*ioService);
- _loginTicketCleanupTimer->expires_from_now(boost::posix_time::seconds(10));
- _loginTicketCleanupTimer->async_wait(std::bind(&LoginRESTService::CleanupLoginTickets, this, std::placeholders::_1));
-
_thread = std::thread(std::bind(&LoginRESTService::Run, this));
return true;
}
@@ -138,7 +131,6 @@ bool LoginRESTService::Start(boost::asio::io_service* ioService)
void LoginRESTService::Stop()
{
_stopped = true;
- _loginTicketCleanupTimer->cancel();
_thread.join();
}
@@ -277,49 +269,68 @@ int32 LoginRESTService::HandlePost(soap* soapClient)
Utf8ToUpperOnlyLatin(login);
Utf8ToUpperOnlyLatin(password);
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO);
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_AUTHENTICATION);
stmt->setString(0, login);
std::string sentPasswordHash = CalculateShaPassHash(login, password);
std::shared_ptr<AsyncLoginRequest> request = std::make_shared<AsyncLoginRequest>(*reinterpret_cast<std::shared_ptr<soap>*>(soapClient->user));
request->SetCallback(Trinity::make_unique<QueryCallback>(LoginDatabase.AsyncQuery(stmt)
- .WithChainingPreparedCallback([request, login, sentPasswordHash](QueryCallback& callback, PreparedQueryResult result)
+ .WithChainingPreparedCallback([request, login, sentPasswordHash, this](QueryCallback& callback, PreparedQueryResult result)
{
if (result)
{
- std::string pass_hash = result->Fetch()[13].GetString();
-
- request->SetResult(Trinity::make_unique<Battlenet::Session::AccountInfo>());
- request->GetResult()->LoadResult(result);
+ Field* fields = result->Fetch();
+ uint32 accountId = fields[0].GetUInt32();
+ std::string pass_hash = fields[1].GetString();
+ uint32 failedLogins = fields[2].GetUInt32();
+ std::string loginTicket = fields[3].GetString();
+ uint32 loginTicketExpiry = fields[4].GetUInt32();
+ bool isBanned = fields[5].GetUInt64() != 0;
if (sentPasswordHash == pass_hash)
{
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS_BY_BNET_ID);
- stmt->setUInt32(0, request->GetResult()->Id);
- callback.SetNextQuery(LoginDatabase.AsyncQuery(stmt));
+ if (loginTicket.empty() || loginTicketExpiry < time(nullptr))
+ {
+ BigNumber ticket;
+ ticket.SetRand(20 * 8);
+
+ loginTicket = "TC-" + ByteArrayToHexStr(ticket.AsByteArray(20).get(), 20);
+ }
+
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_AUTHENTICATION);
+ stmt->setString(0, loginTicket);
+ stmt->setUInt32(1, time(nullptr) + 3600);
+ stmt->setUInt32(2, accountId);
+ callback.WithPreparedCallback([request, loginTicket](PreparedQueryResult)
+ {
+ Battlenet::JSON::Login::LoginResult loginResult;
+ loginResult.set_authentication_state(Battlenet::JSON::Login::DONE);
+ loginResult.set_login_ticket(loginTicket);
+ sLoginService.SendResponse(request->GetClient(), loginResult);
+ }).SetNextQuery(LoginDatabase.AsyncQuery(stmt));
return;
}
- else if (!request->GetResult()->IsBanned)
+ else if (!isBanned)
{
std::string ip_address = boost::asio::ip::address_v4(request->GetClient()->ip).to_string();
uint32 maxWrongPassword = uint32(sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0));
if (sConfigMgr->GetBoolDefault("WrongPass.Logging", false))
- TC_LOG_DEBUG("server.rest", "[%s, Account %s, Id %u] Attempted to connect with wrong password!", ip_address.c_str(), login.c_str(), request->GetResult()->Id);
+ TC_LOG_DEBUG("server.rest", "[%s, Account %s, Id %u] Attempted to connect with wrong password!", ip_address.c_str(), login.c_str(), accountId);
if (maxWrongPassword)
{
SQLTransaction trans = LoginDatabase.BeginTransaction();
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS);
- stmt->setUInt32(0, request->GetResult()->Id);
+ stmt->setUInt32(0, accountId);
trans->Append(stmt);
- ++request->GetResult()->FailedLogins;
+ ++failedLogins;
- TC_LOG_DEBUG("server.rest", "MaxWrongPass : %u, failed_login : %u", maxWrongPassword, request->GetResult()->Id);
+ TC_LOG_DEBUG("server.rest", "MaxWrongPass : %u, failed_login : %u", maxWrongPassword, accountId);
- if (request->GetResult()->FailedLogins >= maxWrongPassword)
+ if (failedLogins >= maxWrongPassword)
{
BanMode banType = BanMode(sConfigMgr->GetIntDefault("WrongPass.BanType", uint16(BanMode::BAN_IP)));
int32 banTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600);
@@ -327,7 +338,7 @@ int32 LoginRESTService::HandlePost(soap* soapClient)
if (banType == BanMode::BAN_ACCOUNT)
{
stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ACCOUNT_AUTO_BANNED);
- stmt->setUInt32(0, request->GetResult()->Id);
+ stmt->setUInt32(0, accountId);
}
else
{
@@ -339,7 +350,7 @@ int32 LoginRESTService::HandlePost(soap* soapClient)
trans->Append(stmt);
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_RESET_FAILED_LOGINS);
- stmt->setUInt32(0, request->GetResult()->Id);
+ stmt->setUInt32(0, accountId);
trans->Append(stmt);
}
@@ -350,52 +361,6 @@ int32 LoginRESTService::HandlePost(soap* soapClient)
Battlenet::JSON::Login::LoginResult loginResult;
loginResult.set_authentication_state(Battlenet::JSON::Login::DONE);
sLoginService.SendResponse(request->GetClient(), loginResult);
- })
- .WithChainingPreparedCallback([request](QueryCallback& callback, PreparedQueryResult characterCountsResult)
- {
- if (characterCountsResult)
- {
- do
- {
- Field* fields = characterCountsResult->Fetch();
- request->GetResult()->GameAccounts[fields[0].GetUInt32()]
- .CharacterCounts[Battlenet::RealmHandle{ fields[3].GetUInt8(), fields[4].GetUInt8(), fields[2].GetUInt32() }.GetAddress()] = fields[1].GetUInt8();
-
- } while (characterCountsResult->NextRow());
- }
-
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_LAST_PLAYER_CHARACTERS);
- stmt->setUInt32(0, request->GetResult()->Id);
- callback.SetNextQuery(LoginDatabase.AsyncQuery(stmt));
- })
- .WithPreparedCallback([request](PreparedQueryResult lastPlayerCharactersResult)
- {
- if (lastPlayerCharactersResult)
- {
- do
- {
- Field* fields = lastPlayerCharactersResult->Fetch();
- Battlenet::RealmHandle realmId{ fields[1].GetUInt8(), fields[2].GetUInt8(), fields[3].GetUInt32() };
- Battlenet::Session::LastPlayedCharacterInfo& lastPlayedCharacter = request->GetResult()->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());
- }
-
- BigNumber ticket;
- ticket.SetRand(20 * 8);
-
- Battlenet::JSON::Login::LoginResult loginResult;
- loginResult.set_authentication_state(Battlenet::JSON::Login::DONE);
- loginResult.set_login_ticket("TC-" + ByteArrayToHexStr(ticket.AsByteArray(20).get(), 20));
- sLoginService.SendResponse(request->GetClient(), loginResult);
-
- sLoginService.AddLoginTicket(loginResult.login_ticket(), std::move(request->GetResult()));
})));
_ioService->post(std::bind(&LoginRESTService::HandleAsyncRequest, this, std::move(request)));
@@ -433,68 +398,9 @@ std::string LoginRESTService::CalculateShaPassHash(std::string const& name, std:
return ByteArrayToHexStr(sha.GetDigest(), sha.GetLength(), true);
}
-std::unique_ptr<Battlenet::Session::AccountInfo> LoginRESTService::VerifyLoginTicket(std::string const& id)
-{
- std::unique_lock<std::mutex> lock(_loginTicketMutex);
-
- auto itr = _validLoginTickets.find(id);
- if (itr != _validLoginTickets.end())
- {
- if (itr->second.ExpiryTime > time(nullptr))
- {
- std::unique_ptr<Battlenet::Session::AccountInfo> accountInfo = std::move(itr->second.Account);
- _validLoginTickets.erase(itr);
- return accountInfo;
- }
- }
-
- return std::unique_ptr<Battlenet::Session::AccountInfo>();
-}
-
-void LoginRESTService::AddLoginTicket(std::string const& id, std::unique_ptr<Battlenet::Session::AccountInfo> accountInfo)
-{
- std::unique_lock<std::mutex> lock(_loginTicketMutex);
-
- _validLoginTickets[id] = { id, std::move(accountInfo), time(nullptr) + 10 };
-}
-
-void LoginRESTService::CleanupLoginTickets(boost::system::error_code const& error)
-{
- if (error)
- return;
-
- time_t now = time(nullptr);
-
- {
- std::unique_lock<std::mutex> lock(_loginTicketMutex);
- for (auto itr = _validLoginTickets.begin(); itr != _validLoginTickets.end();)
- {
- if (itr->second.ExpiryTime < now)
- itr = _validLoginTickets.erase(itr);
- else
- ++itr;
- }
- }
-
- _loginTicketCleanupTimer->expires_from_now(boost::posix_time::seconds(10));
- _loginTicketCleanupTimer->async_wait(std::bind(&LoginRESTService::CleanupLoginTickets, this, std::placeholders::_1));
-}
-
-LoginRESTService::LoginTicket& LoginRESTService::LoginTicket::operator=(LoginTicket&& right)
-{
- if (this != &right)
- {
- Id = std::move(right.Id);
- Account = std::move(right.Account);
- ExpiryTime = right.ExpiryTime;
- }
-
- return *this;
-}
-
Namespace namespaces[] =
{
- { NULL, NULL, NULL, NULL }
+ { nullptr, nullptr, nullptr, nullptr }
};
LoginRESTService& LoginRESTService::Instance()
diff --git a/src/server/bnetserver/REST/LoginRESTService.h b/src/server/bnetserver/REST/LoginRESTService.h
index ff9729e3333..e3a74d92907 100644
--- a/src/server/bnetserver/REST/LoginRESTService.h
+++ b/src/server/bnetserver/REST/LoginRESTService.h
@@ -24,9 +24,7 @@
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ip/address.hpp>
-#include <boost/asio/deadline_timer.hpp>
#include <atomic>
-#include <mutex>
#include <thread>
class AsyncLoginRequest;
@@ -42,7 +40,7 @@ enum class BanMode
class LoginRESTService
{
public:
- LoginRESTService() : _ioService(nullptr), _stopped(false), _port(0), _loginTicketCleanupTimer(nullptr) { }
+ LoginRESTService() : _ioService(nullptr), _stopped(false), _port(0) { }
static LoginRESTService& Instance();
@@ -51,8 +49,6 @@ public:
boost::asio::ip::tcp::endpoint const& GetAddressForClient(boost::asio::ip::address const& address) const;
- std::unique_ptr<Battlenet::Session::AccountInfo> VerifyLoginTicket(std::string const& id);
-
private:
void Run();
@@ -68,18 +64,6 @@ private:
std::string CalculateShaPassHash(std::string const& name, std::string const& password);
- void AddLoginTicket(std::string const& id, std::unique_ptr<Battlenet::Session::AccountInfo> accountInfo);
- void CleanupLoginTickets(boost::system::error_code const& error);
-
- struct LoginTicket
- {
- LoginTicket& operator=(LoginTicket&& right);
-
- std::string Id;
- std::unique_ptr<Battlenet::Session::AccountInfo> Account;
- std::time_t ExpiryTime;
- };
-
struct ResponseCodePlugin
{
static char const* const PluginId;
@@ -110,9 +94,6 @@ private:
int32 _port;
boost::asio::ip::tcp::endpoint _externalAddress;
boost::asio::ip::tcp::endpoint _localAddress;
- std::mutex _loginTicketMutex;
- std::unordered_map<std::string, LoginTicket> _validLoginTickets;
- boost::asio::deadline_timer* _loginTicketCleanupTimer;
};
#define sLoginService LoginRESTService::Instance()
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);
diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h
index 99a0ec088a1..398ca176840 100644
--- a/src/server/bnetserver/Server/Session.h
+++ b/src/server/bnetserver/Server/Session.h
@@ -34,6 +34,8 @@ using boost::asio::ip::tcp;
namespace pb = google::protobuf;
+class ServiceBase;
+
namespace bgs
{
namespace protocol
@@ -114,7 +116,7 @@ namespace Battlenet
bool IsLockedToIP;
std::string LockCountry;
std::string LastIP;
- uint32 FailedLogins;
+ uint32 LoginTicketExpiry;
bool IsBanned;
bool IsPermanenetlyBanned;
@@ -141,8 +143,8 @@ namespace Battlenet
void SendRequest(uint32 serviceHash, uint32 methodId, pb::Message const* request);
- uint32 HandleLogon(authentication::v1::LogonRequest const* logonRequest);
- uint32 HandleVerifyWebCredentials(authentication::v1::VerifyWebCredentialsRequest const* verifyWebCredentialsRequest);
+ uint32 HandleLogon(authentication::v1::LogonRequest const* logonRequest, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation);
+ uint32 HandleVerifyWebCredentials(authentication::v1::VerifyWebCredentialsRequest const* verifyWebCredentialsRequest, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation);
uint32 HandleGetAccountState(account::v1::GetAccountStateRequest const* request, account::v1::GetAccountStateResponse* response);
uint32 HandleGetGameAccountState(account::v1::GetGameAccountStateRequest const* request, account::v1::GetGameAccountStateResponse* response);
uint32 HandleProcessClientRequest(game_utilities::v1::ClientRequest const* request, game_utilities::v1::ClientResponse* response);
@@ -164,6 +166,8 @@ namespace Battlenet
void CheckIpCallback(PreparedQueryResult result);
+ uint32 VerifyWebCredentials(std::string const& webCredentials, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation);
+
typedef uint32(Session::*ClientRequestHandler)(std::unordered_map<std::string, Variant const*> const&, game_utilities::v1::ClientResponse*);
static std::unordered_map<std::string, ClientRequestHandler> const ClientRequestHandlers;
@@ -176,7 +180,7 @@ namespace Battlenet
MessageBuffer _headerBuffer;
MessageBuffer _packetBuffer;
- std::unique_ptr<AccountInfo> _accountInfo;
+ std::shared_ptr<AccountInfo> _accountInfo;
GameAccountInfo* _gameAccountInfo; // Points at selected game account (inside _gameAccounts)
std::string _locale;
diff --git a/src/server/bnetserver/Services/AuthenticationService.cpp b/src/server/bnetserver/Services/AuthenticationService.cpp
index 45e9a0920f2..6fe9b481907 100644
--- a/src/server/bnetserver/Services/AuthenticationService.cpp
+++ b/src/server/bnetserver/Services/AuthenticationService.cpp
@@ -22,17 +22,12 @@ Battlenet::Services::Authentication::Authentication(Session* session) : Authenti
{
}
-uint32 Battlenet::Services::Authentication::HandleLogon(authentication::v1::LogonRequest const* request, NoData* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation)
+uint32 Battlenet::Services::Authentication::HandleLogon(authentication::v1::LogonRequest const* request, NoData* /*response*/, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation)
{
- uint32 status = _session->HandleLogon(request);
- // turning this into async call will be done by stealing the continuation and calling it when done
- // just a test here
- continuation(this, status, response);
- continuation = nullptr;
- return status;
+ return _session->HandleLogon(request, continuation);
}
uint32 Battlenet::Services::Authentication::HandleVerifyWebCredentials(authentication::v1::VerifyWebCredentialsRequest const* request, NoData* /*response*/, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation)
{
- return _session->HandleVerifyWebCredentials(request);
+ return _session->HandleVerifyWebCredentials(request, continuation);
}
diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp
index 7c49b1846fd..dba35a7c906 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/database/Database/Implementation/LoginDatabase.cpp
@@ -116,12 +116,14 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_ACCOUNT_MUTE_INFO, "SELECT mutedate, mutetime, mutereason, mutedby FROM account_muted WHERE guid = ? ORDER BY mutedate ASC", CONNECTION_SYNCH);
PrepareStatement(LOGIN_DEL_ACCOUNT_MUTED, "DELETE FROM account_muted WHERE guid = ?", CONNECTION_ASYNC);
-#define BnetAccountInfo "ba.id, UPPER(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"
+#define BnetAccountInfo "ba.id, UPPER(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"
#define BnetGameAccountInfo "a.id, a.username, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, ab.unbandate = ab.bandate, aa.gmlevel"
- PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT " BnetAccountInfo ", " BnetGameAccountInfo ", ba.sha_pass_hash"
+ PrepareStatement(LOGIN_SEL_BNET_AUTHENTICATION, "SELECT ba.id, ba.sha_pass_hash, ba.failed_logins, ba.LoginTicket, ba.LoginTicketExpiry, bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id WHERE email = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_UPD_BNET_AUTHENTICATION, "UPDATE battlenet_accounts SET LoginTicket = ?, LoginTicketExpiry = ? WHERE id = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT " BnetAccountInfo ", " BnetGameAccountInfo ""
" FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account a ON ba.id = a.battlenet_account"
- " LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID = -1 WHERE ba.email = ? ORDER BY a.id", CONNECTION_ASYNC);
+ " LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID = -1 WHERE ba.LoginTicket = ? ORDER BY a.id", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LOGIN_INFO, "UPDATE account SET sessionkey = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS_BY_ACCOUNT_ID, "SELECT rc.acctid, rc.numchars, r.id, r.Region, r.Battlegroup FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_ASYNC);
diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h
index b58630b4ae5..dae89a9fb3a 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.h
+++ b/src/server/database/Database/Implementation/LoginDatabase.h
@@ -110,6 +110,8 @@ enum LoginDatabaseStatements : uint32
LOGIN_SEL_ACCOUNT_MUTE_INFO,
LOGIN_DEL_ACCOUNT_MUTED,
+ LOGIN_SEL_BNET_AUTHENTICATION,
+ LOGIN_UPD_BNET_AUTHENTICATION,
LOGIN_SEL_BNET_ACCOUNT_INFO,
LOGIN_UPD_BNET_LAST_LOGIN_INFO,
LOGIN_UPD_BNET_GAME_ACCOUNT_LOGIN_INFO,