UI: Master-Key-Button (Settings, via Designer) + UI-Designer-WIP + Steuer-PDF

- Settings: neuer Toolbar-Button 'Master-Key erzeugen' (Tab General Settings, via Designer).
  Erzeugt zufaelligen 32-Byte-AES-Key -> master.key (gitignored), nur aktiv wenn KEIN Key
  existiert (Env-Var oder Datei), Lockout-Schutz + Backup-Warnung, danach deaktiviert.
- Einbezogen: laufende Designer-Umstrukturierung (SettingsView/LauncherForm: Button-Bilder
  aus Properties.Resources statt eingebettet; dgv_accountlist im Launcher; DashboardView.resx).
- docs/steuer: US-CPA-Fragebogen als PDF.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-15 09:27:34 +02:00
co-authored by Claude Opus 4.8
parent 36c89a6acf
commit 4df07bd3d2
6 changed files with 427 additions and 147 deletions
+53
View File
@@ -1,6 +1,8 @@
using System;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Windows.Forms;
using PolyTrader.Core.Persistence;
using PolyTraderSharp.Models;
@@ -33,6 +35,8 @@ namespace PolyTraderSharp.Ui.Views
btn_save.Click += (_, _) => Save();
btn_loadsettings.Click += (_, _) => Reload();
btnGenMasterKey.Click += (_, _) => GenerateMasterKey();
UpdateMasterKeyButtonState();
btnAccNew.Click += (_, _) => AddAccount();
btnAccDelete.Click += (_, _) => DeleteAccount();
@@ -129,5 +133,54 @@ namespace PolyTraderSharp.Ui.Views
_state?.Accounts.AddOrUpdate(acc.AccountId, acc, (_, _) => acc);
dgvAccounts.Refresh();
}
// ===== Master-Key (at-rest-Verschlüsselung, F1) =====
/// <summary>Pfad der Master-Key-Datei identisch zu Program.cs (App-Ordner, gitignored).</summary>
private static string MasterKeyFilePath => Path.Combine(AppContext.BaseDirectory, "master.key");
/// <summary>Existiert bereits ein Master-Key (Umgebungsvariable ODER Datei)?</summary>
private static bool MasterKeyExists() =>
!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("POLYTRADER_MASTER_KEY"))
|| File.Exists(MasterKeyFilePath);
/// <summary>Button nur aktiv, solange KEIN Master-Key existiert (Überschreiben = Lockout-Gefahr).</summary>
private void UpdateMasterKeyButtonState() => btnGenMasterKey.Enabled = !MasterKeyExists();
private void GenerateMasterKey()
{
// Sicherheitsnetz gegen Race/Doppelklick: einen bestehenden Key NIEMALS überschreiben.
if (MasterKeyExists())
{
MessageBox.Show(
"Es existiert bereits ein Master-Key Erzeugung abgebrochen. Ein Überschreiben würde den " +
"Zugriff auf bereits verschlüsselte Wallet-Keys unwiederbringlich zerstören.",
"Master-Key vorhanden", MessageBoxButtons.OK, MessageBoxIcon.Warning);
UpdateMasterKeyButtonState();
return;
}
try
{
byte[] keyBytes = RandomNumberGenerator.GetBytes(32); // 256-Bit-Schlüssel
File.WriteAllText(MasterKeyFilePath, Convert.ToBase64String(keyBytes));
_logger?.Info("🔐 Master-Key erzeugt und in master.key gespeichert. At-rest-Verschlüsselung wird beim nächsten Start aktiv.");
MessageBox.Show(
"Ein zufälliger 32-Byte-Master-Key wurde erzeugt und in der Datei 'master.key' (App-Ordner, gitignored) gespeichert.\n\n" +
"WICHTIG:\n" +
"• Sichere diese Datei SOFORT separat und sicher (z. B. Passwort-Manager / Offline-Backup).\n" +
"• Master-Key-Verlust = KEIN Zugriff mehr auf die verschlüsselten Wallet-Keys!\n" +
"• Die Verschlüsselung der Account-Credentials wird beim nächsten Programmstart aktiv.",
"Master-Key erzeugt", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"Fehler beim Erzeugen des Master-Keys: {ex.Message}",
"Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
UpdateMasterKeyButtonState(); // nach Erzeugung deaktivieren
}
}
}