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:
@@ -164,6 +164,10 @@ public static class AppBootstrapper
|
||||
services.AddSingleton<AiPlanningService>();
|
||||
|
||||
// ── Sync (optional – nur wenn Server konfiguriert) ────────────────────
|
||||
var syncSettings = new SyncSettingsService(appData);
|
||||
services.AddSingleton(syncSettings);
|
||||
services.AddSingleton(_ => new SyncAuthService(new HttpClient()));
|
||||
|
||||
services.AddSingleton(_ => new EventQueue(queuePath));
|
||||
services.AddSingleton(sp => new ConflictResolver(sp.GetRequiredService<EventQueue>()));
|
||||
services.AddSingleton<byte[]>(_ =>
|
||||
@@ -173,18 +177,18 @@ public static class AppBootstrapper
|
||||
return key;
|
||||
});
|
||||
|
||||
var serverUrl = LoadServerUrl(appData);
|
||||
var serverUrl = syncSettings.ServerUrl;
|
||||
var deviceId = LoadOrCreateDeviceId(appData);
|
||||
|
||||
if (!string.IsNullOrEmpty(serverUrl))
|
||||
{
|
||||
services.AddSingleton(sp => new EventApplier(
|
||||
sp.GetRequiredService<LiteDbContext>(), sp.GetRequiredService<byte[]>(),
|
||||
BuildHttp(serverUrl, appData)));
|
||||
BuildHttp(serverUrl, syncSettings)));
|
||||
services.AddSingleton(sp => new SyncEventPublisher(
|
||||
sp.GetRequiredService<EventQueue>(), deviceId, sp.GetRequiredService<byte[]>()));
|
||||
services.AddSingleton(sp => new AttachmentSyncer(
|
||||
sp.GetRequiredService<LiteDbContext>(), BuildHttp(serverUrl, appData),
|
||||
sp.GetRequiredService<LiteDbContext>(), BuildHttp(serverUrl, syncSettings),
|
||||
sp.GetRequiredService<byte[]>()));
|
||||
|
||||
services.AddSingleton<SyncEngine>(sp => new SyncEngine(
|
||||
@@ -192,7 +196,7 @@ public static class AppBootstrapper
|
||||
sp.GetRequiredService<ConflictResolver>(),
|
||||
sp.GetRequiredService<EventApplier>(),
|
||||
sp.GetRequiredService<AttachmentSyncer>(),
|
||||
BuildHttp(serverUrl, appData),
|
||||
BuildHttp(serverUrl, syncSettings),
|
||||
new SyncConfig
|
||||
{
|
||||
ServerUrl = serverUrl,
|
||||
@@ -202,7 +206,7 @@ public static class AppBootstrapper
|
||||
}));
|
||||
|
||||
services.AddSingleton<SnapshotService>(sp => new SnapshotService(
|
||||
BuildHttp(serverUrl, appData),
|
||||
BuildHttp(serverUrl, syncSettings),
|
||||
sp.GetRequiredService<LiteDbContext>(),
|
||||
sp.GetRequiredService<byte[]>(),
|
||||
DeviceType.Desktop, DbPath, keyPath));
|
||||
@@ -247,25 +251,16 @@ public static class AppBootstrapper
|
||||
|
||||
// ── Hilfsmethoden ─────────────────────────────────────────────────────────
|
||||
|
||||
private static HttpClient BuildHttp(string url, string appData)
|
||||
private static HttpClient BuildHttp(string url, SyncSettingsService syncSettings)
|
||||
{
|
||||
var http = new HttpClient { BaseAddress = new Uri(url) };
|
||||
var tokenPath = Path.Combine(appData, "auth.token");
|
||||
if (File.Exists(tokenPath))
|
||||
var token = syncSettings.GetToken();
|
||||
if (token is not null)
|
||||
http.DefaultRequestHeaders.Authorization =
|
||||
new System.Net.Http.Headers.AuthenticationHeaderValue(
|
||||
"Bearer", File.ReadAllText(tokenPath).Trim());
|
||||
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
||||
return http;
|
||||
}
|
||||
|
||||
public static string LoadServerUrl(string? path = null) =>
|
||||
File.Exists(Path.Combine(path ?? AppDataPath, "server.txt"))
|
||||
? File.ReadAllText(Path.Combine(path ?? AppDataPath, "server.txt")).Trim()
|
||||
: "";
|
||||
|
||||
public static void SaveServerUrl(string url) =>
|
||||
File.WriteAllText(Path.Combine(AppDataPath, "server.txt"), url);
|
||||
|
||||
private static string LoadOrCreateDeviceId(string appData)
|
||||
{
|
||||
var p = Path.Combine(appData, "device.id");
|
||||
|
||||
Reference in New Issue
Block a user