public static bool Invoke(Packet reader, Session session)
        {
            var message = reader.Header.Message;

            Log.Network($"Received Auth packet: {message} (0x{message:X}), Length: {reader.Data.Length}");

            HandleAuthPacket packet;

            if (AuthMessageHandlers.TryGetValue(message, out packet))
            {
                packet.Invoke(reader, session);

                return true;
            }

            return false;
        }
        public static void HandleGameAccountListMyAccounts(Packet packet, Session session)
        {
            var userId = uint.Parse(packet["UserId"].ToString());

            if (userId == session.Account.Id)
            {
                var reply = new Packet(StsReason.OK, packet.Header.Sequence);

                // Only 1 GameAccount supported for now.
                reply.Xml.WriteElementRoot("Reply");
                reply.Xml.WriteCustom("<GameAccount>\n");
                reply.Xml.WriteElement("Alias", $"{session.Account.Alias}");
                reply.Xml.WriteElement("Created", "");
                reply.Xml.WriteCustom("</GameAccount>\n");

                session.Send(reply);
            }
        }
        public static void HandleAuthLoginFinish(Packet packet, Session session)
        {
            // Server packets are encrypted now.
            session.ServerCrypt = new RC4();
            session.ServerCrypt.PrepareKey(session.SecureRemotePassword.SessionKey);

            var reply = new Packet(StsReason.OK, packet.Header.Sequence);

            reply.Xml.WriteElementRoot("Reply");

            reply.Xml.WriteElement("LocationId", "");
            reply.Xml.WriteElement("UserId", session.Account.Id.ToString());
            reply.Xml.WriteElement("UserCenter", "");
            reply.Xml.WriteElement("UserName", session.Account.Email);
            reply.Xml.WriteElement("AccessMask", "");
            reply.Xml.WriteElement("Roles", "");
            reply.Xml.WriteElement("Status", "");

            session.Send(reply);
        }
        public static void HandleAuthKeyData(Packet packet, Session session)
        {
            var keyData = new BinaryReader(new MemoryStream(Convert.FromBase64String(packet["KeyData"].ToString())));
            var a = keyData.ReadBytes(keyData.ReadInt32());
            var m = keyData.ReadBytes(keyData.ReadInt32());

            session.SecureRemotePassword.CalculateU(a);
            session.SecureRemotePassword.CalculateClientM(a);

            if (session.SecureRemotePassword.ClientM.Compare(m))
            {
                session.SecureRemotePassword.CalculateServerM(m, a);

                session.ClientCrypt = new RC4();
                session.ClientCrypt.PrepareKey(session.SecureRemotePassword.SessionKey);

                session.State = 1;

                var SKeyData = new BinaryWriter(new MemoryStream());

                SKeyData.Write(session.SecureRemotePassword.ServerM.Length);
                SKeyData.Write(session.SecureRemotePassword.ServerM);

                var reply = new Packet(StsReason.OK, packet.Header.Sequence);

                reply.Xml.WriteElementRoot("Reply");
                reply.Xml.WriteElement("KeyData", Convert.ToBase64String(SKeyData.ToArray()));

                session.Send(reply);
            }
            else
            {
                session.Account = null;

                var reply = new Packet(StsReason.Error, packet.Header.Sequence);

                reply.WriteError(AuthResult.ErrBadPasswd);

                session.Send(reply);
            }
        }
        public static void HandleAuthLoginStart(Packet packet, Session session)
        {
            // Account.Email
            var loginName = packet["LoginName"].ToString();

            session.Account = DB.Auth.Single<Account>(a => a.Email == loginName);

            // Support for email only.
            if (loginName != null && session.Account != null)
            {
                session.SecureRemotePassword = new SRP6a(session.Account.Salt, loginName, session.Account.PasswordVerifier);
                session.SecureRemotePassword.CalculateB();

                var keyData = new BinaryWriter(new MemoryStream());

                keyData.Write(session.SecureRemotePassword.S.Length);
                keyData.Write(session.SecureRemotePassword.S);
                keyData.Write(session.SecureRemotePassword.B.Length);
                keyData.Write(session.SecureRemotePassword.B);

                var reply = new Packet(StsReason.OK, packet.Header.Sequence);

                reply.Xml.WriteElementRoot("Reply");
                reply.Xml.WriteElement("KeyData", Convert.ToBase64String(keyData.ToArray()));

                session.Send(reply);
            }
            else
            {
                // Let's use ErrBadPasswd instead of ErrAccountNotFound.
                var reply = new Packet(StsReason.Error, packet.Header.Sequence);

                reply.WriteError(AuthResult.ErrBadPasswd);

                session.Send(reply);
            }
        }
        public static void HandleAuthRequestGameToken(Packet packet, Session session)
        {
            DB.Auth.Delete<Redirect>(r => r.AccountId == session.Account.Id);

            var redirectData = new Redirect
            {
                AccountId = session.Account.Id,
                IP = session.GetIPAddress()
            };

            if (DB.Auth.Add(redirectData))
            {
                // Reset gateway ticket and redirect.
                if (DB.Auth.Update<Account>(a => a.Id == session.Account.Id, a => a.GatewayTicket.Set("")))
                {
                    var reply = new Packet(StsReason.OK, packet.Header.Sequence);

                    reply.Xml.WriteElementRoot("Reply");

                    reply.Xml.WriteElement("Token", "");

                    session.Send(reply);
                }
            }
            else
                session.Dispose();
        }