/trunk/WingMan/Communication/MQTTCommunication.cs |
@@ -1,4 +1,6 @@ |
using System; |
using System.Collections.Generic; |
using System.Linq; |
using System.Net; |
using System.Threading; |
using System.Threading.Tasks; |
@@ -5,7 +7,9 @@ |
using MQTTnet; |
using MQTTnet.Client; |
using MQTTnet.Extensions.ManagedClient; |
using MQTTnet.Protocol; |
using MQTTnet.Server; |
using WingMan.Utilities; |
using MqttClientConnectedEventArgs = MQTTnet.Client.MqttClientConnectedEventArgs; |
using MqttClientDisconnectedEventArgs = MQTTnet.Client.MqttClientDisconnectedEventArgs; |
|
@@ -13,6 +17,8 @@ |
{ |
public class MQTTCommunication : IDisposable |
{ |
public delegate void ClientAuthenticationFailed(object sender, EventArgs e); |
|
public delegate void ClientConnected(object sender, MqttClientConnectedEventArgs e); |
|
public delegate void ClientConnectionFailed(object sender, MqttManagedProcessFailedEventArgs e); |
@@ -25,6 +31,8 @@ |
|
public delegate void MessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e); |
|
public delegate void ServerAuthenticationFailed(object sender, EventArgs e); |
|
public delegate void ServerClientConnected(object sender, MQTTnet.Server.MqttClientConnectedEventArgs e); |
|
public delegate void ServerClientDisconnected(object sender, MQTTnet.Server.MqttClientDisconnectedEventArgs e); |
@@ -38,10 +46,14 @@ |
TaskScheduler = taskScheduler; |
CancellationToken = cancellationToken; |
|
TrackedClients = new TrackedClients {Clients = new List<TrackedClient>()}; |
|
Client = new MqttFactory().CreateManagedMqttClient(); |
Server = new MqttFactory().CreateMqttServer(); |
} |
|
private TrackedClients TrackedClients { get; } |
|
private TaskScheduler TaskScheduler { get; } |
|
private IManagedMqttClient Client { get; } |
@@ -56,6 +68,8 @@ |
|
private int Port { get; set; } |
|
private string Password { get; set; } |
|
private CancellationToken CancellationToken { get; } |
|
public MQTTCommunicationType Type { get; set; } |
@@ -65,6 +79,10 @@ |
await Stop(); |
} |
|
public event ClientAuthenticationFailed OnClientAuthenticationFailed; |
|
public event ServerAuthenticationFailed OnServerAuthenticationFailed; |
|
public event MessageReceived OnMessageReceived; |
|
public event ClientConnected OnClientConnected; |
@@ -85,12 +103,13 @@ |
|
public event ServerStopped OnServerStopped; |
|
public async Task Start(MQTTCommunicationType type, IPAddress ipAddress, int port, string nick) |
public async Task Start(MQTTCommunicationType type, IPAddress ipAddress, int port, string nick, string password) |
{ |
Type = type; |
IPAddress = ipAddress; |
Port = port; |
Nick = nick; |
Password = password; |
|
switch (type) |
{ |
@@ -158,6 +177,18 @@ |
|
private async void ClientOnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e) |
{ |
try |
{ |
e.ApplicationMessage.Payload = await AES.Decrypt(e.ApplicationMessage.Payload, Password); |
} |
catch (Exception) |
{ |
await Task.Delay(0).ContinueWith(_ => OnClientAuthenticationFailed?.Invoke(sender, e), |
CancellationToken, TaskContinuationOptions.None, TaskScheduler); |
|
return; |
} |
|
await Task.Delay(0).ContinueWith(_ => OnMessageReceived?.Invoke(sender, e), |
CancellationToken, TaskContinuationOptions.None, TaskScheduler); |
} |
@@ -185,6 +216,7 @@ |
var optionsBuilder = new MqttServerOptionsBuilder() |
.WithDefaultEndpointBoundIPAddress(IPAddress) |
.WithSubscriptionInterceptor(MQTTSubscriptionIntercept) |
.WithConnectionValidator(MQTTConnectionValidator) |
.WithDefaultEndpointPort(Port); |
|
BindServerHandlers(); |
@@ -194,6 +226,23 @@ |
Running = true; |
} |
|
private void MQTTConnectionValidator(MqttConnectionValidatorContext context) |
{ |
// Do not accept connections from banned clients. |
if (TrackedClients.Clients.Any(client => |
(string.Equals(client.EndPoint, context.Endpoint, StringComparison.OrdinalIgnoreCase) || |
string.Equals(client.ClientId, context.ClientId, StringComparison.Ordinal)) && |
client.Banned)) |
{ |
context.ReturnCode = MqttConnectReturnCode.ConnectionRefusedNotAuthorized; |
return; |
} |
|
TrackedClients.Clients.Add(new TrackedClient {ClientId = context.ClientId, EndPoint = context.Endpoint}); |
|
context.ReturnCode = MqttConnectReturnCode.ConnectionAccepted; |
} |
|
private async Task StopServer() |
{ |
UnbindServerHandlers(); |
@@ -239,6 +288,37 @@ |
|
private async void ServerOnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e) |
{ |
try |
{ |
e.ApplicationMessage.Payload = await AES.Decrypt(e.ApplicationMessage.Payload, Password); |
} |
catch (Exception) |
{ |
// Decryption failed, assume a rogue client and ban the client. |
foreach (var client in TrackedClients.Clients) |
{ |
if (!string.Equals(client.ClientId, e.ClientId, StringComparison.Ordinal)) |
continue; |
|
client.Banned = true; |
|
foreach (var clientSessionStatus in await Server.GetClientSessionsStatusAsync()) |
{ |
if (!string.Equals(clientSessionStatus.ClientId, e.ClientId, StringComparison.Ordinal) && |
!string.Equals(clientSessionStatus.Endpoint, client.EndPoint, StringComparison.Ordinal)) |
continue; |
|
await clientSessionStatus.ClearPendingApplicationMessagesAsync(); |
await clientSessionStatus.DisconnectAsync(); |
} |
} |
|
await Task.Delay(0).ContinueWith(_ => OnServerAuthenticationFailed?.Invoke(sender, e), |
CancellationToken, TaskContinuationOptions.None, TaskScheduler); |
|
return; |
} |
|
await Task.Delay(0).ContinueWith(_ => OnMessageReceived?.Invoke(sender, e), |
CancellationToken, TaskContinuationOptions.None, TaskScheduler).ConfigureAwait(false); |
} |
@@ -294,19 +374,23 @@ |
|
public async Task Broadcast(string topic, byte[] payload) |
{ |
// Encrypt the payload. |
var encryptedPayload = await AES.Encrypt(payload, Password); |
|
switch (Type) |
{ |
case MQTTCommunicationType.Client: |
|
await Client.PublishAsync(new ManagedMqttApplicationMessage |
{ |
ApplicationMessage = new MqttApplicationMessage {Topic = topic, Payload = payload} |
ApplicationMessage = new MqttApplicationMessage {Topic = topic, Payload = encryptedPayload} |
}).ConfigureAwait(false); |
break; |
case MQTTCommunicationType.Server: |
await Server.PublishAsync(new MqttApplicationMessage {Topic = topic, Payload = payload}) |
await Server.PublishAsync(new MqttApplicationMessage {Topic = topic, Payload = encryptedPayload}) |
.ConfigureAwait(false); |
break; |
} |
} |
} |
} |
} |
/trunk/WingMan/Utilities/AES.cs |
@@ -0,0 +1,131 @@ |
using System; |
using System.IO; |
using System.Security.Cryptography; |
using System.Text; |
using System.Threading.Tasks; |
|
namespace WingMan.Utilities |
{ |
public static class AES |
{ |
private const int AesBlockSize = 128; |
private const CipherMode AesCipherMode = CipherMode.CBC; |
private const PaddingMode AesPaddingMode = PaddingMode.PKCS7; |
private const int AesKeySaltBytes = 16; |
private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider(); |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Encrypts a string given a key and initialization vector. |
/// </summary> |
/// <param name="data">the string to encrypt</param> |
/// <param name="key">the encryption key</param> |
/// <param name="separator">the separator to use between the cyphertext and the IV</param> |
/// <returns>Base64 encoded encrypted data</returns> |
public static async Task<byte[]> Encrypt(byte[] data, string key, string separator = ":") |
{ |
using (var rijdanelManaged = new RijndaelManaged()) |
{ |
// FIPS-197 / CBC |
rijdanelManaged.BlockSize = AesBlockSize; |
rijdanelManaged.Mode = AesCipherMode; |
rijdanelManaged.Padding = AesPaddingMode; |
|
// Compute the salt and the IV from the key. |
var salt = new byte[AesKeySaltBytes]; |
Rng.GetBytes(salt); |
var derivedKey = new Rfc2898DeriveBytes(key, salt); |
rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); |
rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); |
|
using (var encryptor = rijdanelManaged.CreateEncryptor(rijdanelManaged.Key, rijdanelManaged.IV)) |
{ |
using (var memoryStream = new MemoryStream()) |
{ |
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) |
{ |
using (var inputStream = new MemoryStream(data)) |
{ |
await inputStream.CopyToAsync(cryptoStream).ConfigureAwait(false); |
cryptoStream.FlushFinalBlock(); |
|
inputStream.Position = 0L; |
|
var payload = memoryStream.ToArray(); |
|
var base64Salt = Convert.ToBase64String(salt); |
var base64Payload = Convert.ToBase64String(payload); |
|
return Encoding.UTF8.GetBytes($"{base64Salt}{separator}{base64Payload}"); |
} |
} |
} |
} |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Decrypts a Base64 encoded string using AES with a given key and initialization vector. |
/// </summary> |
/// <param name="data"> |
/// a string consisting of the cyphertext to decrypt in Base64 and the IV in Base64 separated by the |
/// separator |
/// </param> |
/// <param name="key">the encryption key</param> |
/// <param name="separator">the separator to use between the cyphertext and the IV</param> |
/// <returns>the decrypted data</returns> |
public static async Task<byte[]> Decrypt(byte[] data, string key, string separator = ":") |
{ |
var input = Encoding.UTF8.GetString(data); |
|
// retrieve the salt from the data. |
var segments = input.Split(new[] {separator}, StringSplitOptions.None); |
if (segments.Length != 2) |
throw new ArgumentException("Invalid data."); |
|
using (var rijdanelManaged = new RijndaelManaged()) |
{ |
// FIPS-197 / CBC |
rijdanelManaged.BlockSize = AesBlockSize; |
rijdanelManaged.Mode = AesCipherMode; |
rijdanelManaged.Padding = AesPaddingMode; |
|
// Retrieve the key and the IV from the salt. |
var derivedKey = new Rfc2898DeriveBytes(key, Convert.FromBase64String(segments[0].Trim())); |
rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); |
rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); |
|
using (var decryptor = rijdanelManaged.CreateDecryptor(rijdanelManaged.Key, rijdanelManaged.IV)) |
{ |
using (var memoryStream = new MemoryStream(Convert.FromBase64String(segments[1].Trim()))) |
{ |
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) |
{ |
using (var streamReader = new StreamReader(cryptoStream)) |
{ |
return Encoding.UTF8.GetBytes(await streamReader.ReadToEndAsync() |
.ConfigureAwait(false)); |
} |
} |
} |
} |
} |
} |
|
public static string LinearFeedbackShiftPassword(string password, int size = 32) |
{ |
var sb = new StringBuilder(password); |
do |
{ |
sb.Append(password); |
} while (sb.Length < size); |
|
return sb.ToString(0, size); |
} |
} |
} |
/trunk/WingMan/WingManForm.Designer.cs |
@@ -21,7 +21,7 @@ |
this.button2 = new System.Windows.Forms.Button(); |
this.button1 = new System.Windows.Forms.Button(); |
this.label1 = new System.Windows.Forms.Label(); |
this.textBox1 = new System.Windows.Forms.TextBox(); |
this.WingBindingsBindToBox = new System.Windows.Forms.TextBox(); |
this.WingBindingsListBox = new System.Windows.Forms.ListBox(); |
this.groupBox2 = new System.Windows.Forms.GroupBox(); |
this.button5 = new System.Windows.Forms.Button(); |
@@ -34,6 +34,8 @@ |
this.label2 = new System.Windows.Forms.Label(); |
this.HelmNameTextBox = new System.Windows.Forms.TextBox(); |
this.groupBox4 = new System.Windows.Forms.GroupBox(); |
this.label6 = new System.Windows.Forms.Label(); |
this.Password = new System.Windows.Forms.TextBox(); |
this.label5 = new System.Windows.Forms.Label(); |
this.Nick = new System.Windows.Forms.TextBox(); |
this.HostButton = new System.Windows.Forms.Button(); |
@@ -52,6 +54,8 @@ |
this.tabPage3 = new System.Windows.Forms.TabPage(); |
this.pictureBox1 = new System.Windows.Forms.PictureBox(); |
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); |
this.OverlayPanel = new System.Windows.Forms.Panel(); |
this.OverlayPanelLabel = new System.Windows.Forms.Label(); |
this.groupBox1.SuspendLayout(); |
this.groupBox2.SuspendLayout(); |
this.groupBox3.SuspendLayout(); |
@@ -64,6 +68,7 @@ |
this.tabPage3.SuspendLayout(); |
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); |
this.tableLayoutPanel1.SuspendLayout(); |
this.OverlayPanel.SuspendLayout(); |
this.SuspendLayout(); |
// |
// groupBox1 |
@@ -72,7 +77,7 @@ |
this.groupBox1.Controls.Add(this.button2); |
this.groupBox1.Controls.Add(this.button1); |
this.groupBox1.Controls.Add(this.label1); |
this.groupBox1.Controls.Add(this.textBox1); |
this.groupBox1.Controls.Add(this.WingBindingsBindToBox); |
this.groupBox1.Controls.Add(this.WingBindingsListBox); |
this.groupBox1.Location = new System.Drawing.Point(8, 10); |
this.groupBox1.Name = "groupBox1"; |
@@ -109,6 +114,7 @@ |
this.button1.TabIndex = 3; |
this.button1.Text = "Bind"; |
this.button1.UseVisualStyleBackColor = true; |
this.button1.Click += new System.EventHandler(this.WingBindingsBindButtonClicked); |
// |
// label1 |
// |
@@ -119,14 +125,14 @@ |
this.label1.TabIndex = 2; |
this.label1.Text = "Bound To"; |
// |
// textBox1 |
// WingBindingsBindToBox |
// |
this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; |
this.textBox1.Location = new System.Drawing.Point(72, 232); |
this.textBox1.Name = "textBox1"; |
this.textBox1.ReadOnly = true; |
this.textBox1.Size = new System.Drawing.Size(168, 20); |
this.textBox1.TabIndex = 1; |
this.WingBindingsBindToBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; |
this.WingBindingsBindToBox.Location = new System.Drawing.Point(72, 232); |
this.WingBindingsBindToBox.Name = "WingBindingsBindToBox"; |
this.WingBindingsBindToBox.ReadOnly = true; |
this.WingBindingsBindToBox.Size = new System.Drawing.Size(168, 20); |
this.WingBindingsBindToBox.TabIndex = 1; |
// |
// WingBindingsListBox |
// |
@@ -244,6 +250,8 @@ |
// |
// groupBox4 |
// |
this.groupBox4.Controls.Add(this.label6); |
this.groupBox4.Controls.Add(this.Password); |
this.groupBox4.Controls.Add(this.label5); |
this.groupBox4.Controls.Add(this.Nick); |
this.groupBox4.Controls.Add(this.HostButton); |
@@ -254,11 +262,28 @@ |
this.groupBox4.Controls.Add(this.Address); |
this.groupBox4.Location = new System.Drawing.Point(8, 8); |
this.groupBox4.Name = "groupBox4"; |
this.groupBox4.Size = new System.Drawing.Size(344, 112); |
this.groupBox4.Size = new System.Drawing.Size(512, 112); |
this.groupBox4.TabIndex = 3; |
this.groupBox4.TabStop = false; |
this.groupBox4.Text = "Connection"; |
// |
// label6 |
// |
this.label6.AutoSize = true; |
this.label6.Location = new System.Drawing.Point(16, 80); |
this.label6.Name = "label6"; |
this.label6.Size = new System.Drawing.Size(53, 13); |
this.label6.TabIndex = 10; |
this.label6.Text = "Password"; |
// |
// Password |
// |
this.Password.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; |
this.Password.Location = new System.Drawing.Point(72, 76); |
this.Password.Name = "Password"; |
this.Password.Size = new System.Drawing.Size(160, 20); |
this.Password.TabIndex = 9; |
// |
// label5 |
// |
this.label5.AutoSize = true; |
@@ -279,7 +304,7 @@ |
// HostButton |
// |
this.HostButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; |
this.HostButton.Location = new System.Drawing.Point(136, 80); |
this.HostButton.Location = new System.Drawing.Point(368, 47); |
this.HostButton.Name = "HostButton"; |
this.HostButton.Size = new System.Drawing.Size(75, 23); |
this.HostButton.TabIndex = 6; |
@@ -290,7 +315,7 @@ |
// label4 |
// |
this.label4.AutoSize = true; |
this.label4.Location = new System.Drawing.Point(240, 24); |
this.label4.Location = new System.Drawing.Point(144, 20); |
this.label4.Name = "label4"; |
this.label4.Size = new System.Drawing.Size(26, 13); |
this.label4.TabIndex = 3; |
@@ -299,7 +324,7 @@ |
// ConnectButton |
// |
this.ConnectButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; |
this.ConnectButton.Location = new System.Drawing.Point(56, 80); |
this.ConnectButton.Location = new System.Drawing.Point(280, 47); |
this.ConnectButton.Name = "ConnectButton"; |
this.ConnectButton.Size = new System.Drawing.Size(75, 23); |
this.ConnectButton.TabIndex = 5; |
@@ -310,7 +335,7 @@ |
// Port |
// |
this.Port.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; |
this.Port.Location = new System.Drawing.Point(272, 20); |
this.Port.Location = new System.Drawing.Point(172, 16); |
this.Port.Name = "Port"; |
this.Port.Size = new System.Drawing.Size(60, 20); |
this.Port.TabIndex = 2; |
@@ -320,7 +345,7 @@ |
// label3 |
// |
this.label3.AutoSize = true; |
this.label3.Location = new System.Drawing.Point(8, 24); |
this.label3.Location = new System.Drawing.Point(8, 20); |
this.label3.Name = "label3"; |
this.label3.Size = new System.Drawing.Size(45, 13); |
this.label3.TabIndex = 1; |
@@ -329,9 +354,9 @@ |
// Address |
// |
this.Address.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; |
this.Address.Location = new System.Drawing.Point(56, 20); |
this.Address.Location = new System.Drawing.Point(56, 16); |
this.Address.Name = "Address"; |
this.Address.Size = new System.Drawing.Size(176, 20); |
this.Address.Size = new System.Drawing.Size(80, 20); |
this.Address.TabIndex = 0; |
this.Address.Text = "0.0.0.0"; |
this.Address.Click += new System.EventHandler(this.AddressTextBoxClick); |
@@ -441,13 +466,35 @@ |
this.tableLayoutPanel1.Size = new System.Drawing.Size(544, 432); |
this.tableLayoutPanel1.TabIndex = 7; |
// |
// OverlayPanel |
// |
this.OverlayPanel.AutoSize = true; |
this.OverlayPanel.BackColor = System.Drawing.Color.Black; |
this.OverlayPanel.Controls.Add(this.OverlayPanelLabel); |
this.OverlayPanel.Location = new System.Drawing.Point(0, 0); |
this.OverlayPanel.Name = "OverlayPanel"; |
this.OverlayPanel.Size = new System.Drawing.Size(544, 432); |
this.OverlayPanel.TabIndex = 8; |
this.OverlayPanel.Visible = false; |
// |
// OverlayPanelLabel |
// |
this.OverlayPanelLabel.AutoSize = true; |
this.OverlayPanelLabel.ForeColor = System.Drawing.SystemColors.Control; |
this.OverlayPanelLabel.Location = new System.Drawing.Point(192, 200); |
this.OverlayPanelLabel.Name = "OverlayPanelLabel"; |
this.OverlayPanelLabel.Size = new System.Drawing.Size(157, 13); |
this.OverlayPanelLabel.TabIndex = 0; |
this.OverlayPanelLabel.Text = "Press key-combination to bind..."; |
// |
// WingManForm |
// |
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); |
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; |
this.ClientSize = new System.Drawing.Size(544, 450); |
this.Controls.Add(this.tableLayoutPanel1); |
this.Controls.Add(this.statusStrip); |
this.Controls.Add(this.tableLayoutPanel1); |
this.Controls.Add(this.OverlayPanel); |
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; |
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); |
this.MaximizeBox = false; |
@@ -456,7 +503,7 @@ |
this.MinimumSize = new System.Drawing.Size(560, 488); |
this.Name = "WingManForm"; |
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; |
this.Text = "WingManForm"; |
this.Text = "WingMan © 2018 Wizardry and Steamworks"; |
this.groupBox1.ResumeLayout(false); |
this.groupBox1.PerformLayout(); |
this.groupBox2.ResumeLayout(false); |
@@ -475,6 +522,8 @@ |
this.tabPage3.ResumeLayout(false); |
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); |
this.tableLayoutPanel1.ResumeLayout(false); |
this.OverlayPanel.ResumeLayout(false); |
this.OverlayPanel.PerformLayout(); |
this.ResumeLayout(false); |
this.PerformLayout(); |
|
@@ -487,7 +536,7 @@ |
private System.Windows.Forms.GroupBox groupBox3; |
private System.Windows.Forms.ListBox WingBindingsListBox; |
private System.Windows.Forms.Label label1; |
private System.Windows.Forms.TextBox textBox1; |
private System.Windows.Forms.TextBox WingBindingsBindToBox; |
private System.Windows.Forms.TextBox LobbySayTextBox; |
public System.Windows.Forms.TextBox LobbyTextBox; |
private System.Windows.Forms.Label label2; |
@@ -518,6 +567,10 @@ |
private System.Windows.Forms.PictureBox pictureBox1; |
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; |
private System.Windows.Forms.ListBox HelmBindingsListBox; |
private System.Windows.Forms.Panel OverlayPanel; |
private System.Windows.Forms.Label OverlayPanelLabel; |
private System.Windows.Forms.Label label6; |
private System.Windows.Forms.TextBox Password; |
} |
} |
|
/trunk/WingMan/WingManForm.cs |
@@ -11,6 +11,7 @@ |
using WingMan.Lobby; |
using WingMan.MouseKey; |
using WingMan.Properties; |
using WingMan.Utilities; |
|
namespace WingMan |
{ |
@@ -24,6 +25,8 @@ |
FormCancellationTokenSource = new CancellationTokenSource(); |
|
MQTTCommunication = new MQTTCommunication(FormTaskScheduler, FormCancellationTokenSource.Token); |
MQTTCommunication.OnClientAuthenticationFailed += OnMQTTClientAuthenticationFailed; |
MQTTCommunication.OnServerAuthenticationFailed += OnMQTTServerAuthenticationFailed; |
|
MouseKeyBindings = new MouseKeyBindings(new List<MouseKeyBinding>()); |
|
@@ -81,6 +84,18 @@ |
|
public MouseKeyBindingsSynchronizer MouseKeyBindingsSynchronizer { get; set; } |
|
private void OnMQTTServerAuthenticationFailed(object sender, EventArgs e) |
{ |
ActivityTextBox.AppendText( |
$"{Strings.Failed_to_authenticate_client}{Environment.NewLine}"); |
} |
|
private void OnMQTTClientAuthenticationFailed(object sender, EventArgs e) |
{ |
ActivityTextBox.AppendText( |
$"{Strings.Server_authentication_failed}{Environment.NewLine}"); |
} |
|
/// <summary> |
/// Clean up any resources being used. |
/// </summary> |
@@ -181,11 +196,12 @@ |
return; |
} |
|
if (!ValidateAddressPort(out var ipAddress, out var port, out var nick)) |
if (!ValidateAddressPort(out var ipAddress, out var port, out var nick, out var password)) |
return; |
|
// Start the MQTT server. |
await MQTTCommunication.Start(MQTTCommunicationType.Server, ipAddress, port, nick).ConfigureAwait(false); |
await MQTTCommunication.Start(MQTTCommunicationType.Server, ipAddress, port, nick, password) |
.ConfigureAwait(false); |
toolStripStatusLabel.Text = Strings.Server_started; |
HostButton.BackColor = Color.Aquamarine; |
|
@@ -196,19 +212,22 @@ |
Nick.Enabled = false; |
} |
|
private bool ValidateAddressPort(out IPAddress address, out int port, out string nick) |
private bool ValidateAddressPort(out IPAddress address, out int port, out string nick, out string password) |
{ |
address = IPAddress.Any; |
port = 0; |
nick = string.Empty; |
password = string.Empty; |
|
if (string.IsNullOrEmpty(Address.Text) && |
string.IsNullOrEmpty(Port.Text) && |
string.IsNullOrEmpty(Nick.Text)) |
string.IsNullOrEmpty(Nick.Text) && |
string.IsNullOrEmpty(Password.Text)) |
{ |
Address.BackColor = Color.LightPink; |
Port.BackColor = Color.LightPink; |
Nick.BackColor = Color.LightPink; |
Password.BackColor = Color.LightPink; |
return false; |
} |
|
@@ -234,9 +253,18 @@ |
|
nick = Nick.Text; |
|
if (string.IsNullOrEmpty(Password.Text)) |
{ |
Password.BackColor = Color.LightPink; |
return false; |
} |
|
password = AES.LinearFeedbackShiftPassword(Password.Text); |
|
Address.BackColor = Color.Empty; |
Port.BackColor = Color.Empty; |
Nick.BackColor = Color.Empty; |
Password.BackColor = Color.Empty; |
|
return true; |
} |
@@ -256,10 +284,11 @@ |
return; |
} |
|
if (!ValidateAddressPort(out var ipAddress, out var port, out var nick)) |
if (!ValidateAddressPort(out var ipAddress, out var port, out var nick, out var password)) |
return; |
|
await MQTTCommunication.Start(MQTTCommunicationType.Client, ipAddress, port, nick).ConfigureAwait(false); |
await MQTTCommunication.Start(MQTTCommunicationType.Client, ipAddress, port, nick, password) |
.ConfigureAwait(false); |
|
toolStripStatusLabel.Text = Strings.Client_started; |
ConnectButton.Text = Strings.Disconnect; |
@@ -289,7 +318,7 @@ |
return; |
} |
|
HelmAddButton.Enabled = false; |
ShowOverlayPanel(); |
|
MouseKeyCombo = new List<string>(); |
|
@@ -300,6 +329,13 @@ |
MouseKeyApplicationHook.MouseUp += MouseKeyHookOnMouseUp; |
} |
|
private void ShowOverlayPanel() |
{ |
OverlayPanel.BringToFront(); |
OverlayPanel.Visible = true; |
OverlayPanel.Invalidate(); |
} |
|
private void MouseKeyHookOnKeyUp(object sender, KeyEventArgs e) |
{ |
MouseKeyBindings.Bindings.Add(new MouseKeyBinding(HelmNameTextBox.Text, MouseKeyCombo)); |
@@ -314,9 +350,16 @@ |
MouseKeyApplicationHook.Dispose(); |
|
HelmNameTextBox.Text = string.Empty; |
HelmAddButton.Enabled = true; |
HideOverlayPanel(); |
} |
|
private void HideOverlayPanel() |
{ |
OverlayPanel.SendToBack(); |
OverlayPanel.Visible = false; |
OverlayPanel.Invalidate(); |
} |
|
private void MouseKeyHookOnMouseUp(object sender, MouseEventArgs e) |
{ |
MouseKeyBindings.Bindings.Add(new MouseKeyBinding(HelmNameTextBox.Text, MouseKeyCombo)); |
@@ -331,7 +374,7 @@ |
MouseKeyApplicationHook.Dispose(); |
|
HelmNameTextBox.Text = string.Empty; |
HelmAddButton.Enabled = true; |
HideOverlayPanel(); |
} |
|
|
@@ -373,5 +416,9 @@ |
{ |
UpdateWingListBoxItems(); |
} |
|
private void WingBindingsBindButtonClicked(object sender, EventArgs e) |
{ |
} |
} |
} |