WingMan

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 7  →  ?path2? @ 8
File deleted
/trunk/WingMan/Utilities.cs
/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/Communication/TrackedClient.cs
@@ -0,0 +1,11 @@
namespace WingMan.Communication
{
public class TrackedClient
{
public string ClientId { get; set; }
 
public string EndPoint { get; set; }
 
public bool Banned { get; set; }
}
}
/trunk/WingMan/Communication/TrackedClients.cs
@@ -0,0 +1,9 @@
using System.Collections.Generic;
 
namespace WingMan.Communication
{
public class TrackedClients
{
public List<TrackedClient> Clients { get; set; }
}
}
/trunk/WingMan/Properties/Strings.Designer.cs
@@ -133,6 +133,15 @@
}
/// <summary>
/// Looks up a localized string similar to Failed to authenticate client.
/// </summary>
internal static string Failed_to_authenticate_client {
get {
return ResourceManager.GetString("Failed_to_authenticate_client", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Matched helm key binding.
/// </summary>
internal static string Matched_helm_key_binding {
@@ -142,6 +151,15 @@
}
/// <summary>
/// Looks up a localized string similar to Server authentication failed.
/// </summary>
internal static string Server_authentication_failed {
get {
return ResourceManager.GetString("Server_authentication_failed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Server started.
/// </summary>
internal static string Server_started {
/trunk/WingMan/Properties/Strings.resx
@@ -141,9 +141,15 @@
<data name="Disconnect" xml:space="preserve">
<value>Disconnect</value>
</data>
<data name="Failed_to_authenticate_client" xml:space="preserve">
<value>Failed to authenticate client</value>
</data>
<data name="Matched_helm_key_binding" xml:space="preserve">
<value>Matched helm key binding</value>
</data>
<data name="Server_authentication_failed" xml:space="preserve">
<value>Server authentication failed</value>
</data>
<data name="Server_started" xml:space="preserve">
<value>Server started</value>
</data>
/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/Utilities/KeyConversion.cs
@@ -0,0 +1,424 @@
using System.Windows.Forms;
 
namespace WingMan
{
public static class KeyConversion
{
public static string ToDisplayName(this MouseButtons button)
{
var mouseButton = string.Empty;
switch (button)
{
case MouseButtons.Left:
mouseButton = "Left Mouse Button";
break;
case MouseButtons.Middle:
mouseButton = "Middle Mouse Button";
break;
case MouseButtons.Right:
mouseButton = "Right Mouse Button";
break;
}
 
return mouseButton;
}
 
public static string ToDisplayName(this Keys keys)
{
var keyString = string.Empty;
switch ((int) keys)
{
case 0:
break;
case 1:
keyString = "Mouse Left";
break;
case 2:
keyString = "Mouse Right";
break;
case 3:
keyString = "Cancel";
break;
case 4:
keyString = "Mouse Middle";
break;
case 5:
keyString = "Special 1";
break;
case 6:
keyString = "Special 2";
break;
case 8:
keyString = "Back";
break;
case 9:
keyString = "TAB";
break;
case 12:
keyString = "Clear";
break;
case 13:
keyString = "Enter";
break;
case 16:
keyString = "Shift";
break;
case 17:
keyString = "Ctrl";
break;
case 18:
keyString = "Menu";
break;
case 19:
keyString = "Pause";
break;
case 20:
keyString = "Caps Lock";
break;
case 21:
keyString = "Kana/Hangul";
break;
case 23:
keyString = "Junja";
break;
case 24:
keyString = "Final";
break;
case 25:
keyString = "Hanja/Kanji";
break;
case 27:
keyString = "Esc";
break;
case 28:
keyString = "Convert";
break;
case 29:
keyString = "NonConvert";
break;
case 30:
keyString = "Accept";
break;
case 31:
keyString = "Mode";
break;
case 32:
keyString = "Space";
break;
case 33:
keyString = "Page Up";
break;
case 34:
keyString = "Page Down";
break;
case 35:
keyString = "End";
break;
case 36:
keyString = "Home";
break;
case 37:
keyString = "Left";
break;
case 38:
keyString = "Up";
break;
case 39:
keyString = "Right";
break;
case 40:
keyString = "Down";
break;
case 41:
keyString = "Select";
break;
case 42:
keyString = "Print";
break;
case 43:
keyString = "Execute";
break;
case 44:
keyString = "Snapshot";
break;
case 45:
keyString = "Insert";
break;
case 46:
keyString = "Delete";
break;
case 47:
keyString = "Help";
break;
case 48:
keyString = "Num 0";
break;
case 49:
keyString = "Num 1";
break;
case 50:
keyString = "Num 2";
break;
case 51:
keyString = "Num 3";
break;
case 52:
keyString = "Num 4";
break;
case 53:
keyString = "Num 5";
break;
case 54:
keyString = "Num 6";
break;
case 55:
keyString = "Num 7";
break;
case 56:
keyString = "Num 8";
break;
case 57:
keyString = "Num 9";
break;
case 65:
keyString = "A";
break;
case 66:
keyString = "B";
break;
case 67:
keyString = "C";
break;
case 68:
keyString = "D";
break;
case 69:
keyString = "E";
break;
case 70:
keyString = "F";
break;
case 71:
keyString = "G";
break;
case 72:
keyString = "H";
break;
case 73:
keyString = "I";
break;
case 74:
keyString = "J";
break;
case 75:
keyString = "K";
break;
case 76:
keyString = "L";
break;
case 77:
keyString = "M";
break;
case 78:
keyString = "N";
break;
case 79:
keyString = "O";
break;
case 80:
keyString = "P";
break;
case 81:
keyString = "Q";
break;
case 82:
keyString = "R";
break;
case 83:
keyString = "S";
break;
case 84:
keyString = "T";
break;
case 85:
keyString = "U";
break;
case 86:
keyString = "V";
break;
case 87:
keyString = "W";
break;
case 88:
keyString = "X";
break;
case 89:
keyString = "Y";
break;
case 90:
keyString = "Z";
break;
case 91:
keyString = "Windows Left";
break;
case 92:
keyString = "Windows Right";
break;
case 93:
keyString = "Application";
break;
case 95:
keyString = "Sleep";
break;
case 96:
keyString = "NumPad 0";
break;
case 97:
keyString = "NumPad 1";
break;
case 98:
keyString = "NumPad 2";
break;
case 99:
keyString = "NumPad 3";
break;
case 100:
keyString = "NumPad 4";
break;
case 101:
keyString = "NumPad 5";
break;
case 102:
keyString = "NumPad 6";
break;
case 103:
keyString = "NumPad 7";
break;
case 104:
keyString = "NumPad 8";
break;
case 105:
keyString = "NumPad 9";
break;
case 106:
keyString = "NumPad *";
break;
case 107:
keyString = "NumPad +";
break;
case 108:
keyString = "NumPad .";
break;
case 109:
keyString = "NumPad -";
break;
case 110:
keyString = "NumPad ,";
break;
case 111:
keyString = "NumPad /";
break;
case 112:
keyString = "F1";
break;
case 113:
keyString = "F2";
break;
case 114:
keyString = "F3";
break;
case 115:
keyString = "F4";
break;
case 116:
keyString = "F5";
break;
case 117:
keyString = "F6";
break;
case 118:
keyString = "F7";
break;
case 119:
keyString = "F8";
break;
case 120:
keyString = "F9";
break;
case 121:
keyString = "F10";
break;
case 122:
keyString = "F11";
break;
case 123:
keyString = "F12";
break;
case 124:
keyString = "F13";
break;
case 125:
keyString = "F14";
break;
case 126:
keyString = "F15";
break;
case 127:
keyString = "F16";
break;
case 128:
keyString = "F17";
break;
case 129:
keyString = "F18";
break;
case 130:
keyString = "F19";
break;
case 131:
keyString = "F20";
break;
case 132:
keyString = "F21";
break;
case 133:
keyString = "F22";
break;
case 134:
keyString = "F23";
break;
case 135:
keyString = "F24";
break;
case 144:
keyString = "Num lock";
break;
case 145:
keyString = "Scroll";
break;
case 160:
keyString = "Shift Left";
break;
case 161:
keyString = "Shift Right";
break;
case 162:
keyString = "Ctrl Left";
break;
case 163:
keyString = "Ctrl Right";
break;
case 164:
keyString = "Menu Left";
break;
case 165:
keyString = "Menu Right";
break;
default:
break;
}
 
return keyString;
}
}
}
/trunk/WingMan/WingMan.csproj
@@ -11,6 +11,8 @@
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -69,6 +71,8 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Communication\TrackedClient.cs" />
<Compile Include="Communication\TrackedClients.cs" />
<Compile Include="Lobby\LobbyMessageReceivedEventArgs.cs" />
<Compile Include="Lobby\LobbyMessageSynchronizer.cs" />
<Compile Include="MouseKey\MouseKeyBindingExchange.cs" />
@@ -80,7 +84,8 @@
<Compile Include="MouseKey\MouseKeyBindingsExchange.cs" />
<Compile Include="Lobby\LobbyMessage.cs" />
<Compile Include="Communication\MQTTCommunicationType.cs" />
<Compile Include="Utilities.cs" />
<Compile Include="Utilities\AES.cs" />
<Compile Include="Utilities\KeyConversion.cs" />
<Compile Include="WingManForm.cs">
<SubType>Form</SubType>
</Compile>
/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)
{
}
}
}