using System; using System.Linq; using Deploymentcenter.Client; using PolyTrader.Core; using PolyTrader.Core.Security; using PolyTraderSharp.Models; namespace PolyTrader.App.Avalonia.Licensing { /// /// Kopflose Lizenzverwaltung von der Kommandozeile aus (D-2), nach der Konvention aus /// LICENSE_INTEGRATION_GUIDE §4: --license-status, --license-set-key, /// --license-deactivate. Diese Schalter baut die Anwendung selbst, das SDK bringt nur die /// Bausteine mit. Läuft VOR dem Host-Aufbau und beendet den Prozess über den Rückgabewert. /// internal static class LicenseCli { /// Liefert true, wenn einer der Lizenz-Schalter erkannt und abgearbeitet wurde. public static bool TryHandle(string[] args, out int exitCode) { exitCode = 0; if (args.Any(a => string.Equals(a, "--license-status", StringComparison.OrdinalIgnoreCase))) { exitCode = Status(); return true; } int setIdx = Array.FindIndex(args, a => string.Equals(a, "--license-set-key", StringComparison.OrdinalIgnoreCase)); if (setIdx >= 0) { string? key = setIdx + 1 < args.Length ? args[setIdx + 1] : null; exitCode = SetKey(key); return true; } if (args.Any(a => string.Equals(a, "--license-deactivate", StringComparison.OrdinalIgnoreCase))) { exitCode = Deactivate(); return true; } return false; } private static int Status() { var options = Program.LoadDeploymentcenterOptions(); var hw = HardwareId.GetHardwareId(options.ProjectSlug); var cached = LicenseClient.TryGetCachedState(options.ProjectSlug); Console.WriteLine($"HWID v2: {hw.HardwareId} ({hw.HwidSource})"); Console.WriteLine($"Produkt: {options.ProjectSlug}"); Console.WriteLine($"Server: {(string.IsNullOrWhiteSpace(options.BaseUrl) ? "(keine URL konfiguriert)" : options.BaseUrl)}"); Console.WriteLine($"Cache: {(cached == null ? "leer" : cached.Status)}"); if (cached != null && cached.CacheExpiresAt > 0) { var until = DateTimeOffset.FromUnixTimeSeconds(cached.CacheExpiresAt); Console.WriteLine($"Offline noch bis: {until:u}"); } var settings = ServerSettings.Load("server_settings.xml"); Console.WriteLine($"Gespeicherter Schlüssel (server_settings.xml): {(string.IsNullOrWhiteSpace(settings.LicenseKey) ? "keiner" : settings.LicenseKeyStatus)}"); return 0; } private static int SetKey(string? key) { if (string.IsNullOrWhiteSpace(key)) { Console.Error.WriteLine("Fehler: --license-set-key erwartet den Schlüssel als nächstes Argument."); return 1; } var options = Program.LoadDeploymentcenterOptions(); if (string.IsNullOrWhiteSpace(options.BaseUrl)) { Console.Error.WriteLine("Fehler: Keine Deploymentcenter-URL konfiguriert (appsettings.json: Deploymentcenter:BaseUrl)."); return 1; } LicenseClient.DefaultAppVersion = BuildInfo.Version; var client = new LicenseClient(); LicenseValidationResult result = client .ValidateAsync(options.ProjectSlug, key.Trim(), options.BaseUrl, BuildInfo.Version) .GetAwaiter().GetResult(); Console.WriteLine($"{result.Status}: {result.Message}"); if (!result.IsValid) { return 1; } const string settingsPath = "server_settings.xml"; var settings = ServerSettings.Load(settingsPath); settings.LicenseKey = SecretProtection.Protect(key.Trim()); settings.Save(settingsPath); Console.WriteLine($"Lizenz gültig und in {settingsPath} gespeichert " + $"({(SecretProtection.IsEncrypted(settings.LicenseKey) ? "verschlüsselt" : "Klartext")})."); return 0; } private static int Deactivate() { var options = Program.LoadDeploymentcenterOptions(); var settings = ServerSettings.Load("server_settings.xml"); string key; try { key = SecretProtection.Unprotect(settings.LicenseKey); } catch (Exception ex) { Console.Error.WriteLine($"Fehler: gespeicherter Schlüssel nicht lesbar: {ex.Message}"); return 1; } if (string.IsNullOrWhiteSpace(key)) { Console.Error.WriteLine("Fehler: kein Lizenzschlüssel hinterlegt."); return 1; } // Die Deaktivierung gibt einen Aktivierungsplatz frei und ist deshalb geschützt - der // shared_key gehört auf den Administrationsrechner, nicht in die ausgelieferte // Anwendung (siehe LICENSE_INTEGRATION_GUIDE). Ohne ihn: klarer Hinweis statt Versuch. string? sharedKey = Environment.GetEnvironmentVariable("DC_SHARED_KEY"); if (string.IsNullOrWhiteSpace(sharedKey)) { Console.Error.WriteLine("Fehler: DC_SHARED_KEY nicht gesetzt. Die Deaktivierung braucht den " + "administrativen Shared Key - alternativ im Deploymentcenter-WebUI unter " + "der Hardware-Liste auf „Freigeben\" klicken."); return 1; } var client = new LicenseClient(); bool ok = client.DeactivateAsync(options.ProjectSlug, key, options.BaseUrl, sharedKey) .GetAwaiter().GetResult(); Console.WriteLine(ok ? "Aktivierung freigegeben." : "Deaktivierung fehlgeschlagen."); return ok ? 0 : 1; } } }