Ejemplo n.º 1
0
        /// <summary>
        /// Processes an incomming message from the connection.
        /// </summary>
        /// <param name="connection">The connection where the message is being read from.</param>
        /// <param name="inboundMessage">The message to process.</param>
        public override void ProcessMessage(IConnection connection, INetworkMessage inboundMessage)
        {
            connection.ThrowIfNull(nameof(connection));
            inboundMessage.ThrowIfNull(nameof(inboundMessage));

            byte packetType;

            if (!connection.IsAuthenticated || connection.XTeaKey.Sum(b => b) == 0)
            {
                // this is a new connection...
                packetType = inboundMessage.GetByte();

                if (packetType != (byte)IncomingGamePacketType.LogIn)
                {
                    // but this is not the packet we were expecting for a new connection.
                    connection.Close();
                    return;
                }

                // Make a copy of the message in case we fail to decrypt using the first set of keys.
                var messageCopy = inboundMessage.Copy();

                inboundMessage.RsaDecrypt(useCipKeys: this.ProtocolConfiguration.UsingCipsoftRsaKeys);

                if (inboundMessage.GetByte() != 0)
                {
                    // means the RSA decrypt was unsuccessful, lets try with the other set of RSA keys...
                    inboundMessage = messageCopy;

                    inboundMessage.RsaDecrypt(useCipKeys: !this.ProtocolConfiguration.UsingCipsoftRsaKeys);

                    if (inboundMessage.GetByte() != 0)
                    {
                        // These RSA keys are also usuccessful... so give up.
                        connection.Close();
                        return;
                    }
                }
            }
            else
            {
                // Decrypt message using XTea
                inboundMessage.XteaDecrypt(connection.XTeaKey);
                inboundMessage.GetUInt16();
                packetType = inboundMessage.GetByte();
            }

            var handler = this.HandlerSelector.SelectForType(packetType);

            if (handler == null)
            {
                return;
            }

            var(intendsToRespond, responsePackets) = handler.HandleRequest(inboundMessage, connection);

            if (intendsToRespond)
            {
                // Send any responses prepared for this.
                var responseMessage = handler.PrepareResponse(responsePackets);

                connection.Send(responseMessage);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="message">The message to handle.</param>
        /// <param name="connection">A reference to the connection from where this message is comming from, for context.</param>
        /// <returns>A value tuple with a value indicating whether the handler intends to respond, and a collection of <see cref="IOutgoingPacket"/>s that compose that response.</returns>
        public override (bool IntendsToRespond, IEnumerable <IOutgoingPacket> ResponsePackets) HandleRequest(INetworkMessage message, IConnection connection)
        {
            connection.ThrowIfNull(nameof(connection));

            var responsePackets = new List <IOutgoingPacket>();

            var newConnectionInfo = message.ReadNewConnectionInfo();

            if (newConnectionInfo.Version != this.ProtocolConfiguration.ClientVersion.Numeric)
            {
                // TODO: hardcoded messages.
                responsePackets.Add(new LoginServerDisconnectPacket($"You need client version {this.ProtocolConfiguration.ClientVersion.Description} to connect to this server."));

                return(true, responsePackets);
            }

            // Make a copy of the message in case we fail to decrypt using the first set of keys.
            var messageCopy = message.Copy();

            message.RsaDecrypt(useCipKeys: this.ProtocolConfiguration.UsingCipsoftRsaKeys);

            // If GetByte() here is not Zero, it means the RSA decrypt was unsuccessful, lets try with the other set of RSA keys...
            if (message.GetByte() != 0)
            {
                message = messageCopy;

                message.RsaDecrypt(useCipKeys: !this.ProtocolConfiguration.UsingCipsoftRsaKeys);

                if (message.GetByte() != 0)
                {
                    // These RSA keys are also unsuccessful... give up.
                    // loginPacket = new AccountLoginPacket(inboundMessage);

                    // connection.SetXtea(loginPacket?.XteaKey);

                    //// TODO: hardcoded messages.
                    // if (gameConfig.UsingCipsoftRSAKeys)
                    // {
                    //    this.SendDisconnect(connection, $"The RSA encryption keys used by your client cannot communicate with this game server.\nPlease use an IP changer that does not replace the RSA Keys.\nWe recommend using Tibia Loader's 7.7 client.\nYou may also download the client from our website.");
                    // }
                    // else
                    // {
                    //    this.SendDisconnect(connection, $"The RSA encryption keys used by your client cannot communicate with this game server.\nPlease use an IP changer that replaces the RSA Keys.\nWe recommend using OTLand's IP changer with a virgin 7.7 client.\nYou may also download the client from our website.");
                    // }
                    return(false, null);
                }
            }

            var accLoginInfo = message.ReadAccountLoginInfo();

            // Associate the xTea key to allow future validate packets from this connection.
            connection.SetupAuthenticationKey(accLoginInfo.XteaKey);

            using var unitOfWork = new OpenTibiaUnitOfWork(this.ApplicationContext.DefaultDatabaseContext);

            // validate credentials.
            var accounts = unitOfWork.Accounts.FindMany(u => u.Number == accLoginInfo.AccountNumber && u.Password.Equals(accLoginInfo.Password));
            var account  = accounts.FirstOrDefault();

            if (account == null)
            {
                // TODO: hardcoded messages.
                responsePackets.Add(new LoginServerDisconnectPacket("Please enter a valid account number and password."));

                return(true, responsePackets);
            }

            var charactersFound = unitOfWork.Characters.FindMany(p => p.AccountId == account.Id);

            if (!charactersFound.Any())
            {
                // TODO: hardcoded messages.
                responsePackets.Add(new LoginServerDisconnectPacket($"You don't have any characters in your account.\nPlease create a new character in our web site: {this.GameConfiguration.World.WebsiteUrl}"));

                return(true, responsePackets);
            }

            var charList = new List <ICharacterListItem>();

            foreach (var character in charactersFound)
            {
                charList.Add(new CharacterListItem(
                                 character.Name,
                                 IPAddress.Parse(this.GameConfiguration.PublicAddressBinding.Ipv4Address),
                                 this.GameConfiguration.PublicAddressBinding.Port,
                                 this.GameConfiguration.World.Name));
            }

            responsePackets.Add(new MessageOfTheDayPacket(this.GameConfiguration.World.MessageOfTheDay));
            responsePackets.Add(new CharacterListPacket(charList, (ushort)(account.PremiumDays + account.TrialOrBonusPremiumDays)));

            return(true, responsePackets);
        }