feat: Warnung + selbstverwalteter Wiederherstellungscode für verlorenen Sync-Schlüssel
Der Sync-Schlüssel verlässt nie den Server im Klartext - verliert das einzige Gerät sync.key, erzeugte AppBootstrapper bisher stillschweigend einen neuen, unabhängigen Schlüssel, ohne dass der Nutzer etwas davon merkt. Bereits synchronisierte Server-Daten werden dadurch dauerhaft unlesbar. AppBootstrapper erkennt jetzt, ob ein fehlender Schlüssel bei einem bereits eingeloggten Gerät auftritt (SyncKeyStatus) - SettingsViewModel zeigt dafür ein Warnbanner im Synchronisation-Tab mit der Empfehlung, im Zweifel über ein noch intaktes zweites Gerät neu zu koppeln. Zusätzlich ein komplett offline laufender, selbstverwalteter Wiederherstellungscode (kein neuer dauerhafter Server-Speicher für ein sicherheitsrelevantes Geheimnis): SyncCrypto bekommt einen neuen, vom Pairing-Code kryptografisch unabhängigen Recovery-Code (120 Bit, Base32), mit dem der Sync-Schlüssel lokal verschlüsselt und als Datei durch den Nutzer selbst gesichert werden kann. Neuer SyncKeyRecoveryService kapselt Erzeugen/Einlösen; Redeem schreibt den wiederhergestellten Schlüssel und setzt vorsorglich Pull-Cursor/Versionsverfolgung zurück. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -105,6 +105,9 @@ public static class AppBootstrapper
|
||||
ResolveDbPath();
|
||||
var queuePath = Path.Combine(appData, "syncqueue.db");
|
||||
var keyPath = Path.Combine(appData, "sync.key");
|
||||
// Muss VOR jedem möglichen Zugriff auf keyPath erfasst werden (siehe SyncKeyStatus unten) -
|
||||
// File.Exists ist hier synchron und unabhängig von der Lazy-Auflösung der DI-Factories.
|
||||
var keyExistedBefore = File.Exists(keyPath);
|
||||
|
||||
// ── Logging & Benachrichtigungen ─────────────────────────────────────────
|
||||
EnsureLogger();
|
||||
@@ -183,6 +186,12 @@ public static class AppBootstrapper
|
||||
var syncSettings = new SyncSettingsService(appData);
|
||||
services.AddSingleton(syncSettings);
|
||||
services.AddSingleton(_ => new SyncAuthService(new HttpClient()));
|
||||
// War dieses Gerät schon eingeloggt, aber sync.key fehlt(e), wurde gerade eben (unten)
|
||||
// stillschweigend ein neuer, unabhängiger Schlüssel erzeugt - bisher unter dem ALTEN
|
||||
// Schlüssel synchronisierte Server-Daten sind für dieses Gerät dann nicht mehr lesbar.
|
||||
// Bei einem Gerät, das noch nie eingeloggt war, ist ein fehlender Schlüssel dagegen der
|
||||
// normale Erstlauf. Siehe SettingsViewModel (Warnbanner) und SyncKeyRecoveryService.
|
||||
services.AddSingleton(new SyncKeyStatus(!keyExistedBefore && syncSettings.IsLoggedIn));
|
||||
|
||||
services.AddSingleton(_ => new EventQueue(queuePath));
|
||||
services.AddSingleton(sp => new ConflictResolver(sp.GetRequiredService<EventQueue>()));
|
||||
@@ -192,6 +201,9 @@ public static class AppBootstrapper
|
||||
SyncCrypto.SaveKey(key, keyPath);
|
||||
return key;
|
||||
});
|
||||
// Rein lokal/offline (kein Server-Zugriff nötig), deshalb unconditional registriert - im
|
||||
// Unterschied zu SnapshotService unten, das eine konfigurierte Server-URL voraussetzt.
|
||||
services.AddSingleton(sp => new SyncKeyRecoveryService(sp.GetRequiredService<byte[]>(), keyPath));
|
||||
|
||||
var serverUrl = syncSettings.ServerUrl;
|
||||
var deviceId = LoadOrCreateDeviceId(appData);
|
||||
|
||||
Reference in New Issue
Block a user