Watchdog-Heartbeat + LicenseLabrador-Lizenzpruefung eingebunden

Slices W-A/W-B/W-C und L-A aus UMSETZUNGSPLAN-Watchdog-LicenseLabrador-Integration.

Watchdog (Dead-Man's-Switch, externer Server):
- WatchdogHeartbeatService als BackgroundService + DI-Singleton; jeder Sendeversuch
  gekapselt, ein Ausfall des Watchdogs beeintraechtigt PolyTrader nie.
- Eigene Implementierung statt Test-Client des Fremdprojekts: TLS-Pruefung bleibt
  aktiv, http:// nur fuer localhost (Agent-Token nicht im Klartext ins Netz).
- Status aus dem App-Log abgeleitet (Error mit 5-Minuten-Sticky-Fenster, entprellt),
  Lifecycle-Events started/stopping.
- Konfiguration in ServerSettings; Agent-Token [Browsable(false)] mit maskierter
  Eingabe + Statusanzeige, bei gesetztem Master-Key verschluesselt (enc:v1:).

Lizenz (LicenseLabrador, Ed25519):
- LicenseGate.RunStartupGate prueft beim Start; bei ungueltiger Lizenz wird die
  Modulliste leer gebaut, sodass nur die Core-Shell (Terminal/Einstellungen)
  startet. Bewusst kein Environment.Exit - ein Trading-Bot darf nicht mitten im
  Lauf hart sterben. TamperSuspected gilt als nicht nutzbar.
- LicenseDialog (partial + .Designer.cs) fuer Start- und Verwalten-Modus, mit
  Hardware-ID zum Kopieren; Smoke-UI konstruiert beide Modi headless.
- Master-Key wird jetzt VOR dem Host-Build geladen, da auch der Lizenzschluessel
  entschluesselt werden muss; derselbe TerminalLogger wird als Singleton
  weitergereicht, damit die Startmeldungen im Terminal-Fenster erscheinen.

Der Lizenz-SDK-Client wird per Cross-Repo-Projektreferenz auf
..\..\LicenseLabrador eingebunden, damit SDK-Fixes ohne Kopie einfliessen.

484 Zeilen Tests fuer den Heartbeat; Suite gruen (438 Tests).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-08-04 09:04:14 +02:00
co-authored by Claude Opus 5
parent bb103a578a
commit ca750a06f5
11 changed files with 2122 additions and 8 deletions
+157
View File
@@ -0,0 +1,157 @@
namespace PolyTraderSharp.Ui
{
partial class LicenseDialog
{
/// <summary>Erforderliche Designer-Variable.</summary>
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Vom Windows Form-Designer generierter Code
private void InitializeComponent()
{
lblHeadline = new System.Windows.Forms.Label();
lblStatus = new System.Windows.Forms.Label();
lblHwCaption = new System.Windows.Forms.Label();
txtHardwareId = new System.Windows.Forms.TextBox();
btnCopyHwId = new System.Windows.Forms.Button();
lblKeyCaption = new System.Windows.Forms.Label();
txtKey = new System.Windows.Forms.TextBox();
btnValidate = new System.Windows.Forms.Button();
lblResult = new System.Windows.Forms.Label();
btnLimited = new System.Windows.Forms.Button();
SuspendLayout();
//
// lblHeadline
//
lblHeadline.AutoSize = true;
lblHeadline.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Bold);
lblHeadline.Location = new System.Drawing.Point(16, 14);
lblHeadline.Name = "lblHeadline";
lblHeadline.Size = new System.Drawing.Size(316, 17);
lblHeadline.TabIndex = 0;
lblHeadline.Text = "Für PolyTrader wird eine gültige Lizenz benötigt.";
//
// lblStatus
//
lblStatus.Location = new System.Drawing.Point(16, 40);
lblStatus.Name = "lblStatus";
lblStatus.Size = new System.Drawing.Size(504, 34);
lblStatus.TabIndex = 1;
lblStatus.Text = "Status:";
//
// lblHwCaption
//
lblHwCaption.AutoSize = true;
lblHwCaption.Location = new System.Drawing.Point(16, 82);
lblHwCaption.Name = "lblHwCaption";
lblHwCaption.Size = new System.Drawing.Size(214, 15);
lblHwCaption.TabIndex = 2;
lblHwCaption.Text = "Hardware-ID dieses Rechners (für die Aktivierung):";
//
// txtHardwareId
//
txtHardwareId.Location = new System.Drawing.Point(16, 100);
txtHardwareId.Name = "txtHardwareId";
txtHardwareId.ReadOnly = true;
txtHardwareId.Size = new System.Drawing.Size(400, 23);
txtHardwareId.TabIndex = 3;
//
// btnCopyHwId
//
btnCopyHwId.Location = new System.Drawing.Point(424, 99);
btnCopyHwId.Name = "btnCopyHwId";
btnCopyHwId.Size = new System.Drawing.Size(96, 25);
btnCopyHwId.TabIndex = 4;
btnCopyHwId.Text = "Kopieren";
btnCopyHwId.UseVisualStyleBackColor = true;
//
// lblKeyCaption
//
lblKeyCaption.AutoSize = true;
lblKeyCaption.Location = new System.Drawing.Point(16, 136);
lblKeyCaption.Name = "lblKeyCaption";
lblKeyCaption.Size = new System.Drawing.Size(96, 15);
lblKeyCaption.TabIndex = 5;
lblKeyCaption.Text = "Lizenzschlüssel:";
//
// txtKey
//
txtKey.CharacterCasing = System.Windows.Forms.CharacterCasing.Upper;
txtKey.Location = new System.Drawing.Point(16, 154);
txtKey.Name = "txtKey";
txtKey.Size = new System.Drawing.Size(400, 23);
txtKey.TabIndex = 6;
//
// btnValidate
//
btnValidate.Location = new System.Drawing.Point(424, 153);
btnValidate.Name = "btnValidate";
btnValidate.Size = new System.Drawing.Size(96, 25);
btnValidate.TabIndex = 7;
btnValidate.Text = "Validieren";
btnValidate.UseVisualStyleBackColor = true;
//
// lblResult
//
lblResult.Location = new System.Drawing.Point(16, 190);
lblResult.Name = "lblResult";
lblResult.Size = new System.Drawing.Size(504, 40);
lblResult.TabIndex = 8;
//
// btnLimited
//
btnLimited.Location = new System.Drawing.Point(16, 236);
btnLimited.Name = "btnLimited";
btnLimited.Size = new System.Drawing.Size(230, 27);
btnLimited.TabIndex = 9;
btnLimited.Text = "Ohne Lizenz starten (eingeschränkt)";
btnLimited.UseVisualStyleBackColor = true;
//
// LicenseDialog
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(536, 278);
Controls.Add(btnLimited);
Controls.Add(lblResult);
Controls.Add(btnValidate);
Controls.Add(txtKey);
Controls.Add(lblKeyCaption);
Controls.Add(btnCopyHwId);
Controls.Add(txtHardwareId);
Controls.Add(lblHwCaption);
Controls.Add(lblStatus);
Controls.Add(lblHeadline);
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
Name = "LicenseDialog";
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
Text = "PolyTrader Lizenz";
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.Label lblHeadline;
private System.Windows.Forms.Label lblStatus;
private System.Windows.Forms.Label lblHwCaption;
private System.Windows.Forms.TextBox txtHardwareId;
private System.Windows.Forms.Button btnCopyHwId;
private System.Windows.Forms.Label lblKeyCaption;
private System.Windows.Forms.TextBox txtKey;
private System.Windows.Forms.Button btnValidate;
private System.Windows.Forms.Label lblResult;
private System.Windows.Forms.Button btnLimited;
}
}