feat: sync guard - Blockieren alter Clients beim sync

This commit is contained in:
2026-08-20 23:54:04 +02:00
parent 7b883555bf
commit 59bd8abb45
19 changed files with 369 additions and 26 deletions
+13 -8
View File
@@ -28,20 +28,24 @@ public class SnapshotService(
// Schritt 1: Upload ohne Key → Code erhalten
Report(SnapshotStep.Uploading, "Code wird angefordert…");
var r1 = await http.PostAsJsonAsync("/api/snapshot/upload",
new SnapshotUploadRequest { EncryptedPayload = encPayload, DeviceType = deviceType }, ct);
r1.EnsureSuccessStatusCode();
using var request1 = SyncProtocol.CreateRequest(HttpMethod.Post, "/api/snapshot/upload");
request1.Content = JsonContent.Create(
new SnapshotUploadRequest { EncryptedPayload = encPayload, DeviceType = deviceType });
using var r1 = await http.SendAsync(request1, ct);
await SyncProtocol.EnsureCompatibleSuccessAsync(r1);
var init = await r1.Content.ReadFromJsonAsync<SnapshotUploadResponse>(ct)
?? throw new InvalidOperationException("Leere Server-Antwort.");
// Schritt 2: Key mit Code verschlüsseln + erneut hochladen
Report(SnapshotStep.Uploading, "Schlüssel wird verschlüsselt…");
var encKey = SyncCrypto.EncryptKeyWithCode(syncKey, init.Code);
var r2 = await http.PostAsJsonAsync("/api/snapshot/upload",
using var request2 = SyncProtocol.CreateRequest(HttpMethod.Post, "/api/snapshot/upload");
request2.Content = JsonContent.Create(
new SnapshotUploadRequest { EncryptedPayload = encPayload,
EncryptedSyncKey = encKey, DeviceType = deviceType,
Code = init.Code }, ct);
r2.EnsureSuccessStatusCode();
Code = init.Code });
using var r2 = await http.SendAsync(request2, ct);
await SyncProtocol.EnsureCompatibleSuccessAsync(r2);
var result = await r2.Content.ReadFromJsonAsync<SnapshotUploadResponse>(ct)
?? throw new InvalidOperationException("Leere Server-Antwort.");
Report(SnapshotStep.Done, $"Bereit Code: {result.Code}");
@@ -53,10 +57,11 @@ public class SnapshotService(
{
var sanitized = code.Trim().ToUpperInvariant();
Report(SnapshotStep.Downloading, "Snapshot wird geladen…");
var resp = await http.GetAsync($"/api/snapshot/{sanitized}", ct);
using var request = SyncProtocol.CreateRequest(HttpMethod.Get, $"/api/snapshot/{sanitized}");
using var resp = await http.SendAsync(request, ct);
if (resp.StatusCode == System.Net.HttpStatusCode.NotFound)
throw new SnapshotNotFoundException($"Code '{sanitized}' nicht gefunden oder abgelaufen.");
resp.EnsureSuccessStatusCode();
await SyncProtocol.EnsureCompatibleSuccessAsync(resp);
var dl = await resp.Content.ReadFromJsonAsync<SnapshotDownloadResponse>(ct)
?? throw new InvalidOperationException("Leere Server-Antwort.");