using System.Text.Json; using LehrerApp.Sync; namespace LehrerApp.Api; /// /// Stoppt veraltete Sync-Clients vor Authentifizierung und insbesondere vor jedem Store-Zugriff. /// Die Prüfung gilt auch für Anhänge, Plain-Sync und Device-Pairing-Snapshots. /// public sealed class SyncProtocolVersionMiddleware(RequestDelegate next) { public async Task InvokeAsync(HttpContext context) { if (!IsProtectedSyncPath(context.Request.Path)) { await next(context); return; } context.Response.Headers[SyncProtocol.VersionHeaderName] = SyncProtocol.CurrentVersion; var clientVersion = context.Request.Headers[SyncProtocol.VersionHeaderName].ToString(); if (string.Equals(clientVersion, SyncProtocol.CurrentVersion, StringComparison.Ordinal)) { await next(context); return; } context.Response.StatusCode = StatusCodes.Status426UpgradeRequired; context.Response.ContentType = "application/problem+json"; await JsonSerializer.SerializeAsync(context.Response.Body, new { type = "https://lehrerapp.local/problems/sync-version-mismatch", title = "Inkompatible Sync-Version", status = StatusCodes.Status426UpgradeRequired, detail = $"Der Server erwartet Sync-Version {SyncProtocol.CurrentVersion}.", expectedVersion = SyncProtocol.CurrentVersion, receivedVersion = string.IsNullOrEmpty(clientVersion) ? null : clientVersion, }); } private static bool IsProtectedSyncPath(PathString path) => path.StartsWithSegments("/api/sync", StringComparison.OrdinalIgnoreCase) || path.StartsWithSegments("/api/snapshot", StringComparison.OrdinalIgnoreCase); }