public static byte[] GetAddonInfoData(CharacterSession 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.Message(LogType.Error, "Wrong AddonInfo for Client '{0}'.", session.GetClientInfo()); session.Dispose(); } return(null); }
public static void LoadAddonInfoData(CharacterSession 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(); } } HandleAddonInfo(session, unpackedAddonData); } else { Log.Message(LogType.Error, "Wrong AddonInfo for Client '{0}'.", session.GetClientIP()); session.Dispose(); } }
public static async Task InvokeHandler <T>(Packet reader, CharacterSession session) { var message = reader.Header.Message; Tuple <MethodInfo, Type, SessionState> data; if (MessageHandlers.TryGetValue(message, out data)) { if ((session.State & data.Item3) == SessionState.None) { var clientInfo = session.GetClientInfo(); Log.Debug($"Client '{clientInfo}': Received not allowed packet for state '{session.State}'."); Log.Debug($"Disconnecting '{clientInfo}'."); session.Dispose(); return; } var handlerObj = Activator.CreateInstance(data.Item2) as ClientPacket; handlerObj.Packet = reader; await Task.Run(() => handlerObj.Read()); if (handlerObj.IsReadComplete) { data.Item1.Invoke(null, new object[] { handlerObj, session }); } else { Log.Error($"Packet read for '{data.Item2.Name}' failed."); } } else { var msgName = Enum.GetName(typeof(ClientMessage), message) ?? Enum.GetName(typeof(GlobalClientMessage), message); if (msgName == null) { Log.Error($"Received unknown opcode '0x{message:X}, Length: {reader.Data.Length}'."); } else { Log.Error($"Packet handler for '{msgName} (0x{message:X}), Length: {reader.Data.Length}' not implemented."); } } }
public static void HandleCharDelete(CharDelete charDelete, CharacterSession 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; } session.Send(deleteChar); } else { session.Dispose(); } }
public static async void AuthSessionHandler(AuthSession authSession, CharacterSession 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); } }
public static async void SendConnectTo(CharacterSession session, string ip, ushort port, byte connection = 0) { var connectTo = new ConnectTo { Key = Manager.Redirect.CreateRedirectKey(session.GameAccount.Id), 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\nArctium grows stronger\n\0\0\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); }