diff --git a/src/FluffySpoon.AspNet.LetsEncrypt.Redis/DistributedCacheChallengePersistenceStrategy.cs b/src/FluffySpoon.AspNet.LetsEncrypt.Redis/DistributedCacheChallengePersistenceStrategy.cs index 5165605..48190d3 100644 --- a/src/FluffySpoon.AspNet.LetsEncrypt.Redis/DistributedCacheChallengePersistenceStrategy.cs +++ b/src/FluffySpoon.AspNet.LetsEncrypt.Redis/DistributedCacheChallengePersistenceStrategy.cs @@ -11,39 +11,60 @@ namespace FluffySpoon.AspNet.LetsEncrypt.Redis { - public class DistributedCacheChallengePersistenceStrategy : CustomChallengePersistenceStrategy + public class DistributedCacheChallengePersistenceStrategy : IChallengePersistenceStrategy { private const string Key = "FluffySpoon_Challenges"; + private readonly ILogger _logger; + private readonly IDistributedCache _cache; + private readonly TimeSpan _expiry; + public DistributedCacheChallengePersistenceStrategy( ILogger logger, IDistributedCache cache, - TimeSpan expiry) : base( - new ChallengeType[] { ChallengeType.Http01 }, - async (challenges) => - { - var json = challenges == null ? null : JsonConvert.SerializeObject(challenges.ToArray()); - logger.LogDebug("Persisting challenges {0}", json); - - var bytes = json == null ? null : Encoding.UTF8.GetBytes(json); - - await cache.SetAsync(Key, bytes, new DistributedCacheEntryOptions() - { - AbsoluteExpirationRelativeToNow = expiry - }); - }, - async () => { - var bytes = await cache.GetAsync(Key); - var json = Encoding.UTF8.GetString(bytes); - var challenges = JsonConvert.DeserializeObject>(json); - - return challenges; - }, - async (challenges) => - { - await cache.RemoveAsync(Key); - }) + TimeSpan expiry) { + _logger = logger; + _cache = cache; + _expiry = expiry; + } + + public bool CanHandleChallengeType(ChallengeType challengeType) + { + return challengeType == ChallengeType.Http01; + } + + public async Task DeleteAsync(IEnumerable challenges) + { + var persistedChallenges = await RetrieveAsync(); + var challengesToPersist = persistedChallenges + .Where(x => + !challenges.Any(y => y.Token == x.Token)) + .ToList(); + + await PersistAsync(challengesToPersist); + } + + public async Task PersistAsync(IEnumerable challenges) + { + var json = challenges == null ? null : JsonConvert.SerializeObject(challenges.ToArray()); + _logger.LogDebug("Persisting challenges {0}", json); + + var bytes = json == null ? null : Encoding.UTF8.GetBytes(json); + + await _cache.SetAsync(Key, bytes, new DistributedCacheEntryOptions() + { + AbsoluteExpirationRelativeToNow = _expiry + }); + } + + public async Task> RetrieveAsync() + { + var bytes = await _cache.GetAsync(Key); + var json = Encoding.UTF8.GetString(bytes); + var challenges = JsonConvert.DeserializeObject>(json); + + return challenges; } } } diff --git a/src/FluffySpoon.AspNet.LetsEncrypt/LetsEncryptRenewalService.cs b/src/FluffySpoon.AspNet.LetsEncrypt/LetsEncryptRenewalService.cs index f7d9024..866fc3a 100644 --- a/src/FluffySpoon.AspNet.LetsEncrypt/LetsEncryptRenewalService.cs +++ b/src/FluffySpoon.AspNet.LetsEncrypt/LetsEncryptRenewalService.cs @@ -278,7 +278,7 @@ private async Task ValidateOrderAsync(string[] domains, IOrderContext order) } finally { - await _persistenceService.PersistChallengesAsync(null); + await _persistenceService.DeleteChallengesAsync(challengeDtos); } } diff --git a/src/FluffySpoon.AspNet.LetsEncrypt/Persistence/FileChallengePersistenceStrategy.cs b/src/FluffySpoon.AspNet.LetsEncrypt/Persistence/FileChallengePersistenceStrategy.cs index 3b32adc..4006bfc 100644 --- a/src/FluffySpoon.AspNet.LetsEncrypt/Persistence/FileChallengePersistenceStrategy.cs +++ b/src/FluffySpoon.AspNet.LetsEncrypt/Persistence/FileChallengePersistenceStrategy.cs @@ -18,9 +18,15 @@ public FileChallengePersistenceStrategy(string relativeFilePath) _relativeFilePath = relativeFilePath; } - public Task DeleteAsync(IEnumerable challenges) + public async Task DeleteAsync(IEnumerable challenges) { - throw new System.NotImplementedException(); + var persistedChallenges = await RetrieveAsync(); + var challengesToPersist = persistedChallenges + .Where(x => + !challenges.Any(y => y.Token == x.Token)) + .ToList(); + + await PersistAsync(challengesToPersist); } public bool CanHandleChallengeType(ChallengeType challengeType) @@ -37,7 +43,7 @@ public Task PersistAsync(IEnumerable challenges) lock (typeof(FileChallengePersistenceStrategy)) { File.WriteAllBytes( - GetCertificatePath(), + GetChallengesStorePath(), bytes); } @@ -48,10 +54,10 @@ public Task> RetrieveAsync() { lock (typeof(FileChallengePersistenceStrategy)) { - if (!File.Exists(GetCertificatePath())) + if (!File.Exists(GetChallengesStorePath())) return Task.FromResult>(new List()); - var bytes = File.ReadAllBytes(GetCertificatePath()); + var bytes = File.ReadAllBytes(GetChallengesStorePath()); var json = Encoding.UTF8.GetString(bytes); var challenges = JsonConvert.DeserializeObject>(json); @@ -59,7 +65,7 @@ public Task> RetrieveAsync() } } - private string GetCertificatePath() + private string GetChallengesStorePath() { return _relativeFilePath + "_Challenges"; } diff --git a/src/FluffySpoon.AspNet.LetsEncrypt/Persistence/MemoryChallengePersistenceStrategy.cs b/src/FluffySpoon.AspNet.LetsEncrypt/Persistence/MemoryChallengePersistenceStrategy.cs index 496c280..69d08ca 100644 --- a/src/FluffySpoon.AspNet.LetsEncrypt/Persistence/MemoryChallengePersistenceStrategy.cs +++ b/src/FluffySpoon.AspNet.LetsEncrypt/Persistence/MemoryChallengePersistenceStrategy.cs @@ -1,5 +1,6 @@ using FluffySpoon.AspNet.LetsEncrypt.Persistence.Models; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace FluffySpoon.AspNet.LetsEncrypt.Persistence @@ -15,7 +16,10 @@ public MemoryChallengePersistenceStrategy() public Task DeleteAsync(IEnumerable challenges) { - _challenges = new List(); + _challenges = _challenges + .Where(x => + !challenges.Any(y => y.Token == x.Token)) + .ToList(); return Task.CompletedTask; }