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;
}
}
}