2026-06-01 20:49:07 +02:00
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
using System.IO;
|
2026-06-26 14:27:56 +02:00
|
|
|
using System.Security.Cryptography;
|
|
|
|
|
using System.Text;
|
2026-06-01 20:49:07 +02:00
|
|
|
|
|
|
|
|
namespace ITNexusAgent.Models;
|
|
|
|
|
|
|
|
|
|
public class AgentConfig
|
|
|
|
|
{
|
2026-06-26 14:27:56 +02:00
|
|
|
private const string ProtectedPrefix = "dpapi:";
|
|
|
|
|
|
|
|
|
|
[JsonIgnore]
|
2026-06-01 20:49:07 +02:00
|
|
|
public string ServerUrl { get; set; } = "";
|
|
|
|
|
|
2026-06-26 14:27:56 +02:00
|
|
|
// Im Speicher immer Klartext — nur auf der Platte (config.json) liegt der verschlüsselte Wert.
|
|
|
|
|
[JsonIgnore]
|
2026-06-01 20:49:07 +02:00
|
|
|
public string AgentKey { get; set; } = "";
|
|
|
|
|
|
2026-06-26 14:27:56 +02:00
|
|
|
private class RawConfig
|
|
|
|
|
{
|
|
|
|
|
[JsonProperty("server_url")] public string ServerUrl { get; set; } = "";
|
|
|
|
|
[JsonProperty("agent_key")] public string AgentKey { get; set; } = "";
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-01 20:49:07 +02:00
|
|
|
public static AgentConfig Load(string path)
|
|
|
|
|
{
|
|
|
|
|
var json = File.ReadAllText(path);
|
2026-06-26 14:27:56 +02:00
|
|
|
var raw = JsonConvert.DeserializeObject<RawConfig>(json)
|
2026-06-01 20:49:07 +02:00
|
|
|
?? throw new Exception("Ungültige config.json");
|
2026-06-26 14:27:56 +02:00
|
|
|
|
|
|
|
|
return new AgentConfig
|
|
|
|
|
{
|
|
|
|
|
ServerUrl = raw.ServerUrl,
|
|
|
|
|
AgentKey = Unprotect(raw.AgentKey),
|
|
|
|
|
};
|
2026-06-01 20:49:07 +02:00
|
|
|
}
|
2026-06-26 13:50:02 +02:00
|
|
|
|
2026-06-26 14:27:56 +02:00
|
|
|
// 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.
|
2026-06-26 13:50:02 +02:00
|
|
|
public void Save(string path)
|
|
|
|
|
{
|
2026-06-26 14:27:56 +02:00
|
|
|
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
|
|
|
|
|
}
|
2026-06-26 13:50:02 +02:00
|
|
|
}
|
2026-06-01 20:49:07 +02:00
|
|
|
}
|