public static byte[] GetAddonInfoData(WorldSession session, byte[] packedData, int packedSize, int unpackedSize)
        {
            // Check ZLib header (normal mode)
            if (packedData[0] == 0x78 && packedData[1] == 0x9C)
            {
                var unpackedAddonData = new byte[unpackedSize];

                if (packedSize > 0)
                {
                    using (var inflate = new DeflateStream(new MemoryStream(packedData, 2, packedSize - 6), CompressionMode.Decompress))
                    {
                        var decompressed = new MemoryStream();
                        inflate.CopyTo(decompressed);

                        decompressed.Seek(0, SeekOrigin.Begin);

                        for (int i = 0; i < unpackedSize; i++)
                            unpackedAddonData[i] = (byte)decompressed.ReadByte();
                    }
                }

                return unpackedAddonData;
            }
            else
            {
                Log.Error($"Wrong AddonInfo for Client '{session.GetClientInfo()}'.");

                session.Dispose();
            }

            return null;
        }
Example #2
0
        public static async void HandleAuthContinuedSession(AuthContinuedSession authContinuedSession, WorldSession session)
        {
            var accountInfo = Manager.Redirect.GetAccountInfo(authContinuedSession.Key);

            // Delete redirect key
            Manager.Redirect.DeleteGameAccountRedirect(authContinuedSession.Key);

            if (accountInfo != null)
            {
                var sha1 = new SHA1Managed();

                var emailBytes = Encoding.UTF8.GetBytes(accountInfo.Item1.Id + "#" + accountInfo.Item2.Index);
                var sessionKeyBytes = accountInfo.Item2.SessionKey.ToByteArray();
                var challengeBytes = BitConverter.GetBytes(session.Challenge);

                sha1.TransformBlock(emailBytes, 0, emailBytes.Length, emailBytes, 0);
                sha1.TransformBlock(sessionKeyBytes, 0, 40, sessionKeyBytes, 0);
                sha1.TransformFinalBlock(challengeBytes, 0, 4);

                if (sha1.Hash.Compare(authContinuedSession.Digest))
                {
                    session.State = SessionState.Authenticated;

                    session.Account = accountInfo.Item1;
                    session.GameAccount = accountInfo.Item2;

                    session.Crypt = new Framework.Cryptography.WoW.WoWCrypt();
                    session.Crypt.Initialize(accountInfo.Item2.SessionKey.ToByteArray(), session.ClientSeed, session.ServerSeed);

                    // Resume on the new connection
                    await session.Send(new ResumeComms());

                    return;
                }
            }

            session.Dispose();
        }
        public static async void HandlePlayerLogin(PlayerLogin playerLogin, WorldSession session)
        {
            Log.Debug($"Character with GUID '{playerLogin.PlayerGUID.CreationBits}' tried to login...");

            var character = DB.Character.Single<Character>(c => c.Guid == playerLogin.PlayerGUID.CreationBits && c.GameAccountId == session.GameAccount.Id);

            if (character != null)
            {
                var worldNode = Manager.Redirect.GetWorldNode((int)character.Map);

                if (worldNode != null)
                {
                    // Create new player.
                    session.Player = new Player(character);

                    // Suspend the current connection & redirect
                    // Disable (causes disconnect).
                    //await session.Send(new SuspendComms());
                    await NetHandler.SendConnectTo(session, worldNode.Address, worldNode.Port, 1);

                    // Enable key bindings, etc.
                    await session.Send(new AccountDataTimes { PlayerGuid = session.Player.Guid });

                    // Send known spells
                    await session.Send(new InitialKnownSpells
                    {
                        InitialLogin = character.FirstLogin == 1,
                        KnownSpells  = character.CharacterSpells
                    });

                    // Enter world.
                    Manager.Player.EnterWorld(session);
                }
            }
            else
                session.Dispose();
        }
        public static async void HandleCharDelete(CharDelete charDelete, WorldSession session)
        {
            if (charDelete.Guid.CreationBits > 0 && charDelete.Guid.Type == GuidType.Player)
            {
                var deleteChar = new DeleteChar();
                var guid = charDelete.Guid;
                var gameAccount = session.GameAccount;

                if (DB.Character.Delete<Character>(c => c.Guid == guid.Low && c.GameAccountId == gameAccount.Id))
                    deleteChar.Code = CharDeleteCode.Success;
                else
                    deleteChar.Code = CharDeleteCode.Failed;

                await session.Send(deleteChar);
            }
            else
                session.Dispose();
        }
Example #5
0
        public static async Task SendConnectTo(WorldSession session, string ip, ushort port, byte connection = 0)
        {
            var connectTo = new ConnectTo
            {
                Key = Manager.Redirect.CreateRedirectKey(session.Player.Guid.Low),
                Serial = 0xE,
                Con = connection
            };

            // Fail
            if (connectTo.Key == 0)
            {
                session.Dispose();

                return;
            }

            var payloadData = new byte[0xFF];
            var ipBytes = IPAddress.Parse(ip).GetAddressBytes();

            // 0 - 15, Address, IPv6 not supported for now
            payloadData[0] = ipBytes[0];
            payloadData[1] = ipBytes[1];
            payloadData[2] = ipBytes[2];
            payloadData[3] = ipBytes[3];

            // 16
            payloadData[16] = 0x01;

            // 17 - 20, adler32, changes with compression seed.
            // Let's use a static one for now
            payloadData[17] = 0x43;
            payloadData[18] = 0xfd;
            payloadData[19] = 0xb8;
            payloadData[20] = 0x22;

            // 21
            payloadData[21] = 0x2A;

            var portBytes = BitConverter.GetBytes(port);

            // 22 - 23, Port
            payloadData[22] = portBytes[0];
            payloadData[23] = portBytes[1];

            var msg = "Blossom opens above\nSpines rising to the air\nMulti-Emu grows stronger\n\0\0";

            // 24 - 94, Haiku
            Array.Copy(Encoding.ASCII.GetBytes(msg), 0, payloadData, 24, 71);

            // 94 - 125, static for now...
            Array.Copy(new byte[] { 0xD6, 0xAC, 0x21, 0xE6, 0xB2, 0x7B, 0x06, 0x3D, 0xA9, 0x9C, 0x09, 0x4B, 0xC7, 0x30, 0x48, 0x34, 0xD4, 0xF0, 0x55, 0x3B, 0x1B, 0x1D, 0xC9, 0x5B, 0xFD, 0x3C, 0xB9, 0x30, 0x9D, 0xF5, 0x40, 0xC0 }, 0, payloadData, 94, 32);

            // 126 - 233, 0 for now
            Array.Copy(new byte[108], 0, payloadData, 126, 108);

            // 234 - 253, ranodm for now
            Array.Copy(new byte[0].GenerateRandomKey(20), 0, payloadData, 234, 20);

            var dataOrder = new byte[payloadData.Length];

            for (var i = 0; i < payloadData.Length; i++)
                dataOrder[i] = payloadData[ConnectTo.PayloadOrder[i]];

            var encrypted = Manager.Redirect.Crypt.Encrypt(dataOrder);

            Array.Copy(encrypted, connectTo.Where, 0x100);

            await session.Send(connectTo);
        }
        public static async void AuthSessionHandler(AuthSession authSession, WorldSession session)
        {
            var accountParts = authSession.Account.Split(new[] { '#' });
            var authResult = AuthResult.Ok;

            if (accountParts.Length == 2)
            {
                var accountId = int.Parse(accountParts[0]);
                var gameIndex = byte.Parse(accountParts[1]);

                session.Account = DB.Auth.Single<Account>(a => a.Id == accountId);

                if (session.Account != null)
                    session.GameAccount = session.Account.GameAccounts.SingleOrDefault(ga => ga.Index == gameIndex);

                if (session.GameAccount != null)
                    session.Crypt = new WoWCrypt(session.GameAccount.SessionKey.ToByteArray());
                else
                    authResult = AuthResult.Failed;
            }

            session.Realm = DB.Auth.Single<Realm>(r => r.Id == authSession.RealmID);

            if (authSession.LoginServerType != (sbyte)LoginServerTypes.Battlenet || session.Realm == null)
                authResult = AuthResult.Reject;

            if (authResult == AuthResult.Ok)
            {
                var sha1 = new Sha1();

                sha1.Process(authSession.Account);
                sha1.Process(0u);
                sha1.Process(authSession.LocalChallenge);
                sha1.Process(session.Challenge);
                sha1.Finish(session.GameAccount.SessionKey.ToByteArray(), 40);

                // Check the password digest.
                if (!sha1.Digest.Compare(authSession.Digest))
                    authResult = AuthResult.Failed;
            }

            var authResponse = new AuthResponse
            {
                Result = authResult,
                HasSuccessInfo = authResult == AuthResult.Ok,
            };

            if (authResponse.HasSuccessInfo)
            {
                session.State = SessionState.Authenticated;

                var addonData = AddonHandler.GetAddonInfoData(session, authSession.AddonInfo, authSession.CompressedAddonInfoSize, authSession.UncompressedAddonInfoSize);

                if (addonData != null && addonData.Length != authSession.UncompressedAddonInfoSize)
                {
                    Log.Error("Addon Info data size mismatch.");

                    session.Dispose();

                    return;
                }

                authResponse.SuccessInfo.ActiveExpansionLevel = session.GameAccount.BoxLevel;
                authResponse.SuccessInfo.AccountExpansionLevel = session.GameAccount.BoxLevel;
                authResponse.SuccessInfo.AvailableRaces = Manager.GameAccount.GetAvailableRaces(session.GameAccount, session.Realm);
                authResponse.SuccessInfo.AvailableClasses = Manager.GameAccount.GetAvailableClasses(session.GameAccount, session.Realm);
                authResponse.SuccessInfo.Templates = Manager.GameAccount.GetAvailableCharacterTemplates(session.GameAccount, session.Realm);

                await session.Send(authResponse);

                AddonHandler.HandleAddonInfo(session, addonData);

                await session.Send(new TutorialFlags());
            }
            else
                await session.Send(authResponse);
        }