Refactoring of BNetServer
This commit is contained in:
@@ -1,30 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
||||
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Framework.Configuration;
|
||||
using Framework.Database;
|
||||
using Framework.Networking;
|
||||
using Framework.Rest;
|
||||
using Framework.Serialization;
|
||||
using Framework.Web;
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Framework.Networking;
|
||||
using System.Net.Sockets;
|
||||
using Framework.Web;
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.Configuration;
|
||||
using Framework.Serialization;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace BNetServer.Networking
|
||||
{
|
||||
@@ -32,14 +19,14 @@ namespace BNetServer.Networking
|
||||
{
|
||||
public RestSession(Socket socket) : base(socket) { }
|
||||
|
||||
public override void Start()
|
||||
public override void Accept()
|
||||
{
|
||||
AsyncHandshake(Global.SessionMgr.GetCertificate());
|
||||
AsyncHandshake(Global.LoginServiceMgr.GetCertificate());
|
||||
}
|
||||
|
||||
public override void ReadHandler(int transferredBytes)
|
||||
{
|
||||
var httpRequest = HttpHelper.ParseRequest(GetReceiveBuffer(), transferredBytes);
|
||||
public async override void ReadHandler(byte[] data, int receivedLength)
|
||||
{
|
||||
var httpRequest = HttpHelper.ParseRequest(data, receivedLength);
|
||||
if (httpRequest == null)
|
||||
return;
|
||||
|
||||
@@ -47,20 +34,14 @@ namespace BNetServer.Networking
|
||||
{
|
||||
case "GET":
|
||||
default:
|
||||
HandleConnectRequest(httpRequest);
|
||||
SendResponse(HttpCode.Ok, Global.LoginServiceMgr.GetFormInput());
|
||||
break;
|
||||
case "POST":
|
||||
HandleLoginRequest(httpRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncRead();
|
||||
}
|
||||
|
||||
public void HandleConnectRequest(HttpHeader request)
|
||||
{
|
||||
// Login form is the same for all clients...
|
||||
SendResponse(HttpCode.Ok, Global.SessionMgr.GetFormInput());
|
||||
await AsyncRead();
|
||||
}
|
||||
|
||||
public void HandleLoginRequest(HttpHeader request)
|
||||
@@ -92,7 +73,7 @@ namespace BNetServer.Networking
|
||||
}
|
||||
}
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_AUTHENTICATION);
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SelBnetAuthentication);
|
||||
stmt.AddValue(0, login);
|
||||
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
@@ -113,7 +94,7 @@ namespace BNetServer.Networking
|
||||
loginTicket = "TC-" + ticket.ToHexString();
|
||||
}
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_AUTHENTICATION);
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UpdBnetAuthentication);
|
||||
stmt.AddValue(0, loginTicket);
|
||||
stmt.AddValue(1, Time.UnixTime + 3600);
|
||||
stmt.AddValue(2, accountId);
|
||||
@@ -126,39 +107,39 @@ namespace BNetServer.Networking
|
||||
uint maxWrongPassword = ConfigMgr.GetDefaultValue("WrongPass.MaxCount", 0u);
|
||||
|
||||
if (ConfigMgr.GetDefaultValue("WrongPass.Logging", false))
|
||||
Log.outDebug(LogFilter.Network, "[{0}, Account {1}, Id {2}] Attempted to connect with wrong password!", request.Host, login, accountId);
|
||||
Log.outDebug(LogFilter.Network, $"[{request.Host}, Account {login}, Id {accountId}] Attempted to connect with wrong password!");
|
||||
|
||||
if (maxWrongPassword != 0)
|
||||
{
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_FAILED_LOGINS);
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UpdBnetFailedLogins);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
|
||||
++failedLogins;
|
||||
|
||||
Log.outDebug(LogFilter.Network, "MaxWrongPass : {0}, failed_login : {1}", maxWrongPassword, accountId);
|
||||
Log.outDebug(LogFilter.Network, "MaxWrongPass : {maxWrongPassword}, failed_login : {accountId}");
|
||||
|
||||
if (failedLogins >= maxWrongPassword)
|
||||
{
|
||||
BanMode banType = ConfigMgr.GetDefaultValue("WrongPass.BanType", BanMode.Ip);
|
||||
BanMode banType = ConfigMgr.GetDefaultValue("WrongPass.BanType", BanMode.IP);
|
||||
int banTime = ConfigMgr.GetDefaultValue("WrongPass.BanTime", 600);
|
||||
|
||||
if (banType == BanMode.Account)
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_BNET_ACCOUNT_AUTO_BANNED);
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.InsBnetAccountAutoBanned);
|
||||
stmt.AddValue(0, accountId);
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_IP_AUTO_BANNED);
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.InsIpAutoBanned);
|
||||
stmt.AddValue(0, request.Host);
|
||||
}
|
||||
|
||||
stmt.AddValue(1, banTime);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_RESET_FAILED_LOGINS);
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UpdBnetResetFailedLogins);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
@@ -171,7 +152,7 @@ namespace BNetServer.Networking
|
||||
SendResponse(HttpCode.Ok, loginResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
loginResult.AuthenticationState = "LOGIN";
|
||||
loginResult.ErrorCode = "UNABLE_TO_DECODE";
|
||||
loginResult.ErrorMessage = "There was an internal error while connecting to Battle.net. Please try again later.";
|
||||
@@ -179,9 +160,9 @@ namespace BNetServer.Networking
|
||||
}
|
||||
}
|
||||
|
||||
void SendResponse<T>(HttpCode code, T response)
|
||||
async void SendResponse<T>(HttpCode code, T response)
|
||||
{
|
||||
AsyncWrite(HttpHelper.CreateResponse(code, Json.CreateString(response)));
|
||||
await AsyncWrite(HttpHelper.CreateResponse(code, Json.CreateString(response)));
|
||||
}
|
||||
|
||||
string CalculateShaPassHash(string name, string password)
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
||||
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Bgs.Protocol.Account.V1;
|
||||
using Framework.Constants;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BNetServer.Networking
|
||||
{
|
||||
public partial class Session
|
||||
{
|
||||
[Service(OriginalHash.AccountService, 30)]
|
||||
BattlenetRpcErrorCode HandleGetAccountState(GetAccountStateRequest request, GetAccountStateResponse response)
|
||||
{
|
||||
if (!authed)
|
||||
return BattlenetRpcErrorCode.Denied;
|
||||
|
||||
if (request.Options.FieldPrivacyInfo)
|
||||
{
|
||||
response.State = new AccountState();
|
||||
response.State.PrivacyInfo = new PrivacyInfo();
|
||||
response.State.PrivacyInfo.IsUsingRid = false;
|
||||
response.State.PrivacyInfo.IsVisibleForViewFriends = false;
|
||||
response.State.PrivacyInfo.IsHiddenFromFriendFinder = true;
|
||||
|
||||
response.Tags = new AccountFieldTags();
|
||||
response.Tags.PrivacyInfoTag = 0xD7CA834D;
|
||||
}
|
||||
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
[Service(OriginalHash.AccountService, 31)]
|
||||
BattlenetRpcErrorCode HandleGetGameAccountState(GetGameAccountStateRequest request, GetGameAccountStateResponse response)
|
||||
{
|
||||
if (!authed)
|
||||
return BattlenetRpcErrorCode.Denied;
|
||||
|
||||
if (request.Options.FieldGameLevelInfo)
|
||||
{
|
||||
var gameAccountInfo = accountInfo.GameAccounts.LookupByKey(request.GameAccountId.Low);
|
||||
if (gameAccountInfo != null)
|
||||
{
|
||||
response.State = new GameAccountState();
|
||||
response.State.GameLevelInfo = new GameLevelInfo();
|
||||
response.State.GameLevelInfo.Name = gameAccountInfo.DisplayName;
|
||||
response.State.GameLevelInfo.Program = 5730135; // WoW
|
||||
}
|
||||
|
||||
response.Tags = new GameAccountFieldTags();
|
||||
response.Tags.GameLevelInfoTag = 0x5C46D483;
|
||||
}
|
||||
|
||||
if (request.Options.FieldGameStatus)
|
||||
{
|
||||
if (response.State == null)
|
||||
response.State = new GameAccountState();
|
||||
|
||||
response.State.GameStatus = new GameStatus();
|
||||
|
||||
var gameAccountInfo = accountInfo.GameAccounts.LookupByKey(request.GameAccountId.Low);
|
||||
if (gameAccountInfo != null)
|
||||
{
|
||||
response.State.GameStatus.IsSuspended = gameAccountInfo.IsBanned;
|
||||
response.State.GameStatus.IsBanned = gameAccountInfo.IsPermanenetlyBanned;
|
||||
response.State.GameStatus.SuspensionExpires = (gameAccountInfo.UnbanDate * 1000000);
|
||||
}
|
||||
|
||||
response.State.GameStatus.Program = 5730135; // WoW
|
||||
response.Tags.GameStatusTag = 0x98B75F99;
|
||||
}
|
||||
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
||||
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Bgs.Protocol;
|
||||
using Bgs.Protocol.Authentication.V1;
|
||||
using Bgs.Protocol.Challenge.V1;
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Google.Protobuf;
|
||||
using System;
|
||||
using Framework.Realm;
|
||||
using System.Net;
|
||||
|
||||
namespace BNetServer.Networking
|
||||
{
|
||||
public partial class Session
|
||||
{
|
||||
[Service(OriginalHash.AuthenticationService, 1)]
|
||||
BattlenetRpcErrorCode HandleLogon(LogonRequest logonRequest, NoData response)
|
||||
{
|
||||
if (logonRequest.Program != "WoW")
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, $"Battlenet.LogonRequest: {GetClientInfo()} attempted to log in with game other than WoW (using {logonRequest.Program})!");
|
||||
return BattlenetRpcErrorCode.BadProgram;
|
||||
}
|
||||
|
||||
if (logonRequest.Platform != "Win" && logonRequest.Platform != "Wn64" && logonRequest.Platform != "Mc64")
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, $"Battlenet.LogonRequest: {GetClientInfo()} attempted to log in from an unsupported platform (using {logonRequest.Platform})!");
|
||||
return BattlenetRpcErrorCode.BadPlatform;
|
||||
}
|
||||
|
||||
if (logonRequest.Locale.ToEnum<Locale>() == Locale.enUS && logonRequest.Locale != "enUS")
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, $"Battlenet.LogonRequest: {GetClientInfo()} attempted to log in with unsupported locale (using {logonRequest.Locale})!");
|
||||
return BattlenetRpcErrorCode.BadLocale;
|
||||
}
|
||||
|
||||
locale = logonRequest.Locale;
|
||||
os = logonRequest.Platform;
|
||||
build = (uint)logonRequest.ApplicationVersion;
|
||||
|
||||
var endpoint = Global.LoginServiceMgr.GetAddressForClient(GetRemoteIpEndPoint().Address);
|
||||
|
||||
ChallengeExternalRequest externalChallenge = new ChallengeExternalRequest();
|
||||
externalChallenge.PayloadType = "web_auth_url";
|
||||
externalChallenge.Payload = ByteString.CopyFromUtf8($"https://{endpoint.Address}:{endpoint.Port}/bnetserver/login/");
|
||||
|
||||
SendRequest((uint)OriginalHash.ChallengeListener, 3, externalChallenge);
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
[Service(OriginalHash.AuthenticationService, 7)]
|
||||
BattlenetRpcErrorCode HandleVerifyWebCredentials(VerifyWebCredentialsRequest verifyWebCredentialsRequest)
|
||||
{
|
||||
if (verifyWebCredentialsRequest.WebCredentials.IsEmpty)
|
||||
return BattlenetRpcErrorCode.Denied;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SelBnetAccountInfo);
|
||||
stmt.AddValue(0, verifyWebCredentialsRequest.WebCredentials.ToStringUtf8());
|
||||
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (result.IsEmpty())
|
||||
return BattlenetRpcErrorCode.Denied;
|
||||
|
||||
accountInfo = new AccountInfo(result);
|
||||
|
||||
if (accountInfo.LoginTicketExpiry < Time.UnixTime)
|
||||
return BattlenetRpcErrorCode.TimedOut;
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.SelBnetCharacterCountsByAccountId);
|
||||
stmt.AddValue(0, accountInfo.Id);
|
||||
|
||||
SQLResult characterCountsResult = DB.Login.Query(stmt);
|
||||
if (!characterCountsResult.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
var realmId = new RealmId(characterCountsResult.Read<byte>(3), characterCountsResult.Read<byte>(4), characterCountsResult.Read<uint>(2));
|
||||
accountInfo.GameAccounts[characterCountsResult.Read<uint>(0)].CharacterCounts[realmId.GetAddress()] = characterCountsResult.Read<byte>(1);
|
||||
|
||||
} while (characterCountsResult.NextRow());
|
||||
}
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.SelBnetLastPlayerCharacters);
|
||||
stmt.AddValue(0, accountInfo.Id);
|
||||
|
||||
SQLResult lastPlayerCharactersResult = DB.Login.Query(stmt);
|
||||
if (!lastPlayerCharactersResult.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
var realmId = new RealmId(lastPlayerCharactersResult.Read<byte>(1), lastPlayerCharactersResult.Read<byte>(2), lastPlayerCharactersResult.Read<uint>(3));
|
||||
|
||||
LastPlayedCharacterInfo lastPlayedCharacter = new LastPlayedCharacterInfo();
|
||||
lastPlayedCharacter.RealmId = realmId;
|
||||
lastPlayedCharacter.CharacterName = lastPlayerCharactersResult.Read<string>(4);
|
||||
lastPlayedCharacter.CharacterGUID = lastPlayerCharactersResult.Read<ulong>(5);
|
||||
lastPlayedCharacter.LastPlayedTime = lastPlayerCharactersResult.Read<uint>(6);
|
||||
|
||||
accountInfo.GameAccounts[lastPlayerCharactersResult.Read<uint>(0)].LastPlayedCharacters[realmId.GetSubRegionAddress()] = lastPlayedCharacter;
|
||||
|
||||
} while (lastPlayerCharactersResult.NextRow());
|
||||
}
|
||||
|
||||
string ip_address = GetRemoteIpEndPoint().ToString();
|
||||
|
||||
// If the IP is 'locked', check that the player comes indeed from the correct IP address
|
||||
if (accountInfo.IsLockedToIP)
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, $"Session.HandleVerifyWebCredentials: Account: {accountInfo.Login} is locked to IP: {accountInfo.LastIP} is logging in from IP: {ip_address}");
|
||||
|
||||
if (accountInfo.LastIP != ip_address)
|
||||
return BattlenetRpcErrorCode.RiskAccountLocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, $"Session.HandleVerifyWebCredentials: Account: {accountInfo.Login} is not locked to ip");
|
||||
if (accountInfo.LockCountry.IsEmpty() || accountInfo.LockCountry == "00")
|
||||
Log.outDebug(LogFilter.Session, $"Session.HandleVerifyWebCredentials: Account: {accountInfo.Login} is not locked to country");
|
||||
else if (!accountInfo.LockCountry.IsEmpty() && !ipCountry.IsEmpty())
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, $"Session.HandleVerifyWebCredentials: Account: {accountInfo.Login} is locked to Country: {accountInfo.LockCountry} player Country: {ipCountry}");
|
||||
|
||||
if (ipCountry != accountInfo.LockCountry)
|
||||
return BattlenetRpcErrorCode.RiskAccountLocked;
|
||||
}
|
||||
}
|
||||
|
||||
// If the account is banned, reject the logon attempt
|
||||
if (accountInfo.IsBanned)
|
||||
{
|
||||
if (accountInfo.IsPermanenetlyBanned)
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, $"{GetClientInfo()} Session.HandleVerifyWebCredentials: Banned account {accountInfo.Login} tried to login!");
|
||||
return BattlenetRpcErrorCode.GameAccountBanned;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, $"{GetClientInfo()} Session.HandleVerifyWebCredentials: Temporarily banned account {accountInfo.Login} tried to login!");
|
||||
return BattlenetRpcErrorCode.GameAccountSuspended;
|
||||
}
|
||||
}
|
||||
|
||||
LogonResult logonResult = new LogonResult();
|
||||
logonResult.ErrorCode = 0;
|
||||
logonResult.AccountId = new EntityId();
|
||||
logonResult.AccountId.Low = accountInfo.Id;
|
||||
logonResult.AccountId.High = 0x100000000000000;
|
||||
foreach (var pair in accountInfo.GameAccounts)
|
||||
{
|
||||
EntityId gameAccountId = new EntityId();
|
||||
gameAccountId.Low = pair.Value.Id;
|
||||
gameAccountId.High = 0x200000200576F57;
|
||||
logonResult.GameAccountId.Add(gameAccountId);
|
||||
}
|
||||
|
||||
if (!ipCountry.IsEmpty())
|
||||
logonResult.GeoipCountry = ipCountry;
|
||||
|
||||
logonResult.SessionKey = ByteString.CopyFrom(new byte[64].GenerateRandomKey(64));
|
||||
|
||||
authed = true;
|
||||
|
||||
SendRequest((uint)OriginalHash.AuthenticationListener, 5, logonResult);
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
||||
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Bgs.Protocol.Connection.V1;
|
||||
using Framework.Constants;
|
||||
using System.Collections.Generic;
|
||||
using Google.Protobuf;
|
||||
using Bgs.Protocol;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BNetServer.Networking
|
||||
{
|
||||
public partial class Session
|
||||
{
|
||||
[Service(OriginalHash.ConnectionService, 1)]
|
||||
BattlenetRpcErrorCode HandleConnect(ConnectRequest request, ConnectResponse response)
|
||||
{
|
||||
if (request.ClientId != null)
|
||||
response.ClientId.MergeFrom(request.ClientId);
|
||||
|
||||
response.ServerId = new ProcessId();
|
||||
response.ServerId.Label = (uint)Process.GetCurrentProcess().Id;
|
||||
response.ServerId.Epoch = (uint)Time.UnixTime;
|
||||
response.ServerTime = (ulong)Time.UnixTimeMilliseconds;
|
||||
|
||||
response.UseBindlessRpc = request.UseBindlessRpc;
|
||||
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
[Service(OriginalHash.ConnectionService, 5)]
|
||||
BattlenetRpcErrorCode HandleKeepAlive(NoData request)
|
||||
{
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
[Service(OriginalHash.ConnectionService, 7)]
|
||||
BattlenetRpcErrorCode HandleRequestDisconnect(DisconnectRequest request)
|
||||
{
|
||||
var disconnectNotification = new DisconnectNotification();
|
||||
disconnectNotification.ErrorCode = request.ErrorCode;
|
||||
SendRequest((uint)OriginalHash.ConnectionService, 4, disconnectNotification);
|
||||
|
||||
CloseSocket();
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
||||
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Bgs.Protocol;
|
||||
using Bgs.Protocol.GameUtilities.V1;
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.Serialization;
|
||||
using Framework.Web;
|
||||
using Google.Protobuf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BNetServer.Networking
|
||||
{
|
||||
public partial class Session
|
||||
{
|
||||
[Service(OriginalHash.GameUtilitiesService, 1)]
|
||||
BattlenetRpcErrorCode HandleProcessClientRequest(ClientRequest request, ClientResponse response)
|
||||
{
|
||||
if (!authed)
|
||||
return BattlenetRpcErrorCode.Denied;
|
||||
|
||||
Bgs.Protocol.Attribute command = null;
|
||||
Dictionary<string, Variant> Params = new Dictionary<string, Variant>();
|
||||
|
||||
for (int i = 0; i < request.Attribute.Count; ++i)
|
||||
{
|
||||
Bgs.Protocol.Attribute attr = request.Attribute[i];
|
||||
Params[attr.Name] = attr.Value;
|
||||
if (attr.Name.Contains("Command_"))
|
||||
command = attr;
|
||||
}
|
||||
|
||||
if (command == null)
|
||||
{
|
||||
Log.outError(LogFilter.SessionRpc, $"{GetClientInfo()} sent ClientRequest with no command.");
|
||||
return BattlenetRpcErrorCode.RpcMalformedRequest;
|
||||
}
|
||||
|
||||
return command.Name switch
|
||||
{
|
||||
"Command_RealmListTicketRequest_v1_b9" => GetRealmListTicket(Params, response),
|
||||
"Command_LastCharPlayedRequest_v1_b9" => GetLastCharPlayed(Params, response),
|
||||
"Command_RealmListRequest_v1_b9" => GetRealmList(Params, response),
|
||||
"Command_RealmJoinRequest_v1_b9" => JoinRealm(Params, response),
|
||||
_ => BattlenetRpcErrorCode.RpcNotImplemented
|
||||
};
|
||||
}
|
||||
|
||||
[Service(OriginalHash.GameUtilitiesService, 10)]
|
||||
BattlenetRpcErrorCode HandleGetAllValuesForAttribute(GetAllValuesForAttributeRequest request, GetAllValuesForAttributeResponse response)
|
||||
{
|
||||
if (!authed)
|
||||
return BattlenetRpcErrorCode.Denied;
|
||||
|
||||
if (request.AttributeKey == "Command_RealmListRequest_v1_b9")
|
||||
{
|
||||
Global.RealmMgr.WriteSubRegions(response);
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
return BattlenetRpcErrorCode.RpcNotImplemented;
|
||||
}
|
||||
|
||||
BattlenetRpcErrorCode GetRealmListTicket(Dictionary<string, Variant> Params, ClientResponse response)
|
||||
{
|
||||
Variant identity = Params.LookupByKey("Param_Identity");
|
||||
if (identity != null)
|
||||
{
|
||||
var realmListTicketIdentity = Json.CreateObject<RealmListTicketIdentity>(identity.BlobValue.ToStringUtf8(), true);
|
||||
var gameAccount = accountInfo.GameAccounts.LookupByKey(realmListTicketIdentity.GameAccountId);
|
||||
if (gameAccount != null)
|
||||
gameAccountInfo = gameAccount;
|
||||
}
|
||||
|
||||
if (gameAccountInfo == null)
|
||||
return BattlenetRpcErrorCode.UtilServerInvalidIdentityArgs;
|
||||
|
||||
if (gameAccountInfo.IsPermanenetlyBanned)
|
||||
return BattlenetRpcErrorCode.GameAccountBanned;
|
||||
else if (gameAccountInfo.IsBanned)
|
||||
return BattlenetRpcErrorCode.GameAccountSuspended;
|
||||
|
||||
bool clientInfoOk = false;
|
||||
Variant clientInfo = Params.LookupByKey("Param_ClientInfo");
|
||||
if (clientInfo != null)
|
||||
{
|
||||
var realmListTicketClientInformation = Json.CreateObject<RealmListTicketClientInformation>(clientInfo.BlobValue.ToStringUtf8(), true);
|
||||
clientInfoOk = true;
|
||||
int i = 0;
|
||||
foreach (byte b in realmListTicketClientInformation.Info.Secret)
|
||||
clientSecret[i++] = b;
|
||||
}
|
||||
|
||||
if (!clientInfoOk)
|
||||
return BattlenetRpcErrorCode.WowServicesDeniedRealmListTicket;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UpdBnetLastLoginInfo);
|
||||
stmt.AddValue(0, GetRemoteIpEndPoint().ToString());
|
||||
stmt.AddValue(1, Enum.Parse(typeof(Locale), locale));
|
||||
stmt.AddValue(2, os);
|
||||
stmt.AddValue(3, accountInfo.Id);
|
||||
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
var attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_RealmListTicket";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.BlobValue = ByteString.CopyFrom("AuthRealmListTicket", System.Text.Encoding.UTF8);
|
||||
response.Attribute.Add(attribute);
|
||||
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
BattlenetRpcErrorCode GetLastCharPlayed(Dictionary<string, Variant> Params, ClientResponse response)
|
||||
{
|
||||
Variant subRegion = Params.LookupByKey("Command_LastCharPlayedRequest_v1_b9");
|
||||
if (subRegion != null)
|
||||
{
|
||||
var lastPlayerChar = gameAccountInfo.LastPlayedCharacters.LookupByKey(subRegion.StringValue);
|
||||
if (lastPlayerChar != null)
|
||||
{
|
||||
var compressed = Global.RealmMgr.GetRealmEntryJSON(lastPlayerChar.RealmId, build);
|
||||
if (compressed.Length == 0)
|
||||
return BattlenetRpcErrorCode.UtilServerFailedToSerializeResponse;
|
||||
|
||||
var attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_RealmEntry";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.BlobValue = ByteString.CopyFrom(compressed);
|
||||
response.Attribute.Add(attribute);
|
||||
|
||||
attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_CharacterName";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.StringValue = lastPlayerChar.CharacterName;
|
||||
response.Attribute.Add(attribute);
|
||||
|
||||
attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_CharacterGUID";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.BlobValue = ByteString.CopyFrom(BitConverter.GetBytes(lastPlayerChar.CharacterGUID));
|
||||
response.Attribute.Add(attribute);
|
||||
|
||||
attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_LastPlayedTime";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.IntValue = (int)lastPlayerChar.LastPlayedTime;
|
||||
response.Attribute.Add(attribute);
|
||||
}
|
||||
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
return BattlenetRpcErrorCode.UtilServerUnknownRealm;
|
||||
}
|
||||
|
||||
BattlenetRpcErrorCode GetRealmList(Dictionary<string, Variant> Params, ClientResponse response)
|
||||
{
|
||||
if (gameAccountInfo == null)
|
||||
return BattlenetRpcErrorCode.UserServerBadWowAccount;
|
||||
|
||||
string subRegionId = "";
|
||||
Variant subRegion = Params.LookupByKey("Command_RealmListRequest_v1_b9");
|
||||
if (subRegion != null)
|
||||
subRegionId = subRegion.StringValue;
|
||||
|
||||
var compressed = Global.RealmMgr.GetRealmList(build, subRegionId);
|
||||
if (compressed.Length == 0)
|
||||
return BattlenetRpcErrorCode.UtilServerFailedToSerializeResponse;
|
||||
|
||||
var attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_RealmList";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.BlobValue = ByteString.CopyFrom(compressed);
|
||||
response.Attribute.Add(attribute);
|
||||
|
||||
var realmCharacterCounts = new RealmCharacterCountList();
|
||||
foreach (var characterCount in gameAccountInfo.CharacterCounts)
|
||||
{
|
||||
var countEntry = new RealmCharacterCountEntry();
|
||||
countEntry.WowRealmAddress = (int)characterCount.Key;
|
||||
countEntry.Count = characterCount.Value;
|
||||
realmCharacterCounts.Counts.Add(countEntry);
|
||||
}
|
||||
|
||||
compressed = Json.Deflate("JSONRealmCharacterCountList", realmCharacterCounts);
|
||||
|
||||
attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_CharacterCountList";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.BlobValue = ByteString.CopyFrom(compressed);
|
||||
response.Attribute.Add(attribute);
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
BattlenetRpcErrorCode JoinRealm(Dictionary<string, Variant> Params, ClientResponse response)
|
||||
{
|
||||
Variant realmAddress = Params.LookupByKey("Param_RealmAddress");
|
||||
if (realmAddress != null)
|
||||
return Global.RealmMgr.JoinRealm((uint)realmAddress.UintValue, build, GetRemoteIpEndPoint().Address, clientSecret, (Locale)Enum.Parse(typeof(Locale), locale), os, gameAccountInfo.Name, response);
|
||||
|
||||
return BattlenetRpcErrorCode.WowServicesInvalidJoinTicket;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
||||
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Bgs.Protocol;
|
||||
using Bgs.Protocol.Challenge.V1;
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Framework.Networking;
|
||||
using Framework.Rest;
|
||||
using Framework.Serialization;
|
||||
using Framework.Realm;
|
||||
using Google.Protobuf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace BNetServer.Networking
|
||||
{
|
||||
public class Session : SSLSocket
|
||||
partial class Session : SSLSocket
|
||||
{
|
||||
AccountInfo accountInfo;
|
||||
GameAccountInfo gameAccountInfo;
|
||||
|
||||
string locale;
|
||||
string os;
|
||||
uint build;
|
||||
string ipCountry;
|
||||
|
||||
byte[] clientSecret;
|
||||
bool authed;
|
||||
uint requestToken;
|
||||
|
||||
AsyncCallbackProcessor<QueryCallback> queryProcessor;
|
||||
Dictionary<uint, Action<CodedInputStream>> responseCallbacks;
|
||||
|
||||
public Session(Socket socket) : base(socket)
|
||||
{
|
||||
_accountInfo = new AccountInfo();
|
||||
|
||||
ClientRequestHandlers.Add("Command_RealmListTicketRequest_v1_b9", GetRealmListTicket);
|
||||
ClientRequestHandlers.Add("Command_LastCharPlayedRequest_v1_b9", GetLastCharPlayed);
|
||||
ClientRequestHandlers.Add("Command_RealmListRequest_v1_b9", GetRealmList);
|
||||
ClientRequestHandlers.Add("Command_RealmJoinRequest_v1_b9", JoinRealm);
|
||||
clientSecret = new byte[32];
|
||||
queryProcessor = new AsyncCallbackProcessor<QueryCallback>();
|
||||
responseCallbacks = new Dictionary<uint, Action<CodedInputStream>>();
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
public override void Accept()
|
||||
{
|
||||
string ip_address = GetRemoteIpAddress().ToString();
|
||||
Log.outInfo(LogFilter.Network, "{0} Accepted connection", GetClientInfo());
|
||||
string ipAddress = GetRemoteIpEndPoint().ToString();
|
||||
Log.outInfo(LogFilter.Network, $"{GetClientInfo()} Connection Accepted.");
|
||||
|
||||
// Verify that this IP is not in the ip_banned table
|
||||
DB.Login.Execute(DB.Login.GetPreparedStatement(LoginStatements.DEL_EXPIRED_IP_BANS));
|
||||
DB.Login.Execute(DB.Login.GetPreparedStatement(LoginStatements.DelExpiredIpBans));
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_IP_INFO);
|
||||
stmt.AddValue(0, ip_address);
|
||||
stmt.AddValue(1, BitConverter.ToUInt32(GetRemoteIpAddress().GetAddressBytes(), 0));
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SelIpInfo);
|
||||
stmt.AddValue(0, ipAddress);
|
||||
stmt.AddValue(1, BitConverter.ToUInt32(GetRemoteIpEndPoint().Address.GetAddressBytes(), 0));
|
||||
|
||||
_queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(CheckIpCallback));
|
||||
}
|
||||
|
||||
void CheckIpCallback(SQLResult result)
|
||||
{
|
||||
if (!result.IsEmpty())
|
||||
queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(async result =>
|
||||
{
|
||||
bool banned = false;
|
||||
do
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
if (result.Read<ulong>(0) != 0)
|
||||
banned = true;
|
||||
bool banned = false;
|
||||
do
|
||||
{
|
||||
if (result.Read<ulong>(0) != 0)
|
||||
banned = true;
|
||||
|
||||
if (!string.IsNullOrEmpty(result.Read<string>(1)))
|
||||
_ipCountry = result.Read<string>(1);
|
||||
if (!string.IsNullOrEmpty(result.Read<string>(1)))
|
||||
ipCountry = result.Read<string>(1);
|
||||
|
||||
} while (result.NextRow());
|
||||
} while (result.NextRow());
|
||||
|
||||
if (banned)
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, "{0} tries to log in using banned IP!", GetClientInfo());
|
||||
CloseSocket();
|
||||
return;
|
||||
if (banned)
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, $"{GetClientInfo()} trying to login with banned ipaddress!");
|
||||
CloseSocket();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AsyncHandshake(Global.SessionMgr.GetCertificate());
|
||||
await AsyncHandshake(Global.LoginServiceMgr.GetCertificate());
|
||||
}));
|
||||
}
|
||||
|
||||
public override bool Update()
|
||||
@@ -89,557 +82,137 @@ namespace BNetServer.Networking
|
||||
if (!base.Update())
|
||||
return false;
|
||||
|
||||
_queryProcessor.ProcessReadyCallbacks();
|
||||
queryProcessor.ProcessReadyCallbacks();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void ReadHandler(int transferredBytes)
|
||||
public async override void ReadHandler(byte[] data, int receivedLength)
|
||||
{
|
||||
if (!IsOpen())
|
||||
return;
|
||||
|
||||
var stream = new CodedInputStream(GetReceiveBuffer(), 0, transferredBytes);
|
||||
var stream = new CodedInputStream(data);
|
||||
while (!stream.IsAtEnd)
|
||||
{
|
||||
var header = new Header();
|
||||
stream.ReadMessage(header);
|
||||
|
||||
if (header.ServiceId != 0xFE)
|
||||
if (header.ServiceId != 0xFE && header.ServiceHash != 0)
|
||||
{
|
||||
Global.ServiceDispatcher.Dispatch(this, header.ServiceHash, header.Token, header.MethodId, stream);
|
||||
var handler = Global.LoginServiceMgr.GetHandler(header.ServiceHash, header.MethodId);
|
||||
if (handler != null)
|
||||
handler.Invoke(this, header.Token, stream);
|
||||
else
|
||||
{
|
||||
Log.outError(LogFilter.ServiceProtobuf, $"{GetClientInfo()} tried to call not implemented methodId: {header.MethodId} for servicehash: {header.ServiceHash}");
|
||||
SendResponse(header.Token, BattlenetRpcErrorCode.RpcNotImplemented);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var handler = _responseCallbacks.LookupByKey(header.Token);
|
||||
var handler = responseCallbacks.LookupByKey(header.Token);
|
||||
if (handler != null)
|
||||
{
|
||||
handler(stream);
|
||||
_responseCallbacks.Remove(header.Token);
|
||||
responseCallbacks.Remove(header.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AsyncRead();
|
||||
await AsyncRead();
|
||||
}
|
||||
|
||||
void AsyncWrite(ByteBuffer packet)
|
||||
{
|
||||
if (!IsOpen())
|
||||
return;
|
||||
|
||||
AsyncWrite(packet.GetData());
|
||||
}
|
||||
|
||||
public void SendResponse(uint token, IMessage response)
|
||||
public async void SendResponse(uint token, IMessage response)
|
||||
{
|
||||
Header header = new Header();
|
||||
header.Token = token;
|
||||
header.ServiceId = 0xFE;
|
||||
header.Size = (uint)response.CalculateSize();
|
||||
|
||||
var headerSizeBytes = BitConverter.GetBytes((ushort)header.CalculateSize());
|
||||
Array.Reverse(headerSizeBytes);
|
||||
ByteBuffer buffer = new ByteBuffer();
|
||||
buffer.WriteBytes(GetHeaderSize(header), 2);
|
||||
buffer.WriteBytes(header.ToByteArray());
|
||||
buffer.WriteBytes(response.ToByteArray());
|
||||
|
||||
ByteBuffer packet = new ByteBuffer();
|
||||
packet.WriteBytes(headerSizeBytes, 2);
|
||||
packet.WriteBytes(header.ToByteArray());
|
||||
packet.WriteBytes(response.ToByteArray());
|
||||
|
||||
AsyncWrite(packet.GetData());
|
||||
await AsyncWrite(buffer.GetData());
|
||||
}
|
||||
|
||||
public void SendResponse(uint token, BattlenetRpcErrorCode status)
|
||||
public async void SendResponse(uint token, BattlenetRpcErrorCode status)
|
||||
{
|
||||
Header header = new Header();
|
||||
header.Token = token;
|
||||
header.Status = (uint)status;
|
||||
header.ServiceId = 0xFE;
|
||||
|
||||
var headerSizeBytes = BitConverter.GetBytes((ushort)header.CalculateSize());
|
||||
Array.Reverse(headerSizeBytes);
|
||||
ByteBuffer buffer = new ByteBuffer();
|
||||
buffer.WriteBytes(GetHeaderSize(header), 2);
|
||||
buffer.WriteBytes(header.ToByteArray());
|
||||
|
||||
ByteBuffer packet = new ByteBuffer();
|
||||
packet.WriteBytes(headerSizeBytes, 2);
|
||||
packet.WriteBytes(header.ToByteArray());
|
||||
|
||||
AsyncWrite(packet);
|
||||
await AsyncWrite(buffer.GetData());
|
||||
}
|
||||
|
||||
public void SendRequest(uint serviceHash, uint methodId, IMessage request, Action<CodedInputStream> callback)
|
||||
{
|
||||
_responseCallbacks[_requestToken] = callback;
|
||||
SendRequest(serviceHash, methodId, request);
|
||||
}
|
||||
|
||||
public void SendRequest(uint serviceHash, uint methodId, IMessage request)
|
||||
public async void SendRequest(uint serviceHash, uint methodId, IMessage request)
|
||||
{
|
||||
Header header = new Header();
|
||||
header.ServiceId = 0;
|
||||
header.ServiceHash = serviceHash;
|
||||
header.MethodId = methodId;
|
||||
header.Size = (uint)request.CalculateSize();
|
||||
header.Token = _requestToken++;
|
||||
header.Token = requestToken++;
|
||||
|
||||
ByteBuffer buffer = new ByteBuffer();
|
||||
buffer.WriteBytes(GetHeaderSize(header), 2);
|
||||
buffer.WriteBytes(header.ToByteArray());
|
||||
buffer.WriteBytes(request.ToByteArray());
|
||||
|
||||
await AsyncWrite(buffer.GetData());
|
||||
}
|
||||
|
||||
public byte[] GetHeaderSize(Header header)
|
||||
{
|
||||
var size = (ushort)header.CalculateSize();
|
||||
byte[] bytes = new byte[2];
|
||||
bytes[0] = (byte)((size >> 8) & 0xff);
|
||||
bytes[1] = (byte)(size & 0xff);
|
||||
|
||||
var headerSizeBytes = BitConverter.GetBytes((ushort)header.CalculateSize());
|
||||
Array.Reverse(headerSizeBytes);
|
||||
|
||||
ByteBuffer packet = new ByteBuffer();
|
||||
packet.WriteBytes(headerSizeBytes, 2);
|
||||
packet.WriteBytes(header.ToByteArray());
|
||||
packet.WriteBytes(request.ToByteArray());
|
||||
|
||||
AsyncWrite(packet);
|
||||
}
|
||||
|
||||
public BattlenetRpcErrorCode HandleLogon(Bgs.Protocol.Authentication.V1.LogonRequest logonRequest)
|
||||
{
|
||||
if (logonRequest.Program != "WoW")
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, "Battlenet.LogonRequest: {0} attempted to log in with game other than WoW (using {1})!", GetClientInfo(), logonRequest.Program);
|
||||
return BattlenetRpcErrorCode.BadProgram;
|
||||
}
|
||||
|
||||
if (logonRequest.Platform != "Win" && logonRequest.Platform != "Wn64" && logonRequest.Platform != "Mc64")
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, "Battlenet.LogonRequest: {0} attempted to log in from an unsupported platform (using {1})!", GetClientInfo(), logonRequest.Platform);
|
||||
return BattlenetRpcErrorCode.BadPlatform;
|
||||
}
|
||||
|
||||
if (logonRequest.Locale.ToEnum<LocaleConstant>() == LocaleConstant.enUS && logonRequest.Locale != "enUS")
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, "Battlenet.LogonRequest: {0} attempted to log in with unsupported locale (using {1})!", GetClientInfo(), logonRequest.Locale);
|
||||
return BattlenetRpcErrorCode.BadLocale;
|
||||
}
|
||||
|
||||
_locale = logonRequest.Locale;
|
||||
_os = logonRequest.Platform;
|
||||
_build = (uint)logonRequest.ApplicationVersion;
|
||||
|
||||
var endpoint = Global.SessionMgr.GetAddressForClient(GetRemoteIpAddress());
|
||||
|
||||
ChallengeExternalRequest externalChallenge = new ChallengeExternalRequest();
|
||||
externalChallenge.PayloadType = "web_auth_url";
|
||||
|
||||
externalChallenge.Payload = ByteString.CopyFromUtf8(string.Format("https://{0}:{1}/bnetserver/login/", endpoint.Address, endpoint.Port));
|
||||
SendRequest((uint)OriginalHash.ChallengeListener, 3, externalChallenge);
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
public BattlenetRpcErrorCode HandleVerifyWebCredentials(Bgs.Protocol.Authentication.V1.VerifyWebCredentialsRequest verifyWebCredentialsRequest)
|
||||
{
|
||||
if (verifyWebCredentialsRequest.WebCredentials.IsEmpty)
|
||||
return BattlenetRpcErrorCode.Denied;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_ACCOUNT_INFO);
|
||||
stmt.AddValue(0, verifyWebCredentialsRequest.WebCredentials.ToStringUtf8());
|
||||
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (result.IsEmpty())
|
||||
return BattlenetRpcErrorCode.Denied;
|
||||
|
||||
_accountInfo = new AccountInfo();
|
||||
_accountInfo.LoadResult(result);
|
||||
|
||||
if (_accountInfo.LoginTicketExpiry < Time.UnixTime)
|
||||
return BattlenetRpcErrorCode.TimedOut;
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_CHARACTER_COUNTS_BY_BNET_ID);
|
||||
stmt.AddValue(0, _accountInfo.Id);
|
||||
|
||||
SQLResult characterCountsResult = DB.Login.Query(stmt);
|
||||
if (!characterCountsResult.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
RealmHandle realmId = new RealmHandle(characterCountsResult.Read<byte>(3), characterCountsResult.Read<byte>(4), characterCountsResult.Read<uint>(2));
|
||||
_accountInfo.GameAccounts[characterCountsResult.Read<uint>(0)].CharacterCounts[realmId.GetAddress()] = characterCountsResult.Read<byte>(1);
|
||||
|
||||
} while (characterCountsResult.NextRow());
|
||||
}
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_LAST_PLAYER_CHARACTERS);
|
||||
stmt.AddValue(0, _accountInfo.Id);
|
||||
|
||||
SQLResult lastPlayerCharactersResult = DB.Login.Query(stmt);
|
||||
if (!lastPlayerCharactersResult.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
RealmHandle realmId = new RealmHandle(lastPlayerCharactersResult.Read<byte>(1), lastPlayerCharactersResult.Read<byte>(2), lastPlayerCharactersResult.Read<uint>(3));
|
||||
|
||||
LastPlayedCharacterInfo lastPlayedCharacter = new LastPlayedCharacterInfo();
|
||||
lastPlayedCharacter.RealmId = realmId;
|
||||
lastPlayedCharacter.CharacterName = lastPlayerCharactersResult.Read<string>(4);
|
||||
lastPlayedCharacter.CharacterGUID = lastPlayerCharactersResult.Read<ulong>(5);
|
||||
lastPlayedCharacter.LastPlayedTime = lastPlayerCharactersResult.Read<uint>(6);
|
||||
|
||||
_accountInfo.GameAccounts[lastPlayerCharactersResult.Read<uint>(0)].LastPlayedCharacters[realmId.GetSubRegionAddress()] = lastPlayedCharacter;
|
||||
|
||||
} while (lastPlayerCharactersResult.NextRow());
|
||||
}
|
||||
|
||||
string ip_address = GetRemoteIpAddress().ToString();
|
||||
|
||||
// If the IP is 'locked', check that the player comes indeed from the correct IP address
|
||||
if (_accountInfo.IsLockedToIP)
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, "Session.HandleVerifyWebCredentials: Account '{0}' is locked to IP - '{1}' is logging in from '{2}'",
|
||||
_accountInfo.Login, _accountInfo.LastIP, ip_address);
|
||||
|
||||
if (_accountInfo.LastIP != ip_address)
|
||||
return BattlenetRpcErrorCode.RiskAccountLocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, "Session.HandleVerifyWebCredentials: Account '{0}' is not locked to ip", _accountInfo.Login);
|
||||
if (_accountInfo.LockCountry.IsEmpty() || _accountInfo.LockCountry == "00")
|
||||
Log.outDebug(LogFilter.Session, "Session.HandleVerifyWebCredentials: Account '{0}' is not locked to country", _accountInfo.Login);
|
||||
else if (!_accountInfo.LockCountry.IsEmpty() && !_ipCountry.IsEmpty())
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, "Session.HandleVerifyWebCredentials: Account '{0}' is locked to country: '{1}' Player country is '{2}'",
|
||||
_accountInfo.Login, _accountInfo.LockCountry, _ipCountry);
|
||||
|
||||
if (_ipCountry != _accountInfo.LockCountry)
|
||||
return BattlenetRpcErrorCode.RiskAccountLocked;
|
||||
}
|
||||
}
|
||||
|
||||
// If the account is banned, reject the logon attempt
|
||||
if (_accountInfo.IsBanned)
|
||||
{
|
||||
if (_accountInfo.IsPermanenetlyBanned)
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, "{0} Session.HandleVerifyWebCredentials: Banned account {1} tried to login!", GetClientInfo(), _accountInfo.Login);
|
||||
return BattlenetRpcErrorCode.GameAccountBanned;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outDebug(LogFilter.Session, "{0} Session.HandleVerifyWebCredentials: Temporarily banned account {1} tried to login!", GetClientInfo(), _accountInfo.Login);
|
||||
return BattlenetRpcErrorCode.GameAccountSuspended;
|
||||
}
|
||||
}
|
||||
|
||||
Bgs.Protocol.Authentication.V1.LogonResult logonResult = new Bgs.Protocol.Authentication.V1.LogonResult();
|
||||
logonResult.ErrorCode = 0;
|
||||
logonResult.AccountId = new EntityId();
|
||||
logonResult.AccountId.Low = _accountInfo.Id;
|
||||
logonResult.AccountId.High = 0x100000000000000;
|
||||
foreach (var pair in _accountInfo.GameAccounts)
|
||||
{
|
||||
EntityId gameAccountId = new EntityId();
|
||||
gameAccountId.Low = pair.Value.Id;
|
||||
gameAccountId.High = 0x200000200576F57;
|
||||
logonResult.GameAccountId.Add(gameAccountId);
|
||||
}
|
||||
|
||||
if (!_ipCountry.IsEmpty())
|
||||
logonResult.GeoipCountry = _ipCountry;
|
||||
|
||||
logonResult.SessionKey = ByteString.CopyFrom(new byte[64].GenerateRandomKey(64));
|
||||
|
||||
_authed = true;
|
||||
|
||||
SendRequest((uint)OriginalHash.AuthenticationListener, 5, logonResult);
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
public BattlenetRpcErrorCode HandleGetAccountState(Bgs.Protocol.Account.V1.GetAccountStateRequest request, Bgs.Protocol.Account.V1.GetAccountStateResponse response)
|
||||
{
|
||||
if (!_authed)
|
||||
return BattlenetRpcErrorCode.Denied;
|
||||
|
||||
if (request.Options.FieldPrivacyInfo)
|
||||
{
|
||||
response.State = new Bgs.Protocol.Account.V1.AccountState();
|
||||
response.State.PrivacyInfo = new Bgs.Protocol.Account.V1.PrivacyInfo();
|
||||
response.State.PrivacyInfo.IsUsingRid = false;
|
||||
response.State.PrivacyInfo.IsVisibleForViewFriends = false;
|
||||
response.State.PrivacyInfo.IsHiddenFromFriendFinder = true;
|
||||
|
||||
response.Tags = new Bgs.Protocol.Account.V1.AccountFieldTags();
|
||||
response.Tags.PrivacyInfoTag = 0xD7CA834D;
|
||||
}
|
||||
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
public BattlenetRpcErrorCode HandleGetGameAccountState(Bgs.Protocol.Account.V1.GetGameAccountStateRequest request, Bgs.Protocol.Account.V1.GetGameAccountStateResponse response)
|
||||
{
|
||||
if (!_authed)
|
||||
return BattlenetRpcErrorCode.Denied;
|
||||
|
||||
if (request.Options.FieldGameLevelInfo)
|
||||
{
|
||||
var gameAccountInfo = _accountInfo.GameAccounts.LookupByKey(request.GameAccountId.Low);
|
||||
if (gameAccountInfo != null)
|
||||
{
|
||||
response.State = new Bgs.Protocol.Account.V1.GameAccountState();
|
||||
response.State.GameLevelInfo = new Bgs.Protocol.Account.V1.GameLevelInfo();
|
||||
response.State.GameLevelInfo.Name = gameAccountInfo.DisplayName;
|
||||
response.State.GameLevelInfo.Program = 5730135; // WoW
|
||||
}
|
||||
|
||||
response.Tags = new Bgs.Protocol.Account.V1.GameAccountFieldTags();
|
||||
response.Tags.GameLevelInfoTag = 0x5C46D483;
|
||||
}
|
||||
|
||||
if (request.Options.FieldGameStatus)
|
||||
{
|
||||
if (response.State == null)
|
||||
response.State = new Bgs.Protocol.Account.V1.GameAccountState();
|
||||
|
||||
response.State.GameStatus = new Bgs.Protocol.Account.V1.GameStatus();
|
||||
|
||||
var gameAccountInfo = _accountInfo.GameAccounts.LookupByKey(request.GameAccountId.Low);
|
||||
if (gameAccountInfo != null)
|
||||
{
|
||||
response.State.GameStatus.IsSuspended = gameAccountInfo.IsBanned;
|
||||
response.State.GameStatus.IsBanned = gameAccountInfo.IsPermanenetlyBanned;
|
||||
response.State.GameStatus.SuspensionExpires = (gameAccountInfo.UnbanDate * 1000000);
|
||||
}
|
||||
|
||||
response.State.GameStatus.Program = 5730135; // WoW
|
||||
response.Tags.GameStatusTag = 0x98B75F99;
|
||||
}
|
||||
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
public BattlenetRpcErrorCode HandleProcessClientRequest(Bgs.Protocol.GameUtilities.V1.ClientRequest request, Bgs.Protocol.GameUtilities.V1.ClientResponse response)
|
||||
{
|
||||
if (!_authed)
|
||||
return BattlenetRpcErrorCode.Denied;
|
||||
|
||||
Bgs.Protocol.Attribute command = null;
|
||||
Dictionary<string, Variant> Params = new Dictionary<string, Variant>();
|
||||
|
||||
for (int i = 0; i < request.Attribute.Count; ++i)
|
||||
{
|
||||
Bgs.Protocol.Attribute attr = request.Attribute[i];
|
||||
Params[attr.Name] = attr.Value;
|
||||
if (attr.Name.Contains("Command_"))
|
||||
command = attr;
|
||||
}
|
||||
|
||||
if (command == null)
|
||||
{
|
||||
Log.outError(LogFilter.SessionRpc, "{0} sent ClientRequest with no command.", GetClientInfo());
|
||||
return BattlenetRpcErrorCode.RpcMalformedRequest;
|
||||
}
|
||||
|
||||
var handler = ClientRequestHandlers.LookupByKey(command.Name);
|
||||
if (handler == null)
|
||||
{
|
||||
Log.outError(LogFilter.SessionRpc, "{0} sent ClientRequest with unknown command {1}.", GetClientInfo(), command.Name);
|
||||
return BattlenetRpcErrorCode.RpcNotImplemented;
|
||||
}
|
||||
|
||||
return handler(Params, response);
|
||||
}
|
||||
|
||||
Variant GetParam(Dictionary<string, Variant> Params, string paramName)
|
||||
{
|
||||
return Params.LookupByKey(paramName);
|
||||
}
|
||||
|
||||
delegate BattlenetRpcErrorCode ClientRequestHandler(Dictionary<string, Variant> Params, Bgs.Protocol.GameUtilities.V1.ClientResponse response);
|
||||
BattlenetRpcErrorCode GetRealmListTicket(Dictionary<string, Variant> Params, Bgs.Protocol.GameUtilities.V1.ClientResponse response)
|
||||
{
|
||||
Variant identity = GetParam(Params, "Param_Identity");
|
||||
if (identity != null)
|
||||
{
|
||||
var realmListTicketIdentity = Json.CreateObject<RealmListTicketIdentity>(identity.BlobValue.ToStringUtf8(), true);
|
||||
var gameAccountInfo = _accountInfo.GameAccounts.LookupByKey(realmListTicketIdentity.GameAccountId);
|
||||
if (gameAccountInfo != null)
|
||||
_gameAccountInfo = gameAccountInfo;
|
||||
}
|
||||
|
||||
if (_gameAccountInfo == null)
|
||||
return BattlenetRpcErrorCode.UtilServerInvalidIdentityArgs;
|
||||
|
||||
if (_gameAccountInfo.IsPermanenetlyBanned)
|
||||
return BattlenetRpcErrorCode.GameAccountBanned;
|
||||
else if (_gameAccountInfo.IsBanned)
|
||||
return BattlenetRpcErrorCode.GameAccountSuspended;
|
||||
|
||||
bool clientInfoOk = false;
|
||||
Variant clientInfo = GetParam(Params, "Param_ClientInfo");
|
||||
if (clientInfo != null)
|
||||
{
|
||||
var realmListTicketClientInformation = Json.CreateObject<RealmListTicketClientInformation>(clientInfo.BlobValue.ToStringUtf8(), true);
|
||||
clientInfoOk = true;
|
||||
int i = 0;
|
||||
foreach (var b in realmListTicketClientInformation.Info.Secret.Select(Convert.ToByte))
|
||||
_clientSecret[i++] = b;
|
||||
}
|
||||
|
||||
if (!clientInfoOk)
|
||||
return BattlenetRpcErrorCode.WowServicesDeniedRealmListTicket;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_LAST_LOGIN_INFO);
|
||||
stmt.AddValue(0, GetRemoteIpAddress().ToString());
|
||||
stmt.AddValue(1, Enum.Parse(typeof(LocaleConstant), _locale));
|
||||
stmt.AddValue(2, _os);
|
||||
stmt.AddValue(3, _accountInfo.Id);
|
||||
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
var attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_RealmListTicket";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.BlobValue = ByteString.CopyFrom("AuthRealmListTicket", System.Text.Encoding.UTF8);
|
||||
response.Attribute.Add(attribute);
|
||||
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
BattlenetRpcErrorCode GetLastCharPlayed(Dictionary<string, Variant> Params, Bgs.Protocol.GameUtilities.V1.ClientResponse response)
|
||||
{
|
||||
Variant subRegion = GetParam(Params, "Command_LastCharPlayedRequest_v1_b9");
|
||||
if (subRegion != null)
|
||||
{
|
||||
var lastPlayerChar = _gameAccountInfo.LastPlayedCharacters.LookupByKey(subRegion.StringValue);
|
||||
if (lastPlayerChar != null)
|
||||
{
|
||||
var compressed = Global.RealmMgr.GetRealmEntryJSON(lastPlayerChar.RealmId, _build);
|
||||
if (compressed.Length == 0)
|
||||
return BattlenetRpcErrorCode.UtilServerFailedToSerializeResponse;
|
||||
|
||||
var attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_RealmEntry";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.BlobValue = ByteString.CopyFrom(compressed);
|
||||
response.Attribute.Add(attribute);
|
||||
|
||||
attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_CharacterName";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.StringValue = lastPlayerChar.CharacterName;
|
||||
response.Attribute.Add(attribute);
|
||||
|
||||
attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_CharacterGUID";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.BlobValue = ByteString.CopyFrom(BitConverter.GetBytes(lastPlayerChar.CharacterGUID));
|
||||
response.Attribute.Add(attribute);
|
||||
|
||||
attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_LastPlayedTime";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.IntValue = (int)lastPlayerChar.LastPlayedTime;
|
||||
response.Attribute.Add(attribute);
|
||||
}
|
||||
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
return BattlenetRpcErrorCode.UtilServerUnknownRealm;
|
||||
}
|
||||
|
||||
BattlenetRpcErrorCode GetRealmList(Dictionary<string, Variant> Params, Bgs.Protocol.GameUtilities.V1.ClientResponse response)
|
||||
{
|
||||
if (_gameAccountInfo == null)
|
||||
return BattlenetRpcErrorCode.UserServerBadWowAccount;
|
||||
|
||||
string subRegionId = "";
|
||||
Variant subRegion = GetParam(Params, "Command_RealmListRequest_v1_b9");
|
||||
if (subRegion != null)
|
||||
subRegionId = subRegion.StringValue;
|
||||
|
||||
var compressed = Global.RealmMgr.GetRealmList(_build, subRegionId);
|
||||
if (compressed.Length == 0)
|
||||
return BattlenetRpcErrorCode.UtilServerFailedToSerializeResponse;
|
||||
|
||||
var attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_RealmList";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.BlobValue = ByteString.CopyFrom(compressed);
|
||||
response.Attribute.Add(attribute);
|
||||
|
||||
var realmCharacterCounts = new RealmCharacterCountList();
|
||||
foreach (var characterCount in _gameAccountInfo.CharacterCounts)
|
||||
{
|
||||
var countEntry = new RealmCharacterCountEntry();
|
||||
countEntry.WowRealmAddress = (int)characterCount.Key;
|
||||
countEntry.Count = characterCount.Value;
|
||||
realmCharacterCounts.Counts.Add(countEntry);
|
||||
}
|
||||
|
||||
compressed = Json.Deflate("JSONRealmCharacterCountList", realmCharacterCounts);
|
||||
|
||||
attribute = new Bgs.Protocol.Attribute();
|
||||
attribute.Name = "Param_CharacterCountList";
|
||||
attribute.Value = new Variant();
|
||||
attribute.Value.BlobValue = ByteString.CopyFrom(compressed);
|
||||
response.Attribute.Add(attribute);
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
BattlenetRpcErrorCode JoinRealm(Dictionary<string, Variant> Params, Bgs.Protocol.GameUtilities.V1.ClientResponse response)
|
||||
{
|
||||
Variant realmAddress = GetParam(Params, "Param_RealmAddress");
|
||||
if (realmAddress != null)
|
||||
return Global.RealmMgr.JoinRealm((uint)realmAddress.UintValue, _build, GetRemoteIpAddress(), _clientSecret, (LocaleConstant)Enum.Parse(typeof(LocaleConstant), _locale), _os, _gameAccountInfo.Name, response);
|
||||
|
||||
return BattlenetRpcErrorCode.WowServicesInvalidJoinTicket;
|
||||
}
|
||||
|
||||
public BattlenetRpcErrorCode HandleGetAllValuesForAttribute(Bgs.Protocol.GameUtilities.V1.GetAllValuesForAttributeRequest request, Bgs.Protocol.GameUtilities.V1.GetAllValuesForAttributeResponse response)
|
||||
{
|
||||
if (!_authed)
|
||||
return BattlenetRpcErrorCode.Denied;
|
||||
|
||||
if (request.AttributeKey == "Command_RealmListRequest_v1_b9")
|
||||
{
|
||||
Global.RealmMgr.WriteSubRegions(response);
|
||||
return BattlenetRpcErrorCode.Ok;
|
||||
}
|
||||
|
||||
return BattlenetRpcErrorCode.RpcNotImplemented;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public string GetClientInfo()
|
||||
{
|
||||
string stream = '[' + GetRemoteIpAddress().ToString() + ':' + GetRemotePort();
|
||||
if (_accountInfo != null && !string.IsNullOrEmpty(_accountInfo.Login))
|
||||
stream += ", Account: " + _accountInfo.Login;
|
||||
string stream = '[' + GetRemoteIpEndPoint().ToString();
|
||||
if (accountInfo != null && !accountInfo.Login.IsEmpty())
|
||||
stream += ", Account: " + accountInfo.Login;
|
||||
|
||||
if (_gameAccountInfo != null)
|
||||
stream += ", Game account: " + _gameAccountInfo.Name;
|
||||
if (gameAccountInfo != null)
|
||||
stream += ", Game account: " + gameAccountInfo.Name;
|
||||
|
||||
stream += ']';
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
public uint GetAccountId() { return _accountInfo.Id; }
|
||||
public uint GetGameAccountId() { return _gameAccountInfo.Id; }
|
||||
|
||||
Dictionary<string, ClientRequestHandler> ClientRequestHandlers = new Dictionary<string, ClientRequestHandler>();
|
||||
|
||||
AccountInfo _accountInfo;
|
||||
GameAccountInfo _gameAccountInfo; // Points at selected game account (inside _gameAccounts)
|
||||
|
||||
string _locale;
|
||||
string _os;
|
||||
uint _build;
|
||||
|
||||
string _ipCountry;
|
||||
|
||||
Array<byte> _clientSecret = new Array<byte>(32);
|
||||
|
||||
bool _authed;
|
||||
|
||||
AsyncCallbackProcessor<QueryCallback> _queryProcessor = new AsyncCallbackProcessor<QueryCallback>();
|
||||
|
||||
Dictionary<uint, Action<CodedInputStream>> _responseCallbacks = new Dictionary<uint, Action<CodedInputStream>>();
|
||||
uint _requestToken;
|
||||
}
|
||||
|
||||
public class AccountInfo
|
||||
{
|
||||
public void LoadResult(SQLResult result)
|
||||
{
|
||||
public uint Id;
|
||||
public string Login;
|
||||
public bool IsLockedToIP;
|
||||
public string LockCountry;
|
||||
public string LastIP;
|
||||
public uint LoginTicketExpiry;
|
||||
public bool IsBanned;
|
||||
public bool IsPermanenetlyBanned;
|
||||
public string PasswordVerifier;
|
||||
public string Salt;
|
||||
|
||||
public Dictionary<uint, GameAccountInfo> GameAccounts;
|
||||
|
||||
public AccountInfo(SQLResult result)
|
||||
{
|
||||
Id = result.Read<uint>(0);
|
||||
Login = result.Read<string>(1);
|
||||
@@ -652,34 +225,31 @@ namespace BNetServer.Networking
|
||||
PasswordVerifier = result.Read<string>(9);
|
||||
Salt = result.Read<string>(10);
|
||||
|
||||
GameAccounts = new Dictionary<uint, GameAccountInfo>();
|
||||
const int GameAccountFieldsOffset = 8;
|
||||
do
|
||||
{
|
||||
var account = new GameAccountInfo();
|
||||
account.LoadResult(result.GetFields(), GameAccountFieldsOffset);
|
||||
var account = new GameAccountInfo(result.GetFields(), GameAccountFieldsOffset);
|
||||
GameAccounts[result.Read<uint>(GameAccountFieldsOffset)] = account;
|
||||
|
||||
} while (result.NextRow());
|
||||
|
||||
}
|
||||
|
||||
public uint Id;
|
||||
public string Login;
|
||||
public bool IsLockedToIP;
|
||||
public string LockCountry;
|
||||
public string LastIP;
|
||||
public uint LoginTicketExpiry;
|
||||
public bool IsBanned;
|
||||
public bool IsPermanenetlyBanned;
|
||||
public string PasswordVerifier;
|
||||
public string Salt;
|
||||
|
||||
public Dictionary<uint, GameAccountInfo> GameAccounts = new Dictionary<uint, GameAccountInfo>();
|
||||
}
|
||||
|
||||
public class GameAccountInfo
|
||||
{
|
||||
public void LoadResult(SQLFields fields, int startColumn)
|
||||
public uint Id;
|
||||
public string Name;
|
||||
public string DisplayName;
|
||||
public uint UnbanDate;
|
||||
public bool IsBanned;
|
||||
public bool IsPermanenetlyBanned;
|
||||
public AccountTypes SecurityLevel;
|
||||
|
||||
public Dictionary<uint, byte> CharacterCounts;
|
||||
public Dictionary<string, LastPlayedCharacterInfo> LastPlayedCharacters;
|
||||
|
||||
public GameAccountInfo(SQLFields fields, int startColumn)
|
||||
{
|
||||
Id = fields.Read<uint>(startColumn + 0);
|
||||
Name = fields.Read<string>(startColumn + 1);
|
||||
@@ -693,23 +263,15 @@ namespace BNetServer.Networking
|
||||
DisplayName = "WoW" + Name.Substring(hashPos + 1);
|
||||
else
|
||||
DisplayName = Name;
|
||||
|
||||
CharacterCounts = new Dictionary<uint, byte>();
|
||||
LastPlayedCharacters = new Dictionary<string, LastPlayedCharacterInfo>();
|
||||
}
|
||||
|
||||
public uint Id;
|
||||
public string Name;
|
||||
public string DisplayName;
|
||||
public uint UnbanDate;
|
||||
public bool IsBanned;
|
||||
public bool IsPermanenetlyBanned;
|
||||
public AccountTypes SecurityLevel;
|
||||
|
||||
public Dictionary<uint /*realmAddress*/, byte> CharacterCounts = new Dictionary<uint, byte>();
|
||||
public Dictionary<string /*subRegion*/, LastPlayedCharacterInfo> LastPlayedCharacters = new Dictionary<string, LastPlayedCharacterInfo>();
|
||||
}
|
||||
|
||||
public class LastPlayedCharacterInfo
|
||||
{
|
||||
public RealmHandle RealmId;
|
||||
public RealmId RealmId;
|
||||
public string CharacterName;
|
||||
public ulong CharacterGUID;
|
||||
public uint LastPlayedTime;
|
||||
|
||||
Reference in New Issue
Block a user