diff --git a/.github/workflows/Build_Proxy.yml b/.github/workflows/Build_Proxy.yml
new file mode 100644
index 00000000..99a875d4
--- /dev/null
+++ b/.github/workflows/Build_Proxy.yml
@@ -0,0 +1,41 @@
+name: Build Proxy
+
+on: ['push']
+
+env:
+ DOTNET_VERSION: '6.0.x'
+
+jobs:
+ build:
+ strategy:
+ matrix:
+ os: ['windows', 'ubuntu']
+ runs-on: ${{ matrix.os }}-latest
+
+ steps:
+ - name: Checkout repository content
+ uses: actions/checkout@v3
+
+ - name: Setup .NET Core SDK
+ uses: actions/setup-dotnet@v2
+ with:
+ dotnet-version: ${{ env.DOTNET_VERSION }}
+
+ - name: Install dependencies
+ run: dotnet restore
+
+ - name: Build
+ run: dotnet build --configuration Release --no-restore
+
+ - name: Publish
+ run: dotnet publish --configuration Release --self-contained true --use-current-runtime
+
+ - name: Copy files
+ run: cp -r ./HermesProxy/bin/*/Release/*/*/publish/ publish
+
+ - name: Upload build artifact
+ uses: actions/upload-artifact@v3
+ with:
+ name: HermesProxy-${{ matrix.os }}-${{ runner.arch }}-${{ github.sha }}
+ path: publish
+ if-no-files-found: error
diff --git a/Framework/Configuration/Configuration.cs b/Framework/Configuration/Configuration.cs
index 839bae21..d02fd39c 100644
--- a/Framework/Configuration/Configuration.cs
+++ b/Framework/Configuration/Configuration.cs
@@ -46,26 +46,11 @@ private static KeyValueConfigurationCollection GetConfiguration()
}
++i;
}
- // load different config file
- if (configFile != null)
- {
- string configPath = Path.Combine(Environment.CurrentDirectory, configFile);
-
- try
- {
- // Get the mapped configuration file
- var config = ConfigurationManager.OpenExeConfiguration(configPath);
-
-
- settings = ((AppSettingsSection)config.GetSection("appSettings")).Settings;
- }
- catch (Exception ex)
- {
- Console.WriteLine("Could not load config file {0}, reason: {1}", configPath, ex.Message);
- }
- }
+
+ ExeConfigurationFileMap map = new ExeConfigurationFileMap { ExeConfigFilename = "HermesProxy.dll.config" };
+ var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
if (settings == null)
- settings = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).AppSettings.Settings;
+ settings = config.AppSettings.Settings;
// override config options with options from command line
foreach (var pair in opts)
diff --git a/Framework/Configuration/Settings.cs b/Framework/Configuration/Settings.cs
index 0aa757b5..3807000e 100644
--- a/Framework/Configuration/Settings.cs
+++ b/Framework/Configuration/Settings.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using System.Net;
namespace Framework
{
@@ -12,15 +13,16 @@ public static class Settings
public static readonly string ClientSeed = Conf.GetString("ClientSeed", "179D3DC3235629D07113A9B3867F97A7");
public static readonly ClientVersionBuild ClientBuild = Conf.GetEnum("ClientBuild", ClientVersionBuild.V2_5_2_40892);
public static readonly ClientVersionBuild ServerBuild = Conf.GetEnum("ServerBuild", ClientVersionBuild.V2_4_3_8606);
- public static readonly string ServerAddress = Conf.GetString("ServerAddress", "127.0.0.1");
+ public static readonly string ServerAddress = Dns.GetHostAddresses(Conf.GetString("ServerAddress", "127.0.0.1")).GetValue(0).ToString();
public static readonly int ServerPort = Conf.GetInt("ServerPort", 3724);
public static readonly string ReportedOS = Conf.GetString("ReportedOS", "OSX");
- public static readonly string ReportedPlatform = Conf.GetString("ReportedPlatform", "PPC");
+ public static readonly string ReportedPlatform = Conf.GetString("ReportedPlatform", "x86");
public static readonly string ExternalAddress = Conf.GetString("ExternalAddress", "127.0.0.1");
public static readonly int RestPort = Conf.GetInt("RestPort", 8081);
public static readonly int BNetPort = Conf.GetInt("BNetPort", 1119);
- public static readonly int RealmPort = Conf.GetInt("RealmPort", 8085);
+ public static readonly int RealmPort = Conf.GetInt("RealmPort", 8084);
public static readonly int InstancePort = Conf.GetInt("InstancePort", 8086);
public static readonly bool DebugOutput = Conf.GetBoolean("DebugOutput", false);
+ public static readonly bool PacketsLog = Conf.GetBoolean("PacketsLog", true);
}
}
diff --git a/Framework/Logging/Log.cs b/Framework/Logging/Log.cs
index ea342d8c..31757605 100644
--- a/Framework/Logging/Log.cs
+++ b/Framework/Logging/Log.cs
@@ -31,40 +31,36 @@ public static class Log
};
static BlockingCollection<(LogType Type, string Message)> logQueue = new();
-
- public static bool IsLogging;
+ private static Thread? _logOutputThread = null;
+ public static bool IsLogging => _logOutputThread != null && !logQueue.IsCompleted;
///
/// Start the logging Thread and take logs out of the
///
public static void Start()
{
- var logThread = new Thread(() =>
+ if (_logOutputThread == null)
{
- IsLogging = true;
-
- while (IsLogging)
+ _logOutputThread = new Thread(() =>
{
- Thread.Sleep(1);
+ foreach (var msg in logQueue.GetConsumingEnumerable())
+ {
+ if (msg.Type == LogType.Debug && !Framework.Settings.DebugOutput)
+ continue;
- if (!logQueue.TryTake(out var msg))
- continue;
+ Console.Write($"{DateTime.Now:HH:mm:ss} |");
- if (msg.Type == LogType.Debug && !Framework.Settings.DebugOutput)
- continue;
+ Console.ForegroundColor = LogToColorType[msg.Type].Color;
+ Console.Write($"{LogToColorType[msg.Type].Type}");
+ Console.ResetColor();
- Console.Write($"{DateTime.Now:H:mm:ss} |");
+ Console.WriteLine($"| {msg.Message}");
+ }
+ });
- Console.ForegroundColor = LogToColorType[msg.Type].Color;
- Console.Write($"{LogToColorType[msg.Type].Type}");
- Console.ResetColor();
-
- Console.WriteLine($"| {msg.Message}");
- }
- });
- IsLogging = true;
- logThread.IsBackground = true;
- logThread.Start();
+ _logOutputThread.IsBackground = true;
+ _logOutputThread.Start();
+ }
}
public static void Print(LogType type, object text, [CallerMemberName] string method = "", [CallerFilePath] string path = "")
diff --git a/HermesProxy/App.config b/HermesProxy/App.config
index c45f1cd0..912d2f9c 100644
--- a/HermesProxy/App.config
+++ b/HermesProxy/App.config
@@ -5,6 +5,7 @@
Option: ClientBuild
Description: The version of the client you will play with.
Default: "40618" (1.14.0)
+ "40892" (2.5.2)
-->
-
+
+
+
-
\ No newline at end of file
+
diff --git a/HermesProxy/Auth/AuthClient.cs b/HermesProxy/Auth/AuthClient.cs
index 43171529..a702d7fd 100644
--- a/HermesProxy/Auth/AuthClient.cs
+++ b/HermesProxy/Auth/AuthClient.cs
@@ -5,6 +5,7 @@
using System.Net.Sockets;
using HermesProxy.Enums;
using System.Numerics;
+using System.Threading.Tasks;
using Framework.Constants;
using Framework.Cryptography;
using Framework;
@@ -15,26 +16,35 @@ namespace HermesProxy.Auth
{
public class AuthClient
{
+ GlobalSessionData _globalSession;
Socket _clientSocket;
- bool? _isSuccessful = null;
+ TaskCompletionSource _response;
byte[] _passwordHash;
BigInteger _key;
byte[] _m2;
bool _hasRealmList;
string _username;
- string _password;
string _locale;
- public bool ConnectToAuthServer(string username, string password, string locale)
+ public AuthClient(GlobalSessionData globalSession)
+ {
+ _globalSession = globalSession;
+ }
+
+ public GlobalSessionData GetSession()
+ {
+ return _globalSession;
+ }
+
+ public AuthResult ConnectToAuthServer(string username, string password, string locale)
{
_username = username;
- _password = password;
_locale = locale;
- _isSuccessful = null;
+ _response = new ();
_hasRealmList = false;
- string authstring = $"{_username.ToUpper()}:{_password}";
+ string authstring = $"{_username.ToUpper()}:{password}";
_passwordHash = HashAlgorithm.SHA1.Hash(Encoding.ASCII.GetBytes(authstring.ToUpper()));
try
@@ -48,15 +58,19 @@ public bool ConnectToAuthServer(string username, string password, string locale)
catch (Exception ex)
{
Log.Print(LogType.Error, $"Socket Error: {ex.Message}");
- _isSuccessful = false;
+ _response.SetResult(AuthResult.FAIL_INTERNAL_ERROR);
}
- while (_isSuccessful == null)
- { }
+ _response.Task.Wait();
- return (bool)_isSuccessful;
+ return _response.Task.Result;
}
+ private void SetAuthResponse(AuthResult response)
+ {
+ _response.TrySetResult(response);
+ }
+
public void Disconnect()
{
if (!IsConnected())
@@ -89,7 +103,7 @@ private void ConnectCallback(IAsyncResult AR)
catch (Exception ex)
{
Log.Print(LogType.Error, $"Connect Error: {ex.Message}");
- _isSuccessful = false;
+ SetAuthResponse(AuthResult.FAIL_INTERNAL_ERROR);
}
}
@@ -101,8 +115,7 @@ private void ReceiveCallback(IAsyncResult AR)
if (received == 0)
{
- if (_isSuccessful == null)
- _isSuccessful = false;
+ SetAuthResponse(AuthResult.FAIL_INTERNAL_ERROR);
Log.Print(LogType.Error, "Socket Closed By Server");
return;
@@ -122,7 +135,7 @@ private void ReceiveCallback(IAsyncResult AR)
catch (Exception ex)
{
Log.Print(LogType.Error, $"Packet Read Error: {ex.Message}");
- _isSuccessful = false;
+ SetAuthResponse(AuthResult.FAIL_INTERNAL_ERROR);
}
}
@@ -135,7 +148,7 @@ private void SendCallback(IAsyncResult AR)
catch (Exception ex)
{
Log.Print(LogType.Error, $"Packet Send Error: {ex.Message}");
- _isSuccessful = false;
+ SetAuthResponse(AuthResult.FAIL_INTERNAL_ERROR);
}
}
@@ -148,7 +161,7 @@ private void SendPacket(ByteBuffer packet)
catch (Exception ex)
{
Log.Print(LogType.Error, $"Packet Write Error: {ex.Message}");
- _isSuccessful = false;
+ SetAuthResponse(AuthResult.FAIL_INTERNAL_ERROR);
}
}
@@ -171,7 +184,7 @@ private void HandlePacket(byte[] buffer, int size)
break;
default:
Log.Print(LogType.Error, $"No handler for opcode {opcode}!");
- _isSuccessful = false;
+ SetAuthResponse(AuthResult.FAIL_INTERNAL_ERROR);
break;
}
}
@@ -207,7 +220,7 @@ private void HandleLogonChallenge(ByteBuffer packet)
if (error != AuthResult.SUCCESS)
{
Log.Print(LogType.Error, $"Login failed. Reason: {error}");
- _isSuccessful = false;
+ SetAuthResponse(error);
return;
}
@@ -375,7 +388,7 @@ private void HandleLogonProof(ByteBuffer packet)
if (error != AuthResult.SUCCESS)
{
Log.Print(LogType.Error, $"Login failed. Reason: {error}");
- _isSuccessful = false;
+ SetAuthResponse(error);
return;
}
@@ -408,12 +421,12 @@ private void HandleLogonProof(ByteBuffer packet)
if (!equal)
{
Log.Print(LogType.Error, "Authentication failed!");
- _isSuccessful = false;
+ SetAuthResponse(AuthResult.FAIL_INTERNAL_ERROR);
}
else
{
Log.Print(LogType.Network, "Authentication succeeded!");
- _isSuccessful = true;
+ SetAuthResponse(AuthResult.SUCCESS);
}
}
@@ -471,7 +484,7 @@ private void HandleRealmList(ByteBuffer packet)
realmInfo.Name = packet.ReadCString();
string addressAndPort = packet.ReadCString();
string[] strArr = addressAndPort.Split(':');
- realmInfo.Address = strArr[0];
+ realmInfo.Address = Dns.GetHostAddresses(strArr[0]).GetValue(0).ToString();
realmInfo.Port = UInt16.Parse(strArr[1]);
realmInfo.Population = packet.ReadFloat();
realmInfo.CharacterCount = packet.ReadUInt8();
@@ -488,7 +501,7 @@ private void HandleRealmList(ByteBuffer packet)
realmList.Add(realmInfo);
}
- RealmManager.Instance.UpdateRealms(realmList);
+ GetSession().RealmManager.UpdateRealms(realmList);
_hasRealmList = true;
}
}
diff --git a/HermesProxy/Auth/AuthCommand.cs b/HermesProxy/Auth/AuthCommand.cs
index 13129528..cdca5166 100644
--- a/HermesProxy/Auth/AuthCommand.cs
+++ b/HermesProxy/Auth/AuthCommand.cs
@@ -6,6 +6,7 @@
namespace HermesProxy.Auth
{
+ // ReSharper disable InconsistentNaming
public enum AuthCommand : byte
{
LOGON_CHALLENGE = 0x00,
@@ -17,4 +18,5 @@ public enum AuthCommand : byte
TRANSFER_RESUME = 0x33,
TRANSFER_CANCEL = 0x34
}
-}
\ No newline at end of file
+ // ReSharper restore InconsistentNaming
+}
diff --git a/HermesProxy/Auth/AuthResult.cs b/HermesProxy/Auth/AuthResult.cs
index 86f55862..319243f9 100644
--- a/HermesProxy/Auth/AuthResult.cs
+++ b/HermesProxy/Auth/AuthResult.cs
@@ -1,28 +1,45 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace HermesProxy.Auth
+namespace HermesProxy.Auth
{
+ // ReSharper disable InconsistentNaming
public enum AuthResult : byte
- {
- SUCCESS = 0,
- FAILURE = 0x01,
- UNKNOWN1 = 0x02,
- ACCOUNT_BANNED = 0x03,
- NO_MATCH = 0x04,
- UNKNOWN2 = 0x05,
- ACCOUNT_IN_USE = 0x06,
- PREPAID_TIME_LIMIT = 0x07,
- SERVER_FULL = 0x08,
- WRONG_BUILD_NUMBER = 0x09,
- UPDATE_CLIENT = 0x0a,
- UNKNOWN3 = 0x0b,
- ACCOUNT_FREEZED = 0x0c,
- UNKNOWN4 = 0x0d,
- UNKNOWN5 = 0x0e,
- PARENTAL_CONTROL = 0x0f
+ { // See vMangos
+ SUCCESS = 0x00,
+ FAIL_UNKNOWN0 = 0x01, // ? Unable to connect
+ FAIL_UNKNOWN1 = 0x02, // ? Unable to connect
+ FAIL_BANNED = 0x03, // This account has been closed and is no longer available for use. Please go to /banned.html for further information.
+
+ FAIL_UNKNOWN_ACCOUNT = 0x04, // The information you have entered is not valid. Please check the spelling of the account name and password. If you need help in retrieving a lost or stolen password, see for more information
+ FAIL_INCORRECT_PASSWORD = 0x05, // The information you have entered is not valid. Please check the spelling of the account name and password. If you need help in retrieving a lost or stolen password, see for more information
+ // client reject next login attempts after this error, so in code used FAIL_UNKNOWN_ACCOUNT for both cases
+
+ FAIL_ALREADY_ONLINE = 0x06, // This account is already logged into . Please check the spelling and try again.
+ FAIL_NO_TIME = 0x07, // You have used up your prepaid time for this account. Please purchase more to continue playing
+ FAIL_DB_BUSY = 0x08, // Could not log in to at this time. Please try again later.
+ FAIL_VERSION_INVALID = 0x09, // Unable to validate game version. This may be caused by file corruption or interference of another program. Please visit for more information and possible solutions to this issue.
+ FAIL_VERSION_UPDATE = 0x0A, // Downloading
+ FAIL_INVALID_SERVER = 0x0B, // Unable to connect
+ FAIL_SUSPENDED = 0x0C, // This account has been temporarily suspended. Please go to /banned.html for further information
+ FAIL_FAIL_NOACCESS = 0x0D, // Unable to connect
+ SUCCESS_SURVEY = 0x0E, // Connected.
+ FAIL_PARENTCONTROL = 0x0F, // Access to this account has been blocked by parental controls. Your settings may be changed in your account preferences at
+ // TBC+
+ FAIL_LOCKED_ENFORCED = 0x10, // You have applied a lock to your account. You can change your locked status by calling your account lock phone number.
+ // WOTLK+
+ FAIL_TRIAL_ENDED = 0x11, // Your trial subscription has expired. Please visit to upgrade your account.
+ FAIL_USE_BATTLENET = 0x12, // This account is now attached to a Battle.net account. Please login with your Battle.net account email address and password.
+ FAIL_ANTI_INDULGENCE = 0x13, // Unable to connect
+ FAIL_EXPIRED = 0x14, // Unable to connect
+ FAIL_NO_GAME_ACCOUNT = 0x15, // Unable to connect
+ FAIL_CHARGEBACK = 0x16, // This World of Warcraft account has been temporary closed due to a chargeback on its subscription. Please refer to this for further information.
+ FAIL_IGR_WITHOUT_BNET = 0x17, // In order to log in to World of Warcraft using IGR time, this World of Warcraft account must first be merged with a Battle.net account. Please visit to merge this account.
+ FAIL_GAME_ACCOUNT_LOCKE = 0x18, // Access to your account has been temporarily disabled.
+ FAIL_UNLOCKABLE_LOCK = 0x19, // Your account has been locked but can be unlocked.
+ FAIL_CONVERSION_REQUIRE = 0x20, // This account needs to be converted to a Battle.net account. Please [Click Here] or go to: to begin conversion.
+ FAIL_DISCONNECTED = 0xFF,
+
+ // HermesProxy internal variables
+ FAIL_INTERNAL_ERROR = 0xFE, // Internal error
+ FAIL_WRONG_MODERN_VER = 0xFD, // Modern client is using unsupported version
}
+ // ReSharper restore InconsistentNaming
}
diff --git a/HermesProxy/BnetServer/Managers/Global.cs b/HermesProxy/BnetServer/Managers/Global.cs
index 5b18c183..35439b91 100644
--- a/HermesProxy/BnetServer/Managers/Global.cs
+++ b/HermesProxy/BnetServer/Managers/Global.cs
@@ -43,7 +43,5 @@ public static void AddNewSessionByKey(ulong connectKey, GlobalSessionData sessio
else
SessionsByKey.Add(connectKey, session);
}
-
- public static RealmManager RealmMgr { get { return RealmManager.Instance; } }
public static LoginServiceManager LoginServiceMgr { get { return LoginServiceManager.Instance; } }
}
\ No newline at end of file
diff --git a/HermesProxy/BnetServer/Networking/RestSession.cs b/HermesProxy/BnetServer/Networking/RestSession.cs
index 277cf3f0..0d708f92 100644
--- a/HermesProxy/BnetServer/Networking/RestSession.cs
+++ b/HermesProxy/BnetServer/Networking/RestSession.cs
@@ -9,97 +9,102 @@
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
+using System.Threading.Tasks;
+using HermesProxy.Auth;
+using HermesProxy.Enums;
namespace BNetServer.Networking
{
public class RestSession : SSLSocket
{
+ private const string BNET_SERVER_BASE_PATH = "/bnetserver/";
+ private const string TICKET_PREFIX = "HP-"; // Hermes Proxy
+
public RestSession(Socket socket) : base(socket) { }
public override void Accept()
{
+ // Setup SSL connection
AsyncHandshake(Global.LoginServiceMgr.GetCertificate());
}
- public async override void ReadHandler(byte[] data, int receivedLength)
+ public override async void ReadHandler(byte[] data, int receivedLength)
{
var httpRequest = HttpHelper.ParseRequest(data, receivedLength);
- if (httpRequest == null)
+ if (httpRequest == null || !RequestRouter(httpRequest))
+ {
+ CloseSocket();
return;
+ }
- switch (httpRequest.Method)
+ await AsyncRead(); // Read next request
+ }
+
+ public bool RequestRouter(HttpHeader httpRequest)
+ {
+ if (!httpRequest.Path.StartsWith(BNET_SERVER_BASE_PATH))
{
- case "GET":
- default:
- SendResponse(HttpCode.Ok, Global.LoginServiceMgr.GetFormInput());
- break;
- case "POST":
- HandleLoginRequest(httpRequest);
- return;
+ SendEmptyResponse(HttpCode.NotFound);
+ return false;
}
- await AsyncRead();
+ string path = httpRequest.Path.Substring(BNET_SERVER_BASE_PATH.Length);
+ string[] pathElements = path.Split('/');
+
+ switch (pathElements[0], httpRequest.Method)
+ {
+ case ("login", "GET"):
+ SendResponse(HttpCode.Ok, Global.LoginServiceMgr.GetFormInput());
+ return true;
+ case ("login", "POST"):
+ HandleLoginRequest(pathElements, httpRequest);
+ return true;
+ default:
+ SendEmptyResponse(HttpCode.NotFound);
+ return false;
+ };
}
- public void HandleLoginRequest(HttpHeader request)
+ public Task HandleLoginRequest(string[] pathElements, HttpHeader request)
{
LogonData loginForm = Json.CreateObject(request.Content);
- LogonResult loginResult = new();
if (loginForm == null)
- {
- loginResult.AuthenticationState = "LOGIN";
- loginResult.ErrorCode = "UNABLE_TO_DECODE";
- loginResult.ErrorMessage = "There was an internal error while connecting to Battle.net. Please try again later.";
- SendResponse(HttpCode.BadRequest, loginResult);
- return;
- }
+ return SendEmptyResponse(HttpCode.InternalServerError);
+
+ HermesProxy.GlobalSessionData globalSession = new();
+
+ // Format: "login/$platform/$build/$locale/"
+ globalSession.OS = pathElements[1];
+ globalSession.Build = UInt32.Parse(pathElements[2]);
+ globalSession.Locale = pathElements[3];
+
+ // Should never happen. Session.HandleLogon checks version already
+ if (Framework.Settings.ClientBuild != (ClientVersionBuild) globalSession.Build)
+ return SendAuthError(AuthResult.FAIL_WRONG_MODERN_VER);
string login = "";
string password = "";
- for (int i = 0; i < loginForm.Inputs.Count; ++i)
+ foreach (var field in loginForm.Inputs)
{
- switch (loginForm.Inputs[i].Id)
+ switch (field.Id)
{
- case "account_name":
- login = loginForm.Inputs[i].Value;
- break;
- case "password":
- password = loginForm.Inputs[i].Value;
- break;
+ case "account_name": login = field.Value; break;
+ case "password": password = field.Value; break;
}
}
- HermesProxy.GlobalSessionData globalSession = new();
-
- // We pass OS, Build and Locale in Path from HandleLogon
- string str = request.Path;
- str = str.Replace("/bnetserver/login/", "");
- str = str.Substring(0, str.IndexOf("/"));
- globalSession.OS = str;
- str = request.Path;
- str = str.Replace("/bnetserver/login/", "");
- str = str.Substring(str.IndexOf('/') + 1);
- str = str.Substring(0, str.IndexOf("/"));
- globalSession.Build = UInt32.Parse(str);
- str = request.Path;
- str = str.Replace("/bnetserver/login/", "");
- str = str.Substring(str.IndexOf('/') + 1);
- str = str.Substring(str.IndexOf('/') + 1);
- str = str.Substring(0, str.IndexOf("/"));
- globalSession.Locale = str;
-
- globalSession.AuthClient = new();
- if (globalSession.AuthClient.ConnectToAuthServer(login, password, globalSession.Locale))
- {
- string loginTicket = "";
- uint loginTicketExpiry = (uint)(Time.UnixTime + 3600);
-
- if (loginTicket.IsEmpty() || loginTicketExpiry < Time.UnixTime)
- {
- byte[] ticket = Array.Empty().GenerateRandomKey(20);
- loginTicket = "TC-" + ticket.ToHexString();
- }
+ globalSession.AuthClient = new(globalSession);
+ AuthResult response = globalSession.AuthClient.ConnectToAuthServer(login, password, globalSession.Locale);
+ if (response != AuthResult.SUCCESS)
+ { // Error handling
+ return SendAuthError(response);
+ }
+ else
+ { // Ticket creation
+ LogonResult loginResult = new();
+ byte[] ticket = Array.Empty().GenerateRandomKey(20);
+ string loginTicket = TICKET_PREFIX + ticket.ToHexString();
globalSession.LoginTicket = loginTicket;
globalSession.Username = login;
@@ -109,27 +114,35 @@ public void HandleLoginRequest(HttpHeader request)
loginResult.LoginTicket = loginTicket;
loginResult.AuthenticationState = "DONE";
- 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.";
- SendResponse(HttpCode.BadRequest, loginResult);
+ return SendResponse(HttpCode.Ok, loginResult);
}
}
- async void SendResponse(HttpCode code, T response)
+ async Task SendResponse(HttpCode code, T response)
{
await AsyncWrite(HttpHelper.CreateResponse(code, Json.CreateString(response)));
}
- string CalculateShaPassHash(string name, string password)
+ async Task SendAuthError(AuthResult response)
+ {
+ LogonResult loginResult = new();
+ (loginResult.AuthenticationState, loginResult.ErrorCode, loginResult.ErrorMessage) = response switch
+ {
+ AuthResult.FAIL_UNKNOWN_ACCOUNT => ("LOGIN", "UNABLE_TO_DECODE", "Invalid username or password."),
+ AuthResult.FAIL_INCORRECT_PASSWORD => ("LOGIN", "UNABLE_TO_DECODE", "Invalid password."),
+ AuthResult.FAIL_BANNED => ("LOGIN", "UNABLE_TO_DECODE", "This account has been closed and is no longer available for use."),
+ AuthResult.FAIL_SUSPENDED => ("LOGIN", "UNABLE_TO_DECODE", "This account has been temporarily suspended."),
+
+ AuthResult.FAIL_INTERNAL_ERROR => ("LOGON", "UNABLE_TO_DECODE", "There was an internal error. Please try again later."),
+ _ => ("LOGON", "UNABLE_TO_DECODE", $"Error: {response}"),
+ };
+
+ await SendResponse(HttpCode.BadRequest, loginResult);
+ }
+
+ async Task SendEmptyResponse(HttpCode code)
{
- SHA256 sha256 = SHA256.Create();
- var email = sha256.ComputeHash(Encoding.UTF8.GetBytes(name));
- return sha256.ComputeHash(Encoding.UTF8.GetBytes(email.ToHexString() + ":" + password)).ToHexString(true);
+ await SendResponse