Licensing: 100-day offline cache with anti-rollback + cached server status
- CachedValidityDays bumped 7 → 100 days. Covers the "user goes online once every 3 months for updates" use case without repeatedly nagging for re-auth. - LastValidationAt now uses response.ServerTime (signed Ed25519 by the server) rather than DateTime.UtcNow, so the client's local clock can't be used to forge a fresh validation date. - LastSeenUtc monotonic counter, persisted on every launch as max(stored, now). Combined with a 1h grace window: if the user rolls their PC clock backward to extend the offline cache, the rollback is detected (now < LastSeen - 1h) and the cache is invalidated → forced re-validation next time online. - CachedStatus persists the server-returned status (valid/expired/revoked/ invalid/machine_limit_exceeded) so a revocation done while the user is offline still shows correctly when they next launch with cached data. Auto-override to "expired" if entitlement date has passed (handles the valid → expired transition without needing a server round-trip). - ILicenseService.GetDecryptedKey() exposed for the new auto-revalidation flow. This puts the trust boundary in the right place: cached data is informational offline, the actual download authorization always re-validates against the server (the gate to download is /api/download-url/, which checks the live license state on each call). User can't fake offline-only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,13 +13,53 @@ public sealed class LocalConfig
|
||||
/// </summary>
|
||||
public string Language { get; set; } = "auto";
|
||||
|
||||
/// <summary>
|
||||
/// Nombre de connexions HTTP parallèles utilisées pour télécharger un build.
|
||||
/// 1 = comportement legacy single-connection. 4-8 contourne le throttling
|
||||
/// per-connection d'Apache/OVH mutualisé. 8 est un bon défaut.
|
||||
/// </summary>
|
||||
public int ParallelDownloadSegments { get; set; } = 8;
|
||||
|
||||
/// <summary>
|
||||
/// Si false, ignore la vérification SHA-256 même si le manifest l'exige.
|
||||
/// Utile sur les machines lentes ou pour gagner 30 s-3 min en fin de DL d'un gros build.
|
||||
/// La sécurité repose alors uniquement sur la signature Ed25519 du manifest + HTTPS,
|
||||
/// ce qui reste robuste.
|
||||
/// </summary>
|
||||
public bool VerifyDownloadHash { get; set; } = true;
|
||||
|
||||
public LicenseConfig License { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class LicenseConfig
|
||||
{
|
||||
public string? EncryptedKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Date UTC de la dernière validation online réussie. Utilise <c>response.ServerTime</c>
|
||||
/// (signé Ed25519) plutôt que l'horloge locale, donc non manipulable par l'utilisateur.
|
||||
/// Sert de point de départ au calcul d'expiration du cache offline.
|
||||
/// </summary>
|
||||
public DateTime? LastValidationAt { get; set; }
|
||||
|
||||
public DateTime? CachedEntitlementUntil { get; set; }
|
||||
public string? CachedOwnerName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Statut tel que renvoyé par le serveur lors de la dernière validation : "valid",
|
||||
/// "expired", "revoked", "invalid", "machine_limit_exceeded". Persisté pour qu'une
|
||||
/// révocation effectuée pendant que le user est offline soit toujours visible
|
||||
/// même après son expiration de cache local. Le calcul "valid → expired" basé
|
||||
/// sur la date est aussi appliqué côté lecture (sanity) si le temps a passé.
|
||||
/// </summary>
|
||||
public string? CachedStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compteur monotone : date UTC la plus récente jamais observée par le launcher
|
||||
/// sur cette machine. Mise à jour à chaque démarrage si <c>now</c> est postérieur.
|
||||
/// Sert d'anti-rollback : si l'utilisateur recule l'horloge PC, on détecte
|
||||
/// (now < LastSeenUtc - grace) et on invalide le cache → forçage d'une
|
||||
/// re-validation online la prochaine fois qu'il sera connecté.
|
||||
/// </summary>
|
||||
public DateTime? LastSeenUtc { get; set; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user