public static async void HandleProofResponse(ProofResponse proofResponse, AuthSession session)
        {
            for (int i = 0; i < proofResponse.ModuleCount; i++)
            {
                if (proofResponse.State == PasswordModuleState.ClientChallenge)
                {
                    if (session.GameAccount == null && session.GameAccounts?.Count > 1)
                    {
                        session.GameAccount = session.GameAccounts.SingleOrDefault(ga =>
                                                                                   ga.Game + ga.Index == proofResponse.GameAccountGame &&
                                                                                   ga.Region == proofResponse.GameAccountRegion);

                        var proofRequest = new ProofRequest { AccountRegion = session.Account.Region };

                        proofRequest.Modules.Add(new RiskFingerprintModule
                        {
                            AccountRegion = proofRequest.AccountRegion,
                            Data = Manager.ModuleMgr.Modules.SingleOrDefault(m => m.Name == "RiskFingerprint" && m.System == session.Platform)
                        });

                        await session.Send(proofRequest);

                        return;
                    }
                    else
                        session.GameAccount = session.GameAccounts[0];

                    if (session.GameAccount == null)
                        await SendAuthComplete(true, AuthResult.NoGameAccount, session);
                    else if (!session.GameAccount.IsOnline)
                    {
                        await SendAuthComplete(false, AuthResult.GlobalSuccess, session);

                        session.GameAccount.IsOnline = true;
                    }

                }
                else if (proofResponse.State == PasswordModuleState.ClientProof)
                {
                    session.SecureRemotePassword.CalculateU(proofResponse.A);
                    session.SecureRemotePassword.CalculateClientM(proofResponse.A);

                    if (session.SecureRemotePassword.ClientM.Compare(proofResponse.M1))
                    {
                        session.SecureRemotePassword.CalculateServerM(proofResponse.M1);

                        // Assign valid game accounts for the account
                        if (session.Account.GameAccounts != null)
                            session.GameAccounts = session.Account.GameAccounts.Where(ga => ga.Game == session.Program).ToList();

                        await SendProofValidation(session, proofResponse.ClientChallenge);
                    }
                    else
                        await SendAuthComplete(true, AuthResult.BadLoginInformation, session);
                }
            }
        }
        public static async void HandleListSubscribeRequest(ListSubscribeRequest listSubscribeRequest, AuthSession session)
        {
            var listSubscribeResponse = new ListSubscribeResponse();

            var index = 0;

            // Battlenet::Client::WoWRealm::ListUpdate
            foreach (var realm in Manager.RealmMgr.RealmList)
            {
                listSubscribeResponse.ListUpdates.Add(new ListUpdate
                {
                    Index = ++index,
                    RealmInfo = realm.Value
                });
            }

            await session.Send(listSubscribeResponse);
        }
        public static async void HandleJoinRequest(JoinRequest joinRequest, AuthSession session)
        {
            var serverSalt = new byte[0].GenerateRandomKey(4);

            session.GenerateSessionKey(BitConverter.GetBytes(joinRequest.ClientSalt), serverSalt);

            // Continue if sessionKey is not empty
            if (session.GameAccount.SessionKey != "")
            {
                var joinResponse = new JoinResponse
                {
                    RealmCount = Manager.RealmMgr.RealmList.Count,
                    ServerSalt = BitConverter.ToUInt32(serverSalt, 0)
                };

                foreach (var realm in Manager.RealmMgr.RealmList)
                {
                    var cRealm = Manager.RealmMgr.GetRealm(realm.Value.Id);

                    if (cRealm == null)
                    {
                        session.Dispose();
                        break;
                    }

                    var ip = IPAddress.Parse(cRealm.IPAddress).GetAddressBytes();
                    var port = BitConverter.GetBytes(cRealm.Port);

                    Array.Reverse(port);

                    joinResponse.RealmInfo.Add(Tuple.Create(ip, port));
                }

                await session.Send(joinResponse);
            }
        }
        public static async Task SendProofRequest(AuthSession session)
        {
            session.SecureRemotePassword = new SRP6a(session.Account.Salt, session.Account.Email, session.Account.PasswordVerifier);
            session.SecureRemotePassword.CalculateB();

            var proofRequest = new ProofRequest { AccountRegion = session.Account.Region };

            var thumbprintModule = new ThumbprintModule
            {
                AccountRegion = proofRequest.AccountRegion,
                Data = Manager.ModuleMgr.Modules.SingleOrDefault(m => m.Name == "Thumbprint" && m.System == session.Platform),
            };

            thumbprintModule.ModuleData = thumbprintModule.Data.Data.ToByteArray();

            proofRequest.Modules.Add(thumbprintModule);
            proofRequest.Modules.Add(new PasswordModule
            {
                AccountRegion = proofRequest.AccountRegion,
                Data = Manager.ModuleMgr.Modules.SingleOrDefault(m => m.Name == "Password" && m.System == session.Platform),
                SecureRemotePassword = session.SecureRemotePassword,
                State = PasswordModuleState.ServerChallenge
            });

            await session.Send(proofRequest);
        }
        public static async Task SendAuthComplete(bool failed, AuthResult result, AuthSession session)
        {
            var authComplete = new Complete { AuthResult = result, Failed = failed };

            if (!failed)
            {
                authComplete.PingTimeout = 0x80005000;

                authComplete.RegulatorInfo = new RegulatorInfo
                {
                    Threshold = 25000000,
                    Rate = 1000
                };

                authComplete.LogonInfo = new LogonInfo
                {
                    Account = session.Account,
                    GameAccount = session.GameAccount
                };
            }

            await session.Send(authComplete);
        }
        public static async Task SendProofValidation(AuthSession session, byte[] clientChallenge)
        {
            var proofRequest = new ProofRequest { AccountRegion = session.Account.Region };

            proofRequest.Modules.Add(new PasswordModule
            {
                Data = Manager.ModuleMgr.Modules.SingleOrDefault(m => m.Name == "Password" && m.System == session.Platform),
                State = PasswordModuleState.ValidateProof,
                AccountRegion = proofRequest.AccountRegion,
                SecureRemotePassword = session.SecureRemotePassword, 
                Size = 161
            });

            /// SelectGameAccount module
            if (session.GameAccounts?.Count > 1)
            {
                var gameAccountBuffer = new AuthPacket();

                gameAccountBuffer.Write(0, 8);
                gameAccountBuffer.Write(session.GameAccounts.Count, 8);

                session.GameAccounts.ForEach(ga =>
                {
                    gameAccountBuffer.Write(ga.Region, 8);
                    gameAccountBuffer.WriteString(ga.Game + ga.Index, 8, false);
                });

                gameAccountBuffer.Finish();

                proofRequest.Modules.Add(new SelectGameAccountModule
                {
                    Data = Manager.ModuleMgr.Modules.SingleOrDefault(m => m.Name == "SelectGameAccount" && m.System == session.Platform),
                    AccountRegion = proofRequest.AccountRegion,
                    GameAccountData = gameAccountBuffer.Data,
                    Size = (uint)gameAccountBuffer.Data.Length
                });
            }
            else
                proofRequest.Modules.Add(new RiskFingerprintModule
                {
                    Data = Manager.ModuleMgr.Modules.SingleOrDefault(m => m.Name == "RiskFingerprint" && m.System == session.Platform)
                });

            await session.Send(proofRequest);
        }
 public static async void HandlePing(Ping ping, AuthSession session)
 {
     await session.Send(new Pong());
 }