using Newtonsoft.Json; using System.IO; using System.Security.Cryptography; using System.Text; namespace ITNexusAgent.Models; public class AgentConfig { private const string ProtectedPrefix = "dpapi:"; [JsonIgnore] public string ServerUrl { get; set; } = ""; // Im Speicher immer Klartext — nur auf der Platte (config.json) liegt der verschlüsselte Wert. [JsonIgnore] public string AgentKey { get; set; } = ""; private class RawConfig { [JsonProperty("server_url")] public string ServerUrl { get; set; } = ""; [JsonProperty("agent_key")] public string AgentKey { get; set; } = ""; } public static AgentConfig Load(string path) { var json = File.ReadAllText(path); var raw = JsonConvert.DeserializeObject(json) ?? throw new Exception("Ungültige config.json"); return new AgentConfig { ServerUrl = raw.ServerUrl, AgentKey = Unprotect(raw.AgentKey), }; } // Verschlüsselt den Key per Windows DPAPI (LocalMachine-Scope) bevor er auf die Platte geschrieben // wird — ein Klartext-Auslesen von config.json bringt einem Angreifer dann nichts mehr, da der Wert // nur vom SYSTEM-Konto auf genau diesem Rechner wieder entschlüsselt werden kann. public void Save(string path) { var raw = new RawConfig { ServerUrl = ServerUrl, AgentKey = Protect(AgentKey) }; File.WriteAllText(path, JsonConvert.SerializeObject(raw, Formatting.Indented)); } private static string Protect(string plaintext) { if (string.IsNullOrEmpty(plaintext)) return plaintext; var bytes = ProtectedData.Protect(Encoding.UTF8.GetBytes(plaintext), null, DataProtectionScope.LocalMachine); return ProtectedPrefix + Convert.ToBase64String(bytes); } // Erkennt das alte Klartext-Format (z.B. frisch aus dem Installer-Template) und lässt es unverändert // durch — wird beim nächsten Save() automatisch verschlüsselt persistiert. private static string Unprotect(string stored) { if (string.IsNullOrEmpty(stored) || !stored.StartsWith(ProtectedPrefix)) return stored; try { var bytes = ProtectedData.Unprotect(Convert.FromBase64String(stored[ProtectedPrefix.Length..]), null, DataProtectionScope.LocalMachine); return Encoding.UTF8.GetString(bytes); } catch { return stored; // Korrupt/falsche Maschine → unverändert zurückgeben statt Crash } } }