69 lines
3.5 KiB
C#
69 lines
3.5 KiB
C#
using System.IO;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Windows;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows.Interop;
|
|
using QSafe.Core;
|
|
|
|
namespace QSafe.Desktop;
|
|
|
|
public partial class App : Application
|
|
{
|
|
private Mutex? single;
|
|
private bool ownsMutex;
|
|
protected override void OnStartup(StartupEventArgs e)
|
|
{
|
|
base.OnStartup(e);
|
|
bool smoke = e.Args.Contains("--smoke-test");
|
|
bool demo = smoke || e.Args.Contains("--demo");
|
|
var path = demo ? Path.Combine(Path.GetTempPath(), "QSafe-Demo", Guid.NewGuid().ToString("N")) : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Kusoft", "QSafe");
|
|
single = new Mutex(false, "Local\\QSafe-" + Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(path)))[..20]);
|
|
try { ownsMutex = single.WaitOne(0); } catch (AbandonedMutexException) { ownsMutex = true; }
|
|
if (!ownsMutex) { MessageBox.Show("QSafe уже запущен. Откройте существующее окно.", "QSafe"); Shutdown(); return; }
|
|
try
|
|
{
|
|
var store = new LocalStore(path);
|
|
int connectionIndex = Array.IndexOf(e.Args, "--connection");
|
|
if (!demo && connectionIndex >= 0)
|
|
{
|
|
if (connectionIndex + 1 >= e.Args.Length) throw new InvalidDataException("Укажите личный файл локального подключения.");
|
|
store.Configure(Connection.Parse(LocalStore.ReadBounded(e.Args[connectionIndex + 1], 65536)));
|
|
}
|
|
if (!demo && e.Args.Contains("--configure-only")) { Shutdown(); return; }
|
|
MainWindow = new MainWindow(store, demo); MainWindow.Show();
|
|
if (smoke)
|
|
{
|
|
var timer = new System.Windows.Threading.DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
|
|
timer.Tick += (_, _) => { timer.Stop(); MainWindow.Close(); }; timer.Start();
|
|
}
|
|
}
|
|
catch { MessageBox.Show("Не удалось открыть локальное хранилище или защищённые настройки. Данные не изменены. Проверьте доступ к папке %LOCALAPPDATA%\\Kusoft\\QSafe.", "QSafe", MessageBoxButton.OK, MessageBoxImage.Error); Shutdown(1); }
|
|
}
|
|
protected override void OnExit(ExitEventArgs e)
|
|
{
|
|
if (ownsMutex) single?.ReleaseMutex(); single?.Dispose(); base.OnExit(e);
|
|
}
|
|
}
|
|
|
|
public static class NativeWindow
|
|
{
|
|
[DllImport("dwmapi.dll")] private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attribute, ref int value, int size);
|
|
[DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool SetWindowDisplayAffinity(IntPtr hwnd, uint affinity);
|
|
public static void Style(Window window)
|
|
{
|
|
window.SourceInitialized += (_, _) =>
|
|
{
|
|
var handle = new WindowInteropHelper(window).Handle; int dark = 1;
|
|
DwmSetWindowAttribute(handle, 20, ref dark, sizeof(int));
|
|
// Demo contains only synthetic credentials and can be captured for interface review.
|
|
SetProtection(window, !(Application.Current.MainWindow is MainWindow main && main.IsDemo));
|
|
};
|
|
}
|
|
public static void SetProtection(Window window, bool enabled)
|
|
{
|
|
var handle = new WindowInteropHelper(window).Handle;
|
|
if (handle != IntPtr.Zero) SetWindowDisplayAffinity(handle, enabled ? 0x11u : 0u);
|
|
}
|
|
}
|