예제 #1
0
        public async Task StartConnectionAsync()
        {
            while (!Cancellation.IsCancellationRequested && this.tcp.Connected)
            {
                Packet packet = await this.GetNextPacketAsync();

                if (this.State == ClientState.Play && packet.data.Length < 1)
                {
                    this.Disconnect();
                }

                switch (this.State)
                {
                case ClientState.Status:     // Server ping/list
                    switch (packet.id)
                    {
                    case 0x00:
                        var status = new ServerStatus(Server);
                        await this.SendPacketAsync(new RequestResponse(status));

                        break;

                    case 0x01:
                        await this.SendPacketAsync(new PingPong(packet.data));

                        this.Disconnect();
                        break;
                    }
                    break;

                case ClientState.Handshaking:
                    if (packet.id == 0x00)
                    {
                        if (packet == null)
                        {
                            throw new InvalidOperationException();
                        }

                        var handshake = await PacketSerializer.FastDeserializeAsync <Handshake>(packet.data);

                        var nextState = handshake.NextState;

                        if (nextState != ClientState.Status && nextState != ClientState.Login)
                        {
                            this.Logger.LogDebug($"Client sent unexpected state ({(int)nextState}), forcing it to disconnect");
                            await this.DisconnectAsync(ChatMessage.Simple("you seem suspicious"));
                        }

                        this.State = nextState;
                        this.Logger.LogInformation($"Handshaking with client (protocol: {handshake.Version}, server: {handshake.ServerAddress}:{handshake.ServerPort})");
                    }
                    else
                    {
                        // Handle legacy ping
                    }
                    break;

                case ClientState.Login:
                    switch (packet.id)
                    {
                    default:
                        this.Logger.LogError("Client in state Login tried to send an unimplemented packet. Forcing it to disconnect.");
                        await this.DisconnectAsync("Unknown Packet Id.");

                        break;

                    case 0x00:
                        var loginStart = await PacketSerializer.FastDeserializeAsync <LoginStart>(packet.data);

                        string username = config.MulitplayerDebugMode ? $"Player{Globals.Random.Next(1, 999)}" : loginStart.Username;

                        this.Logger.LogDebug($"Received login request from user {loginStart.Username}");

                        await this.Server.DisconnectIfConnectedAsync(username);

                        if (this.config.OnlineMode)
                        {
                            var user = await MinecraftAPI.GetUserAsync(loginStart.Username);

                            this.Player = new Player(Guid.Parse(user.Id), loginStart.Username, this)
                            {
                                World = this.Server.World
                            };

                            this.packetCryptography.GenerateKeyPair();

                            var values = this.packetCryptography.GeneratePublicKeyAndToken();

                            this.randomToken = values.randomToken;

                            await this.SendPacketAsync(new EncryptionRequest(values.publicKey, this.randomToken));

                            break;
                        }

                        this.Player = new Player(UUIDFactory.CreateUUID(3, 1, $"OfflinePlayer:{username}"), username, this)
                        {
                            World = this.Server.World
                        };

                        //await this.SetCompression();
                        await this.ConnectAsync();

                        break;

                    case 0x01:
                        var encryptionResponse = PacketSerializer.FastDeserialize <EncryptionResponse>(packet.data);

                        this.sharedKey = this.packetCryptography.Decrypt(encryptionResponse.SharedSecret);
                        var decryptedToken = this.packetCryptography.Decrypt(encryptionResponse.VerifyToken);

                        if (!decryptedToken.SequenceEqual(this.randomToken))
                        {
                            await this.DisconnectAsync("Invalid token..");

                            break;
                        }

                        var serverId = sharedKey.Concat(this.packetCryptography.PublicKey).ToArray().MinecraftShaDigest();

                        JoinedResponse response = await MinecraftAPI.HasJoined(this.Player.Username, serverId);

                        if (response is null)
                        {
                            this.Logger.LogWarning($"Failed to auth {this.Player.Username}");
                            await this.DisconnectAsync("Unable to authenticate..");

                            break;
                        }

                        this.encryptionEnabled = true;
                        this.minecraftStream   = new AesStream(this.debugStream ?? (Stream)this.tcp.GetStream(), this.sharedKey);

                        //await this.SetCompression();
                        await ConnectAsync();

                        break;

                    case 0x02:
                        // Login Plugin Response
                        break;
                    }
                    break;

                case ClientState.Play:

                    //await this.Logger.LogDebugAsync($"Received Play packet with Packet ID 0x{packet.id.ToString("X")}");

                    await PacketHandler.HandlePlayPackets(packet, this);

                    break;
                }

                //await Task.Delay(50);
            }

            Logger.LogInformation($"Disconnected client");

            if (this.State == ClientState.Play)
            {
                await this.Server.Events.InvokePlayerLeaveAsync(new PlayerLeaveEventArgs(this.Player));
            }

            if (tcp.Connected)
            {
                this.tcp.Close();

                if (this.Player != null)
                {
                    this.Server.OnlinePlayers.TryRemove(this.Player.Uuid, out var _);
                }
            }
        }
예제 #2
0
        public async Task StartConnectionAsync()
        {
            while (!Cancellation.IsCancellationRequested && this.Tcp.Connected)
            {
                Packet packet = this.Compressed ? await this.GetNextCompressedPacketAsync() : await this.GetNextPacketAsync();

                Packet returnPacket;

                if (this.State == ClientState.Play && packet.PacketData.Length < 1)
                {
                    this.Disconnect();
                }

                switch (this.State)
                {
                case ClientState.Status:     //server ping/list
                    switch (packet.PacketId)
                    {
                    case 0x00:
                        var status = new ServerStatus(OriginServer);
                        await PacketHandler.CreateAsync(new RequestResponse(status), this.MinecraftStream);

                        break;

                    case 0x01:
                        await PacketHandler.CreateAsync(new PingPong(packet.PacketData), this.MinecraftStream);

                        this.Disconnect();
                        break;
                    }
                    break;

                case ClientState.Handshaking:
                    if (packet.PacketId == 0x00)
                    {
                        if (packet == null)
                        {
                            throw new InvalidOperationException();
                        }

                        var handshake = await PacketHandler.CreateAsync(new Handshake(packet.PacketData));

                        var nextState = handshake.NextState;

                        if (nextState != ClientState.Status && nextState != ClientState.Login)
                        {
                            this.Logger.LogDebug($"Client sent unexpected state ({(int)nextState}), forcing it to disconnect");
                            await this.DisconnectAsync(Chat.ChatMessage.Simple("you seem suspicious"));
                        }

                        this.State = nextState;
                        this.Logger.LogMessage($"Handshaking with client (protocol: {handshake.Version}, server: {handshake.ServerAddress}:{handshake.ServerPort})");
                    }
                    else
                    {
                        //Handle legacy ping stuff
                    }
                    break;

                case ClientState.Login:
                    switch (packet.PacketId)
                    {
                    default:
                        this.Logger.LogError("Client in state Login tried to send an unimplemented packet. Forcing it to disconnect.");
                        await this.DisconnectAsync(ChatMessage.Simple("Unknown Packet Id."));

                        break;

                    case 0x00:
                        var loginStart = await PacketHandler.CreateAsync(new LoginStart(packet.PacketData));

                        string username = loginStart.Username;

                        if (Config.MulitplayerDebugMode)
                        {
                            username = $"Player{new Random().Next(1, 999)}";
                            this.Logger.LogDebug($"Overriding username from {loginStart.Username} to {username}");
                        }

                        this.Logger.LogDebug($"Received login request from user {loginStart.Username}");

                        if (this.OriginServer.CheckPlayerOnline(username))
                        {
                            await this.OriginServer.Clients.FirstOrDefault(c => c.Player.Username == username).DisconnectAsync(Chat.ChatMessage.Simple("Logged in from another location"));
                        }

                        if (this.Config.OnlineMode)
                        {
                            var users = await MinecraftAPI.GetUsersAsync(new string[] { loginStart.Username });

                            var uid = users.FirstOrDefault();

                            var uuid = Guid.Parse(uid.Id);
                            this.Player = new Player(uuid, loginStart.Username, this);

                            PacketCryptography.GenerateKeyPair();

                            var pubKey = PacketCryptography.PublicKeyToAsn();

                            this.Token = PacketCryptography.GetRandomToken();

                            returnPacket = await PacketHandler.CreateAsync(new EncryptionRequest(pubKey, this.Token), this.MinecraftStream);

                            break;
                        }

                        this.Player = new Player(Guid.NewGuid(), username, this);
                        await ConnectAsync(this.Player.Uuid);

                        break;

                    case 0x01:
                        var encryptionResponse = await PacketHandler.CreateAsync(new EncryptionResponse(packet.PacketData));

                        JoinedResponse response;

                        this.SharedKey = PacketCryptography.Decrypt(encryptionResponse.SharedSecret);

                        var dec2 = PacketCryptography.Decrypt(encryptionResponse.VerifyToken);

                        var dec2Base64 = Convert.ToBase64String(dec2);

                        var tokenBase64 = Convert.ToBase64String(this.Token);

                        if (!dec2Base64.Equals(tokenBase64))
                        {
                            await this.DisconnectAsync(Chat.ChatMessage.Simple("Invalid token.."));

                            break;
                        }

                        var encodedKey = PacketCryptography.PublicKeyToAsn();

                        var serverId = PacketCryptography.MinecraftShaDigest(SharedKey.Concat(encodedKey).ToArray());

                        response = await MinecraftAPI.HasJoined(this.Player.Username, serverId);

                        if (response is null)
                        {
                            this.Logger.LogWarning($"Failed to auth {this.Player.Username}");
                            await this.DisconnectAsync(Chat.ChatMessage.Simple("Unable to authenticate.."));

                            break;
                        }
                        this.EncryptionEnabled = true;
                        this.MinecraftStream   = new AesStream(this.Tcp.GetStream(), this.SharedKey);

                        await ConnectAsync(new Guid(response.Id));

                        break;

                    case 0x02:
                        // Login Plugin Response
                        break;
                    }
                    break;

                case ClientState.Play:

                    ///this.Logger.LogDebugAsync($"Received Play packet with Packet ID 0x{packet.PacketId.ToString("X")}");

                    await PacketHandler.HandlePlayPackets(packet, this);

                    break;
                }
            }

            Logger.LogMessage($"Disconnected client");

            if (this.IsPlaying)
            {
                await this.OriginServer.Events.InvokePlayerLeave(new PlayerLeaveEventArgs(this));
            }

            this.OriginServer.Broadcast(string.Format(this.Config.LeaveMessage, this.Player.Username));

            this.Player = null;

            if (Tcp.Connected)
            {
                this.Tcp.Close();
            }
        }