diff options
author | Wouter Tinus <wouter.tinus@gmail.com> | 2020-06-17 20:01:43 +0200 |
---|---|---|
committer | Wouter Tinus <wouter.tinus@gmail.com> | 2020-06-17 20:01:43 +0200 |
commit | 8edfefc8fe0ce3c145a7370df9fa26ce7e167bca (patch) | |
tree | f0853c8a010d19b7a86ba73b0d6c78150401552b | |
parent | f9d62aba18af98ac7758918b0d0e712f195bff8e (diff) | |
download | letsencrypt-win-simple-8edfefc8fe0ce3c145a7370df9fa26ce7e167bca.zip letsencrypt-win-simple-8edfefc8fe0ce3c145a7370df9fa26ce7e167bca.tar.gz letsencrypt-win-simple-8edfefc8fe0ce3c145a7370df9fa26ce7e167bca.tar.bz2 |
make HttpValidation support parallel validation
6 files changed, 78 insertions, 99 deletions
diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/FileSystem/FileSystem.cs b/src/main.lib/Plugins/ValidationPlugins/Http/FileSystem/FileSystem.cs index ff23950..8dfccb4 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/FileSystem/FileSystem.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/FileSystem/FileSystem.cs @@ -3,6 +3,7 @@ using PKISharp.WACS.DomainObjects; using System; using System.IO; using System.Linq; +using System.Threading.Tasks; namespace PKISharp.WACS.Plugins.ValidationPlugins.Http { @@ -12,7 +13,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http public FileSystem(FileSystemOptions options, IIISClient iisClient, RunLevel runLevel, HttpValidationParameters pars) : base(options, runLevel, pars) => _iisClient = iisClient; - protected override void DeleteFile(string path) + protected override Task DeleteFile(string path) { var fi = new FileInfo(path); if (fi.Exists) @@ -24,9 +25,10 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http { _log.Warning("File {path} already deleted", path); } + return Task.CompletedTask; } - protected override void DeleteFolder(string path) + protected override Task DeleteFolder(string path) { var di = new DirectoryInfo(path); if (di.Exists) @@ -38,11 +40,12 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http { _log.Warning("Folder {path} already deleted", path); } + return Task.CompletedTask; } - protected override bool IsEmpty(string path) => !new DirectoryInfo(path).EnumerateFileSystemInfos().Any(); + protected override Task<bool> IsEmpty(string path) => Task.FromResult(!new DirectoryInfo(path).EnumerateFileSystemInfos().Any()); - protected override void WriteFile(string path, string content) + protected override async Task WriteFile(string path, string content) { var fi = new FileInfo(path); if (!fi.Directory.Exists) @@ -50,7 +53,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http fi.Directory.Create(); } _log.Verbose("Writing file to {path}", path); - File.WriteAllText(path, content); + await File.WriteAllTextAsync(path, content); } /// <summary> diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/Ftp.cs b/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/Ftp.cs index 1084b07..c9aa07e 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/Ftp.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/Ftp.cs @@ -1,5 +1,6 @@ using PKISharp.WACS.Clients; using System.Linq; +using System.Threading.Tasks; namespace PKISharp.WACS.Plugins.ValidationPlugins.Http { @@ -11,12 +12,12 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http protected override char PathSeparator => '/'; - protected override void DeleteFile(string path) => _ftpClient.Delete(path, FtpClient.FileType.File); + protected override async Task DeleteFile(string path) => _ftpClient.Delete(path, FtpClient.FileType.File); - protected override void DeleteFolder(string path) => _ftpClient.Delete(path, FtpClient.FileType.Directory); + protected override async Task DeleteFolder(string path) => _ftpClient.Delete(path, FtpClient.FileType.Directory); - protected override bool IsEmpty(string path) => !_ftpClient.GetFiles(path).Any(); + protected override async Task<bool> IsEmpty(string path) => !_ftpClient.GetFiles(path).Any(); - protected override void WriteFile(string path, string content) => _ftpClient.Upload(path, content); + protected override async Task WriteFile(string path, string content) => _ftpClient.Upload(path, content); } } diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidation.cs b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidation.cs index 6c2c48b..768fcce 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidation.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidation.cs @@ -4,6 +4,7 @@ using PKISharp.WACS.DomainObjects; using PKISharp.WACS.Plugins.Interfaces; using PKISharp.WACS.Services; using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; @@ -20,10 +21,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins where TOptions : HttpValidationOptions<TPlugin> where TPlugin : IValidationPlugin { - - private bool _webConfigWritten = false; - private bool _challengeWritten = false; - private Http01ChallengeValidationDetails? _challenge = null; + private readonly List<string> _filesWritten = new List<string>(); protected TOptions _options; protected ILogService _log; @@ -32,6 +30,10 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins protected Renewal _renewal; protected RunLevel _runLevel; + /// <summary> + /// Multiple http-01 validation challenges can be answered at the same time + /// </summary> + public override ParallelOperations Parallelism => ParallelOperations.Answer; /// <summary> /// Path used for the current renewal, may not be same as _options.Path @@ -160,9 +162,12 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins { throw new InvalidOperationException(); } - WriteFile(CombinePath(_path, challenge.HttpResourcePath), challenge.HttpResourceValue); - _challengeWritten = true; - _challenge = challenge; + var path = CombinePath(_path, challenge.HttpResourcePath); + WriteFile(path, challenge.HttpResourceValue); + if (!_filesWritten.Contains(path)) + { + _filesWritten.Add(path); + } } /// <summary> @@ -181,12 +186,15 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins { try { - _log.Debug("Writing web.config"); var partialPath = challenge.HttpResourcePath.Split('/').Last(); var destination = CombinePath(_path, challenge.HttpResourcePath.Replace(partialPath, "web.config")); - var content = GetWebConfig(); - WriteFile(destination, content); - _webConfigWritten = true; + if (!_filesWritten.Contains(destination)) + { + _log.Debug("Writing web.config"); + var content = GetWebConfig(); + WriteFile(destination, content); + _filesWritten.Add(destination); + } } catch (Exception ex) { @@ -202,65 +210,6 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins private string GetWebConfig() => File.ReadAllText(TemplateWebConfig); /// <summary> - /// Can be used to write out server specific configuration, to handle extensionless files etc. - /// </summary> - /// <param name="target"></param> - /// <param name="answerPath"></param> - /// <param name="token"></param> - private void DeleteWebConfig() - { - if (_path == null) - { - throw new InvalidOperationException(); - } - if (_webConfigWritten && _challenge != null) - { - _log.Debug("Deleting web.config"); - var partialPath = _challenge.HttpResourcePath.Split('/').Last(); - var destination = CombinePath(_path, _challenge.HttpResourcePath.Replace(partialPath, "web.config")); - DeleteFile(destination); - } - } - - /// <summary> - /// Should delete any authorizations - /// </summary> - /// <param name="answerPath">where the answerFile should be located</param> - /// <param name="token">the token</param> - /// <param name="webRootPath">the website root path</param> - /// <param name="filePath">the file path for the authorization file</param> - private void DeleteAuthorization() - { - try - { - if (_path != null && _challengeWritten && _challenge != null) - { - _log.Debug("Deleting answer"); - var path = CombinePath(_path, _challenge.HttpResourcePath); - var partialPath = _challenge.HttpResourcePath.Split('/').Last(); - DeleteFile(path); - if (_settings.Validation.CleanupFolders) - { - path = path.Replace($"{PathSeparator}{partialPath}", ""); - if (DeleteFolderIfEmpty(path)) - { - var idx = path.LastIndexOf(PathSeparator); - if (idx >= 0) - { - path = path.Substring(0, path.LastIndexOf(PathSeparator)); - DeleteFolderIfEmpty(path); - } - } - } - } - } - catch (Exception ex) - { - _log.Warning("Error occured while deleting folder structure. Error: {@ex}", ex); - } - } - - /// <summary> /// Combine root path with relative path /// </summary> /// <param name="root"></param> @@ -279,11 +228,11 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// </summary> /// <param name="path"></param> /// <returns></returns> - private bool DeleteFolderIfEmpty(string path) + private async Task<bool> DeleteFolderIfEmpty(string path) { - if (IsEmpty(path)) + if (await IsEmpty(path)) { - DeleteFolder(path); + await DeleteFolder(path); return true; } else @@ -299,28 +248,28 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// <param name="root"></param> /// <param name="path"></param> /// <param name="content"></param> - protected abstract void WriteFile(string path, string content); + protected abstract Task WriteFile(string path, string content); /// <summary> /// Delete file from specific location /// </summary> /// <param name="root"></param> /// <param name="path"></param> - protected abstract void DeleteFile(string path); + protected abstract Task DeleteFile(string path); /// <summary> /// Check if folder is empty /// </summary> /// <param name="root"></param> /// <param name="path"></param> - protected abstract bool IsEmpty(string path); + protected abstract Task<bool> IsEmpty(string path); /// <summary> /// Delete folder if not empty /// </summary> /// <param name="root"></param> /// <param name="path"></param> - protected abstract void DeleteFolder(string path); + protected abstract Task DeleteFolder(string path); /// <summary> /// Refresh @@ -332,11 +281,36 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// <summary> /// Dispose /// </summary> - public override Task CleanUp() + public override async Task CleanUp() { - DeleteWebConfig(); - DeleteAuthorization(); - return Task.CompletedTask; + try + { + if (_path != null) + { + foreach (var file in _filesWritten) + { + _log.Debug("Deleting answer"); + await DeleteFile(file); + if (_settings.Validation.CleanupFolders) + { + var folder = file.Substring(0, file.LastIndexOf(PathSeparator)); + if (await DeleteFolderIfEmpty(folder)) + { + var idx = file.LastIndexOf(PathSeparator); + if (idx >= 0) + { + folder = folder.Substring(0, folder.LastIndexOf(PathSeparator)); + await DeleteFolderIfEmpty(folder); + } + } + } + } + } + } + catch (Exception ex) + { + _log.Warning("Error occured while deleting folder structure. Error: {@ex}", ex); + } } } } diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/Sftp/Sftp.cs b/src/main.lib/Plugins/ValidationPlugins/Http/Sftp/Sftp.cs index c3d5c08..a7a88ee 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/Sftp/Sftp.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/Sftp/Sftp.cs @@ -1,5 +1,6 @@ using PKISharp.WACS.Clients; using System.Linq; +using System.Threading.Tasks; namespace PKISharp.WACS.Plugins.ValidationPlugins.Http { @@ -11,12 +12,12 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http protected override char PathSeparator => '/'; - protected override void DeleteFile(string path) => _sshFtpClient.Delete(path, SshFtpClient.FileType.File); + protected override async Task DeleteFile(string path) => _sshFtpClient.Delete(path, SshFtpClient.FileType.File); - protected override void DeleteFolder(string path) => _sshFtpClient.Delete(path, SshFtpClient.FileType.Directory); + protected override async Task DeleteFolder(string path) => _sshFtpClient.Delete(path, SshFtpClient.FileType.Directory); - protected override bool IsEmpty(string path) => !_sshFtpClient.GetFiles(path).Any(); + protected override async Task<bool> IsEmpty(string path) => !_sshFtpClient.GetFiles(path).Any(); - protected override void WriteFile(string path, string content) => _sshFtpClient.Upload(path, content); + protected override async Task WriteFile(string path, string content) => _sshFtpClient.Upload(path, content); } } diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDav.cs b/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDav.cs index c34149d..f1adaea 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDav.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDav.cs @@ -15,15 +15,15 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http RunLevel runLevel, ProxyService proxy) : base(options, runLevel, pars) => _webdavClient = new WebDavClientWrapper(_options.Credential, pars.LogService, proxy); - protected override void DeleteFile(string path) => _webdavClient.Delete(path); + protected override async Task DeleteFile(string path) => _webdavClient.Delete(path); - protected override void DeleteFolder(string path) => _webdavClient.Delete(path); + protected override async Task DeleteFolder(string path) => _webdavClient.Delete(path); - protected override bool IsEmpty(string path) => !_webdavClient.IsEmpty(path); + protected override async Task<bool> IsEmpty(string path) => !_webdavClient.IsEmpty(path); protected override char PathSeparator => '/'; - protected override void WriteFile(string path, string content) => _webdavClient.Upload(path, content); + protected override async Task WriteFile(string path, string content) => _webdavClient.Upload(path, content); public override Task CleanUp() { base.CleanUp(); diff --git a/src/main.lib/RenewalCreator.cs b/src/main.lib/RenewalCreator.cs index 4a198db..0210ca2 100644 --- a/src/main.lib/RenewalCreator.cs +++ b/src/main.lib/RenewalCreator.cs @@ -363,7 +363,7 @@ namespace PKISharp.WACS { goto retry; } - _exceptionHandler.HandleException(message: $"Create certificate failed: {string.Join(", ", result.ErrorMessages)}"); + _exceptionHandler.HandleException(message: $"Create certificate failed: {string.Join("\n\t- ", result.ErrorMessages)}"); } else { |