Beispiel #1
0
 /// <summary>
 /// Used to send a message to a specific dashboard API client.
 /// </summary>
 /// <param name="message">The text value of the BaseMessage.</param>
 /// <param name="name">The name of the system.</param>
 /// <param name="type">The message type.</param>
 /// <param name="client">The target.</param>
 /// /<param name="flags">Optional message data.</param>
 public void PushTo(string message, string name, string type, IWebSocketConnection client, float[] flags = null)
 {
     try
     {
         var connection = GetWith(client);
         if (connection == null)
         {
             return;                     //programmer error
         }
         var msg = new Structures.BaseMessage
         {
             Type  = type,
             Name  = name,
             Text  = message,
             Date  = GetTime(),
             Flags = flags
         };
         connection.Send(JsonSerializer.Serialize(msg), QEData).ConfigureAwait(false);
     }
     catch (Fleck.ConnectionNotAvailableException)
     {
         RemoveWith(client);
     }
     catch (Exception ex)
     {
         //we'd like all the dashboards to know that they have been betrayed.
         Master.LogManager.LogError($"SRC : {client.ConnectionInfo.ClientIpAddress}: " + ex.ToString(), Shared.ErrorLocation.PushTo);
         Logger.LogError(ex.Message);
     }
 }
Beispiel #2
0
 private void MessageReceived(Structures.BaseMessage message, IWebSocketConnection conn)
 {
     //the dashboard clients should not be sending something that does not start with '/'.
     //if it is not that, it might correspond to some plugin.
     if (message.Text.StartsWith("/"))
     {
         lock (Commands)
         {
             Parallel.ForEach(Commands, Options, (prefix, state) =>
             {
                 if (message.Text.StartsWith(prefix.Key))
                 {
                     OnMessageReceived?.Invoke(message, conn);
                     state.Break();
                 }
             });
         }
     }
 }
Beispiel #3
0
 /// <summary>
 /// This will host an API server, that can be accessed with the given API keys.
 /// </summary>
 /// <param name="port">The port to host the server on.</param>
 /// <param name="listenInterface">The interface to bind the socket to.</param>
 /// <param name="keys">The accepted API keys.</param>
 /// <param name="logger">The global logger.</param>
 public WebApiServer(ushort port, string listenInterface, string[] keys, ILogger <Class> logger, IGameManager manager, Class masterClass, QuiteEffectiveDetector detector, bool secure, X509Certificate2 certificate)
 {
     this.StartTime = DateTime.UtcNow;
     this.Counters  = new PerformanceMonitors();
     this.Running   = true;
     this.Commands  = new Dictionary <string, string>();
     Options        = new ParallelOptions
     {
         MaxDegreeOfParallelism = Environment.ProcessorCount
     };
     this.Logger        = logger;
     this.GameManager   = manager;
     this.QEDector      = detector;
     this.QEData        = new QuodEratDemonstrandum.QuiteEnigmaticData(keys);
     GlobalMessage      = new Structures.BaseMessage();
     ApiKeys            = new List <string>();
     GlobalMessage.Type = Structures.MessageFlag.ConsoleLogMessage;
     ApiKeys.AddRange(keys);
     if (!secure)
     {
         Server = new WebSocketServer($"ws://{listenInterface}:{port}");
         Logger.LogInformation("! WebApi server: bound insecure listener.");
     }
     else
     {
         Server = new WebSocketServer($"wss://{listenInterface}:{port}")
         {
             Certificate = certificate
         };
         Server.EnabledSslProtocols = SslProtocols.Tls12;
         Logger.LogInformation("! WebApi server: bound secure listener.");
     }
     //we start the listener.
     Server.Start(socket =>
     {
         //a client connects.
         socket.OnOpen += () => OnOpen(socket);
     });
     HeartbeatThread = new Thread(DoHeartbeat);
     HeartbeatThread.Start();
     this.Master = masterClass;
 }
Beispiel #4
0
        /// <summary>
        /// A client has connected to the websocket server.
        /// </summary>
        /// <param name="conn">The client to process.</param>
        private void OnOpen(IWebSocketConnection conn)
        {
            if (QEDector.IsAttacking(IPAddress.Parse((ReadOnlySpan <char>)conn.ConnectionInfo.ClientIpAddress)))
            {
                lock (AttackerAddresses)
                {
                    if (!AttackerAddresses.Contains(conn.ConnectionInfo.ClientIpAddress))
                    {
                        Push(
                            $"Under denial of service attack from: {conn.ConnectionInfo.ClientIpAddress}! The address has been booted from accessing the Web API server, for 5 minutes. Please take action!",
                            "-HIGHEST PRIORITY/CRITICAL-", Structures.MessageFlag.ConsoleLogMessage);
                        AttackerAddresses.Add(conn.ConnectionInfo.ClientIpAddress);
                    }
                }

                return;
            }
            conn.OnMessage = message =>
            {
                //we will handle AUTH and commands here.
                try
                {
                    BlackTeaConnection connection;
                    if (!ContainsWith(conn))
                    {
                        var cryptoResult = QEData.TryDecrypt(message);
                        if (cryptoResult != null)
                        {
                            connection = new BlackTeaConnection(conn, cryptoResult.Password);
                        }
                        else
                        {
                            var reject = new Structures.BaseMessage
                            {
                                Name = "reject",
                                Date = GetTime(),
                                Type = Structures.MessageFlag.LoginApiRejected
                            };
                            conn.Send(JsonSerializer.Serialize(reject));
                            Master.LogManager.LogDashboard(IPAddress.Parse(conn.ConnectionInfo.ClientIpAddress), "[CRITICAL WARN] Failed log-in attempt.");
                            conn.Close();
                            //we log the issue.
                            Logger.LogWarning($"Failed log-in attempt : {conn.ConnectionInfo.ClientIpAddress}.");
                            return;
                        }
                    }
                    else
                    {
                        connection = GetWith(conn);
                    }

                    var json = QEData.Decrypt(message, connection.Key);
                    if (json == null)
                    {
                        return;
                    }
                    var msg = JsonSerializer.Deserialize <Structures.BaseMessage>(json);
                    if (msg != null)
                    {
                        if (msg.Type.Equals(Structures.MessageFlag.LoginApiRequest))
                        {
                            //the client has entered an invalid key.
                            lock (ApiKeys) if (!ApiKeys.Contains(msg.Text))
                                {
                                    msg.Name = "reject";
                                    msg.Date = GetTime();
                                    msg.Type = Structures.MessageFlag.LoginApiRejected;
                                    conn.Send(JsonSerializer.Serialize(msg));
                                    Master.LogManager.LogDashboard(IPAddress.Parse(conn.ConnectionInfo.ClientIpAddress), "[CRITICAL WARN] Failed log-in attempt.");
                                    conn.Close();
                                    //we log the issue.
                                    Logger.LogWarning($"Failed log-in attempt : {conn.ConnectionInfo.ClientIpAddress} - key : {msg.Text}");
                                    return;
                                }
                            lock (Clients)
                            {
                                Clients.Add(connection);
                                Logger.LogWarning($"ImpostorHQ : New web admin client : {conn.ConnectionInfo.ClientIpAddress}");
                                msg.Text = "You have successfully connected to ImpostorHQ!";
                                msg.Type = Structures.MessageFlag.LoginApiAccepted;
                                msg.Name = "welcome";
                                msg.Date = GetTime();
                                conn.Send(JsonSerializer.Serialize(msg));
                                conn.OnClose += () =>
                                {
                                    //we handle the client disconnecting.
                                    RemoveWith(conn);
                                };
                            }
                        }
                        else if (msg.Type.Equals(Structures.MessageFlag.ConsoleCommand))
                        {
                            if (!ContainsWith(conn))
                            {
                                //we are being attacked.
                                //the client is sending commands without being logged in.
                                conn.Close();
                                RemoveWith(conn);
                                Logger.LogWarning($"Break-in attempt from : {conn.ConnectionInfo.ClientIpAddress}");
                                return;
                            }
                            MessageReceived(msg, conn);
                        }
                        else
                        {
                            //invalid API call.
                            //probably not a client.
                            conn.Close();
                        }
                    }
                }
                catch (Exception ex)
                {
                    //not JSON.
                    Console.WriteLine($"Fatal error occured : {ex}");
                    return;
                }
            };
        }