Baustein 8: Settings-Tab "Synchronisation" (Kapitel 10)
Neuer Tab in den Einstellungen: Server-URL, Login, Verbindungstest, Logout. - Neu SyncSettingsService (Muster AiSettingsService): Token AES-256-verschluesselt ueber SyncCrypto mit eigenem, rein lokalem Schluessel - ersetzt die bisherigen Klartext-Helfer AppBootstrapper.LoadServerUrl/SaveServerUrl und die unverschluesselte auth.token-Datei - Neu SyncAuthService fuer den Login-HTTP-Aufruf gegen /api/auth/login und den Verbindungstest (unterscheidet erreichbar & angemeldet / erreichbar aber nicht angemeldet / nicht erreichbar) - Speichern/Anmelden startet die App neu (AppBootstrapper. RestartApplication, gleiches Muster wie bei DB-Passwort/AppLock- Aenderungen) - SyncEngine/SnapshotService werden nur einmalig beim Start registriert, es gibt keinen Live-Re-Registrierungspfad Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
using LehrerApp.Sync.Crypto;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace LehrerApp.Desktop.Services;
|
||||
|
||||
internal class SyncSettingsConfig
|
||||
{
|
||||
public string ServerUrl { get; set; } = "";
|
||||
public string Username { get; set; } = "";
|
||||
public string? EncryptedToken { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ersetzt die früheren Klartext-Helfer (<c>AppBootstrapper.LoadServerUrl</c>/<c>SaveServerUrl</c>,
|
||||
/// unverschlüsselte <c>auth.token</c>-Datei). Token liegt wie beim KI-Backend-Token (siehe
|
||||
/// <see cref="AiSettingsService"/>) AES-256-verschlüsselt über <see cref="SyncCrypto"/>, mit
|
||||
/// eigenem, rein lokalem Schlüssel — nicht zu verwechseln mit dem in <c>AppBootstrapper</c>
|
||||
/// separat verwalteten Sync-Schlüssel (<c>sync.key</c>), der die Ereignis-Payloads zwischen den
|
||||
/// gepaarten Geräten verschlüsselt.
|
||||
/// </summary>
|
||||
public class SyncSettingsService
|
||||
{
|
||||
private readonly string _configPath;
|
||||
private readonly string _keyPath;
|
||||
private readonly byte[] _tokenKey;
|
||||
private SyncSettingsConfig _config;
|
||||
|
||||
public string ServerUrl => _config.ServerUrl;
|
||||
public string Username => _config.Username;
|
||||
public bool IsLoggedIn => _config.EncryptedToken is not null;
|
||||
|
||||
public SyncSettingsService(string appDataPath)
|
||||
{
|
||||
_configPath = Path.Combine(appDataPath, "sync-settings.json");
|
||||
_keyPath = Path.Combine(appDataPath, "sync-token.key");
|
||||
_tokenKey = SyncCrypto.LoadKey(_keyPath) ?? GenerateAndSaveKey();
|
||||
_config = Load();
|
||||
}
|
||||
|
||||
public void SetServerUrl(string url)
|
||||
{
|
||||
_config.ServerUrl = url.Trim();
|
||||
Save();
|
||||
}
|
||||
|
||||
public void SetCredentialsAndToken(string username, string token)
|
||||
{
|
||||
_config.Username = username;
|
||||
_config.EncryptedToken = SyncCrypto.EncryptObject(token, _tokenKey);
|
||||
Save();
|
||||
}
|
||||
|
||||
public string? GetToken() =>
|
||||
_config.EncryptedToken is null ? null : SyncCrypto.DecryptObject<string>(_config.EncryptedToken, _tokenKey);
|
||||
|
||||
public void Logout()
|
||||
{
|
||||
_config.EncryptedToken = null;
|
||||
Save();
|
||||
}
|
||||
|
||||
private byte[] GenerateAndSaveKey()
|
||||
{
|
||||
var key = SyncCrypto.GenerateKey();
|
||||
SyncCrypto.SaveKey(key, _keyPath);
|
||||
return key;
|
||||
}
|
||||
|
||||
private void Save() => File.WriteAllText(_configPath, JsonSerializer.Serialize(_config));
|
||||
|
||||
private SyncSettingsConfig Load()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(_configPath))
|
||||
return JsonSerializer.Deserialize<SyncSettingsConfig>(File.ReadAllText(_configPath))
|
||||
?? new SyncSettingsConfig();
|
||||
}
|
||||
catch { /* beschädigte Konfiguration -> Standardwert */ }
|
||||
return new SyncSettingsConfig();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user