diff options
Diffstat (limited to 'src')
119 files changed, 665 insertions, 551 deletions
diff --git a/src/main.lib/Acme/AcmeClient.cs b/src/main.lib/Acme/AcmeClient.cs index 5fcb485..e81de4d 100644 --- a/src/main.lib/Acme/AcmeClient.cs +++ b/src/main.lib/Acme/AcmeClient.cs @@ -108,41 +108,39 @@ namespace PKISharp.WACS.Acme _client.AfterHttpSend = (x, r) => _log.Verbose("Request completed with status {s}", r.StatusCode); _client.Directory = await _client.GetDirectoryAsync(); await _client.GetNonceAsync(); - _client.Account = await LoadAccount(signer); + _client.Account = await LoadAccount(_client, signer); if (_client.Account == null) { throw new Exception("AcmeClient was unable to find or create an account"); } } - internal async Task<AccountDetails?> GetAccount() { - await EnsureInitialized(); - if (_client != null) - { - return _client.Account; - } - return null; - } + internal async Task<AccountDetails?> GetAccount() => (await GetClient()).Account; - internal async Task EnsureInitialized() + internal async Task<AcmeProtocolClient> GetClient() { if (!_initialized) { await ConfigureAcmeClient(); _initialized = true; } + if (_client == null) + { + throw new InvalidOperationException(); + } + return _client; } - private async Task<AccountDetails?> LoadAccount(IJwsTool? signer) + private async Task<AccountDetails?> LoadAccount(AcmeProtocolClient client, IJwsTool? signer) { AccountDetails? account = null; if (File.Exists(AccountPath)) { - if (signer != null && _client != null) + if (signer != null) { _log.Debug("Loading account information from {registrationPath}", AccountPath); account = JsonConvert.DeserializeObject<AccountDetails>(File.ReadAllText(AccountPath)); - _client.Account = account; + client.Account = account; // Maybe we should update the account details // on every start of the program to figure out // if it hasn't been suspended or cancelled? @@ -156,7 +154,7 @@ namespace PKISharp.WACS.Acme else { var contacts = await GetContacts(); - var (_, filename, content) = await _client.GetTermsOfServiceAsync(); + var (_, filename, content) = await client.GetTermsOfServiceAsync(); if (!string.IsNullOrEmpty(filename)) { if (!await AcceptTos(filename, content)) @@ -164,12 +162,12 @@ namespace PKISharp.WACS.Acme return null; } } - account = await _client.CreateAccountAsync(contacts, termsOfServiceAgreed: true); + account = await client.CreateAccountAsync(contacts, termsOfServiceAgreed: true); _log.Debug("Saving registration"); var accountKey = new AccountSigner { - KeyType = _client.Signer.JwsAlg, - KeyExport = _client.Signer.Export(), + KeyType = client.Signer.JwsAlg, + KeyExport = client.Signer.Export(), }; AccountSigner = accountKey; File.WriteAllText(AccountPath, JsonConvert.SerializeObject(account)); @@ -306,11 +304,17 @@ namespace PKISharp.WACS.Acme #endregion - internal IChallengeValidationDetails DecodeChallengeValidation(Authorization auth, Challenge challenge) => AuthorizationDecoder.DecodeChallengeValidation(auth, challenge.Type, _client.Signer); + internal async Task<IChallengeValidationDetails> DecodeChallengeValidation(Authorization auth, Challenge challenge) + { + var client = await GetClient(); + return AuthorizationDecoder.DecodeChallengeValidation(auth, challenge.Type, client.Signer); + } - internal async Task<Challenge> AnswerChallenge(Challenge challenge) { + internal async Task<Challenge> AnswerChallenge(Challenge challenge) + { // Have to loop to wait for server to stop being pending - challenge = await Retry(() => _client.AnswerChallengeAsync(challenge.Url)); + var client = await GetClient(); + challenge = await Retry(() => client.AnswerChallengeAsync(challenge.Url)); var tries = 1; while ( challenge.Status == AuthorizationPending || @@ -318,7 +322,7 @@ namespace PKISharp.WACS.Acme { await Task.Delay(_settings.Acme.RetryInterval * 1000); _log.Debug("Refreshing authorization ({tries}/{count})", tries, _settings.Acme.RetryCount); - challenge = await Retry(() => _client.GetChallengeDetailsAsync(challenge.Url)); + challenge = await Retry(() => client.GetChallengeDetailsAsync(challenge.Url)); tries += 1; if (tries > _settings.Acme.RetryCount) { @@ -326,13 +330,25 @@ namespace PKISharp.WACS.Acme } } return challenge; - } + } - internal async Task<OrderDetails> CreateOrder(IEnumerable<string> identifiers) => await Retry(() => _client.CreateOrderAsync(identifiers)); - - internal async Task<Challenge> GetChallengeDetails(string url) => await Retry(() => _client.GetChallengeDetailsAsync(url)); - - internal async Task<Authorization> GetAuthorizationDetails(string url) => await Retry(() => _client.GetAuthorizationDetailsAsync(url)); + internal async Task<OrderDetails> CreateOrder(IEnumerable<string> identifiers) + { + var client = await GetClient(); + return await Retry(() => client.CreateOrderAsync(identifiers)); + } + + internal async Task<Challenge> GetChallengeDetails(string url) + { + var client = await GetClient(); + return await Retry(() => client.GetChallengeDetailsAsync(url)); + } + + internal async Task<Authorization> GetAuthorizationDetails(string url) + { + var client = await GetClient(); + return await Retry(() => client.GetAuthorizationDetailsAsync(url)); + } /// <summary> /// https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.1.3 @@ -340,16 +356,18 @@ namespace PKISharp.WACS.Acme /// <param name="details"></param> /// <param name="csr"></param> /// <returns></returns> - internal async Task<OrderDetails> SubmitCsr(OrderDetails details, byte[] csr) { + internal async Task<OrderDetails> SubmitCsr(OrderDetails details, byte[] csr) + { // First wait for the order to get "ready", meaning that all validations // are complete. The program makes sure this is the case at the level of // individual authorizations, but the server might need some extra time to // propagate this status at the order level. + var client = await GetClient(); await WaitForOrderStatus(details, OrderReady, false); if (details.Payload.Status == OrderReady) { - details = await Retry(() => _client.FinalizeOrderAsync(details.Payload.Finalize, csr)); + details = await Retry(() => client.FinalizeOrderAsync(details.Payload.Finalize, csr)); await WaitForOrderStatus(details, OrderProcessing, true); } return details; @@ -365,6 +383,7 @@ namespace PKISharp.WACS.Acme private async Task WaitForOrderStatus(OrderDetails details, string status, bool negate) { // Wait for processing + var client = await GetClient(); var tries = 0; do { @@ -376,7 +395,7 @@ namespace PKISharp.WACS.Acme } _log.Debug($"Waiting for order to get {(negate ? "NOT " : "")}{{ready}} ({{tries}}/{{count}})", OrderReady, tries, _settings.Acme.RetryCount); await Task.Delay(_settings.Acme.RetryInterval * 1000); - var update = await Retry(() => _client.GetOrderDetailsAsync(details.OrderUrl)); + var update = await Retry(() => client.GetOrderDetailsAsync(details.OrderUrl)); details.Payload = update.Payload; } tries += 1; @@ -388,38 +407,31 @@ namespace PKISharp.WACS.Acme internal async Task ChangeContacts() { - if (_client != null) - { - var contacts = await GetContacts(); - var account = await Retry(() => _client.UpdateAccountAsync(contacts, _client.Account)); - await UpdateAccount(); - } - else - { - throw new InvalidOperationException("Client not initialized"); - } + var client = await GetClient(); + var contacts = await GetContacts(); + var account = await Retry(() => client.UpdateAccountAsync(contacts, client.Account)); + await UpdateAccount(); } internal async Task UpdateAccount() { - if (_client != null) - { - var account = await Retry(() => _client.CheckAccountAsync()); - File.WriteAllText(AccountPath, JsonConvert.SerializeObject(account)); - _client.Account = account; - } - else - { - throw new InvalidOperationException("Client not initialized"); - } + var client = await GetClient(); + var account = await Retry(() => client.CheckAccountAsync()); + File.WriteAllText(AccountPath, JsonConvert.SerializeObject(account)); + client.Account = account; } - internal async Task<byte[]> GetCertificate(OrderDetails order) => await Retry(() => _client.GetOrderCertificateAsync(order)); + internal async Task<byte[]> GetCertificate(OrderDetails order) + { + var client = await GetClient(); + return await Retry(() => client.GetOrderCertificateAsync(order)); + } - internal async Task RevokeCertificate(byte[] crt) => await Retry(async () => { - await _client.RevokeCertificateAsync(crt, RevokeReason.Unspecified); - return Task.CompletedTask; - }); + internal async Task RevokeCertificate(byte[] crt) + { + var client = await GetClient(); + _ = await Retry(async () => client.RevokeCertificateAsync(crt, RevokeReason.Unspecified)); + } /// <summary> /// According to the ACME standard, we SHOULD retry calls @@ -433,7 +445,6 @@ namespace PKISharp.WACS.Acme { try { - await EnsureInitialized(); return await executor(); } catch (AcmeProtocolException apex) @@ -441,7 +452,8 @@ namespace PKISharp.WACS.Acme if (apex.ProblemType == ProblemType.BadNonce) { _log.Warning("First chance error calling into ACME server, retrying with new nonce..."); - await _client.GetNonceAsync(); + var client = await GetClient(); + await client.GetNonceAsync(); return await executor(); } else @@ -458,7 +470,7 @@ namespace PKISharp.WACS.Acme { if (!disposedValue) { - if (disposing) + if (disposing && _client != null) { _client.Dispose(); } diff --git a/src/main.lib/Clients/DNS/LookupClientProvider.cs b/src/main.lib/Clients/DNS/LookupClientProvider.cs index 367d306..70744b9 100644 --- a/src/main.lib/Clients/DNS/LookupClientProvider.cs +++ b/src/main.lib/Clients/DNS/LookupClientProvider.cs @@ -136,7 +136,7 @@ namespace PKISharp.WACS.Clients.DNS remainingParts = remainingParts.Reverse(); var digDeeper = true; - IEnumerable<IPAddress> ipSet = null; + IEnumerable<IPAddress>? ipSet = null; do { using (LogContext.PushProperty("Domain", testZone)) diff --git a/src/main.lib/Clients/DNS/LookupClientWrapper.cs b/src/main.lib/Clients/DNS/LookupClientWrapper.cs index 9ab91e4..1fbdcd6 100644 --- a/src/main.lib/Clients/DNS/LookupClientWrapper.cs +++ b/src/main.lib/Clients/DNS/LookupClientWrapper.cs @@ -15,9 +15,9 @@ namespace PKISharp.WACS.Clients.DNS private readonly DomainParseService _domainParser; private readonly LookupClientProvider _provider; public ILookupClient LookupClient { get; private set; } - public IPAddress IpAddress { get; private set; } + public IPAddress? IpAddress { get; private set; } - public LookupClientWrapper(DomainParseService domainParser, ILogService logService, IPAddress ipAddress, LookupClientProvider provider) + public LookupClientWrapper(DomainParseService domainParser, ILogService logService, IPAddress? ipAddress, LookupClientProvider provider) { IpAddress = ipAddress; LookupClient = ipAddress == null ? new LookupClient() : new LookupClient(ipAddress); @@ -29,7 +29,7 @@ namespace PKISharp.WACS.Clients.DNS public string GetRootDomain(string domainName) => _domainParser.GetTLD(domainName.TrimEnd('.')); - public async Task<IEnumerable<IPAddress>> GetAuthoritativeNameServers(string domainName, int round) + public async Task<IEnumerable<IPAddress>?> GetAuthoritativeNameServers(string domainName, int round) { domainName = domainName.TrimEnd('.'); _log.Debug("Querying name servers for {part}", domainName); @@ -55,8 +55,11 @@ namespace PKISharp.WACS.Clients.DNS _log.Verbose("Querying IP for name server"); var aResponse = _provider.GetDefaultClient(round).LookupClient.Query(nsRecord, QueryType.A); var nameServerIp = aResponse.Answers.ARecords().FirstOrDefault()?.Address; - _log.Verbose("Name server IP {NameServerIpAddress} identified", nameServerIp); - yield return nameServerIp; + if (nameServerIp != null) + { + _log.Verbose("Name server IP {NameServerIpAddress} identified", nameServerIp); + yield return nameServerIp; + } } } } @@ -69,6 +72,7 @@ namespace PKISharp.WACS.Clients.DNS return result.Answers.TxtRecords(). Select(txtRecord => txtRecord?.EscapedText?.FirstOrDefault()). Where(txtRecord => txtRecord != null). + OfType<string>(). ToList(); } diff --git a/src/main.lib/Clients/FtpClient.cs b/src/main.lib/Clients/FtpClient.cs index 4b75abe..61d80c7 100644 --- a/src/main.lib/Clients/FtpClient.cs +++ b/src/main.lib/Clients/FtpClient.cs @@ -8,13 +8,16 @@ namespace PKISharp.WACS.Clients { internal class FtpClient { - private NetworkCredential Credential { get; set; } + private NetworkCredential? Credential { get; set; } private readonly ILogService _log; - public FtpClient(NetworkCredentialOptions options, ILogService log) + public FtpClient(NetworkCredentialOptions? options, ILogService log) { - Credential = options.GetCredential(); _log = log; + if (options != null) + { + Credential = options.GetCredential(); + } } private FtpWebRequest CreateRequest(string ftpPath) @@ -40,24 +43,20 @@ namespace PKISharp.WACS.Clients { EnsureDirectories(ftpPath); var stream = new MemoryStream(); - using (var writer = new StreamWriter(stream)) - { - writer.Write(content); - writer.Flush(); - stream.Position = 0; + using var writer = new StreamWriter(stream); + writer.Write(content); + writer.Flush(); + stream.Position = 0; - var request = CreateRequest(ftpPath); - request.Method = WebRequestMethods.Ftp.UploadFile; + var request = CreateRequest(ftpPath); + request.Method = WebRequestMethods.Ftp.UploadFile; - using (var requestStream = request.GetRequestStream()) - { - stream.CopyTo(requestStream); - } - using (var response = (FtpWebResponse)request.GetResponse()) - { - _log.Verbose("Upload {ftpPath} status {StatusDescription}", ftpPath, response.StatusDescription?.Trim()); - } + using (var requestStream = request.GetRequestStream()) + { + stream.CopyTo(requestStream); } + using var response = (FtpWebResponse)request.GetResponse(); + _log.Verbose("Upload {ftpPath} status {StatusDescription}", ftpPath, response.StatusDescription?.Trim() ?? "(null)"); } private void EnsureDirectories(string ftpPath) @@ -74,10 +73,8 @@ namespace PKISharp.WACS.Clients request.Method = WebRequestMethods.Ftp.MakeDirectory; try { - using (var response = (FtpWebResponse)request.GetResponse()) - { - _log.Verbose("Create {path} status {StatusDescription}", path, response.StatusDescription?.Trim()); - } + using var response = (FtpWebResponse)request.GetResponse(); + _log.Verbose("Create {path} status {StatusDescription}", path, response.StatusDescription?.Trim() ?? "(null)"); } catch (Exception ex) { @@ -95,10 +92,8 @@ namespace PKISharp.WACS.Clients using (var response = (FtpWebResponse)request.GetResponse()) { var responseStream = response.GetResponseStream(); - using (var reader = new StreamReader(responseStream)) - { - names = reader.ReadToEnd(); - } + using var reader = new StreamReader(responseStream); + names = reader.ReadToEnd(); } names = names.Trim(); @@ -117,10 +112,8 @@ namespace PKISharp.WACS.Clients { request.Method = WebRequestMethods.Ftp.RemoveDirectory; } - using (var response = (FtpWebResponse)request.GetResponse()) - { - _log.Verbose("Delete {ftpPath} status {StatusDescription}", ftpPath, response.StatusDescription?.Trim()); - } + using var response = (FtpWebResponse)request.GetResponse(); + _log.Verbose("Delete {ftpPath} status {StatusDescription}", ftpPath, response.StatusDescription?.Trim()); } public enum FileType diff --git a/src/main.lib/Clients/IIS/BindingOptions.cs b/src/main.lib/Clients/IIS/BindingOptions.cs index fe488bb..dc3c261 100644 --- a/src/main.lib/Clients/IIS/BindingOptions.cs +++ b/src/main.lib/Clients/IIS/BindingOptions.cs @@ -37,7 +37,7 @@ namespace PKISharp.WACS.Clients.IIS /// <summary> /// Hostname that should be set for the binding /// </summary> - public string Host { get; } + public string? Host { get; } /// <summary> /// Optional: SiteId where new binding are supposed to be created @@ -63,7 +63,7 @@ namespace PKISharp.WACS.Clients.IIS public BindingOptions( SSLFlags flags = SSLFlags.None, int port = IISClient.DefaultBindingPort, - string? ip = IISClient.DefaultBindingIp, + string ip = IISClient.DefaultBindingIp, byte[]? thumbprint = null, string? store = null, string? host = null, @@ -80,10 +80,10 @@ namespace PKISharp.WACS.Clients.IIS public BindingOptions WithFlags(SSLFlags flags) => new BindingOptions(flags, Port, IP, Thumbprint, Store, Host, SiteId); public BindingOptions WithPort(int port) => new BindingOptions(Flags, port, IP, Thumbprint, Store, Host, SiteId); - public BindingOptions WithIP(string? ip) => new BindingOptions(Flags, Port, ip, Thumbprint, Store, Host, SiteId); + public BindingOptions WithIP(string ip) => new BindingOptions(Flags, Port, ip, Thumbprint, Store, Host, SiteId); public BindingOptions WithThumbprint(byte[] thumbprint) => new BindingOptions(Flags, Port, IP, thumbprint, Store, Host, SiteId); - public BindingOptions WithStore(string store) => new BindingOptions(Flags, Port, IP, Thumbprint, store, Host, SiteId); - public BindingOptions WithHost(string hostName) => new BindingOptions(Flags, Port, IP, Thumbprint, Store, hostName, SiteId); + public BindingOptions WithStore(string? store) => new BindingOptions(Flags, Port, IP, Thumbprint, store, Host, SiteId); + public BindingOptions WithHost(string? hostName) => new BindingOptions(Flags, Port, IP, Thumbprint, Store, hostName, SiteId); public BindingOptions WithSiteId(long? siteId) => new BindingOptions(Flags, Port, IP, Thumbprint, Store, Host, siteId); } }
\ No newline at end of file diff --git a/src/main.lib/Clients/IIS/IIISClient.cs b/src/main.lib/Clients/IIS/IIISClient.cs index 50f4866..05286db 100644 --- a/src/main.lib/Clients/IIS/IIISClient.cs +++ b/src/main.lib/Clients/IIS/IIISClient.cs @@ -13,7 +13,7 @@ namespace PKISharp.WACS.Clients.IIS Version Version { get; } IEnumerable<IIISSite> WebSites { get; } - void AddOrUpdateBindings(IEnumerable<string> identifiers, BindingOptions bindingOptions, byte[] oldThumbprint); + void AddOrUpdateBindings(IEnumerable<string> identifiers, BindingOptions bindingOptions, byte[]? oldThumbprint); IIISSite GetFtpSite(long id); IIISSite GetWebSite(long id); diff --git a/src/main.lib/Clients/IIS/IISClient.cs b/src/main.lib/Clients/IIS/IISClient.cs index f4e3dbc..817fde3 100644 --- a/src/main.lib/Clients/IIS/IISClient.cs +++ b/src/main.lib/Clients/IIS/IISClient.cs @@ -18,7 +18,7 @@ namespace PKISharp.WACS.Clients.IIS public Version Version { get; set; } [SuppressMessage("Code Quality", "IDE0069:Disposable fields should be disposed", Justification = "Actually is disposed")] - private ServerManager _ServerManager; + private ServerManager? _ServerManager; private readonly ILogService _log; public IISClient(ILogService log) @@ -30,7 +30,7 @@ namespace PKISharp.WACS.Clients.IIS /// <summary> /// Single reference to the ServerManager /// </summary> - private ServerManager ServerManager + private ServerManager? ServerManager { get { @@ -154,7 +154,7 @@ namespace PKISharp.WACS.Clients.IIS #region _ Https Install _ - public void AddOrUpdateBindings(IEnumerable<string> identifiers, BindingOptions bindingOptions, byte[] oldThumbprint) + public void AddOrUpdateBindings(IEnumerable<string> identifiers, BindingOptions bindingOptions, byte[]? oldThumbprint) { var updater = new IISHttpBindingUpdater<IISSiteWrapper, IISBindingWrapper>(this, _log); var updated = updater.AddOrUpdateBindings(identifiers, bindingOptions, oldThumbprint); diff --git a/src/main.lib/Clients/IIS/IISHttpBindingUpdater.cs b/src/main.lib/Clients/IIS/IISHttpBindingUpdater.cs index d6a3341..69b3c0e 100644 --- a/src/main.lib/Clients/IIS/IISHttpBindingUpdater.cs +++ b/src/main.lib/Clients/IIS/IISHttpBindingUpdater.cs @@ -38,7 +38,7 @@ namespace PKISharp.WACS.Clients.IIS public int AddOrUpdateBindings( IEnumerable<string> identifiers, BindingOptions bindingOptions, - byte[] oldThumbprint) + byte[]? oldThumbprint) { // Helper function to get updated sites IEnumerable<(TSite site, TBinding binding)> GetAllSites() => _client.WebSites. @@ -145,6 +145,11 @@ namespace PKISharp.WACS.Clients.IIS /// <param name="fuzzy"></param> private string? AddOrUpdateBindings(TBinding[] allBindings, TSite site, BindingOptions bindingOptions) { + if (bindingOptions.Host == null) + { + throw new InvalidOperationException("bindingOptions.Host is null"); + } + // Get all bindings which could map to the host var matchingBindings = site.Bindings. Select(x => new { binding = x, fit = Fits(x.Host, bindingOptions.Host, bindingOptions.Flags) }). diff --git a/src/main.lib/Clients/IIS/IISSiteWrapper.cs b/src/main.lib/Clients/IIS/IISSiteWrapper.cs index 4f4b537..cb1ecd2 100644 --- a/src/main.lib/Clients/IIS/IISSiteWrapper.cs +++ b/src/main.lib/Clients/IIS/IISSiteWrapper.cs @@ -35,7 +35,21 @@ namespace PKISharp.WACS.Clients.IIS public string Host => Binding.Host; public string Protocol => Binding.Protocol; public int Port => Binding.EndPoint?.Port ?? -1; - public string? IP => Binding.EndPoint?.Address?.ToString() ?? null; + public string? IP + { + get + { + var address = Binding.EndPoint?.Address; + if (address == null || address.GetAddressBytes().All(b => b == 0)) + { + return null; + } + else + { + return address.ToString(); + } + } + } public byte[] CertificateHash => Binding.CertificateHash; public string CertificateStoreName => Binding.CertificateStoreName; public string BindingInformation => Binding.NormalizedBindingInformation(); diff --git a/src/main.lib/Clients/SftpClient.cs b/src/main.lib/Clients/SftpClient.cs index e4e1c83..84342f6 100644 --- a/src/main.lib/Clients/SftpClient.cs +++ b/src/main.lib/Clients/SftpClient.cs @@ -12,7 +12,7 @@ namespace PKISharp.WACS.Clients { private readonly NetworkCredential _credential; private readonly ILogService _log; - private Uri Uri { get; set; } + private Uri? Uri { get; set; } /// <summary> /// Creating an Instance of SSH FTP Client. @@ -68,28 +68,26 @@ namespace PKISharp.WACS.Clients // Start upload process var stream = new MemoryStream(); - using (var writer = new StreamWriter(stream)) - { - // Write content into memorystream - writer.Write(content); - writer.Flush(); - stream.Position = 0; + using var writer = new StreamWriter(stream); + // Write content into memorystream + writer.Write(content); + writer.Flush(); + stream.Position = 0; - // Setup connection - var client = CreateRequest(sftpPathWithHost); - client.Connect(); + // Setup connection + var client = CreateRequest(sftpPathWithHost); + client.Connect(); - // Copy data onto sftp - client.UploadFile(stream, Uri.AbsolutePath); + // Copy data onto sftp + client.UploadFile(stream, Uri.AbsolutePath); - // Log for debugging - var statusDescription = client.Exists(Uri.AbsolutePath) ? "Completed" : "Failed"; - _log.Verbose("Upload {sftpPath} status {StatusDescription}", sftpPathWithHost, statusDescription); + // Log for debugging + var statusDescription = client.Exists(Uri.AbsolutePath) ? "Completed" : "Failed"; + _log.Verbose("Upload {sftpPath} status {StatusDescription}", sftpPathWithHost, statusDescription); - // Close connection - client.Disconnect(); - client.Dispose(); - } + // Close connection + client.Disconnect(); + client.Dispose(); } /// <summary> diff --git a/src/main.lib/Clients/WebDavClient.cs b/src/main.lib/Clients/WebDavClient.cs index ea343c3..e73eb94 100644 --- a/src/main.lib/Clients/WebDavClient.cs +++ b/src/main.lib/Clients/WebDavClient.cs @@ -11,20 +11,23 @@ namespace PKISharp.WACS.Client { internal class WebDavClientWrapper : IDisposable { - private readonly NetworkCredential _credential; + private readonly NetworkCredential? _credential; private readonly ILogService _log; private readonly ProxyService _proxy; private readonly WebDavClient _client; - public WebDavClientWrapper(NetworkCredentialOptions options, ILogService log, ProxyService proxy) + public WebDavClientWrapper(NetworkCredentialOptions? options, ILogService log, ProxyService proxy) { _log = log; - _credential = options.GetCredential(); + if (options != null && options.UserName != null) + { + _credential = options.GetCredential(); + } _proxy = proxy; _client = new WebDavClient(new WebDavClientParams() { Proxy = _proxy.GetWebProxy(), UseDefaultCredentials = _proxy.UseSystemProxy, - Credentials = string.IsNullOrEmpty(_credential.UserName) ? null : _credential + Credentials = _credential }); } diff --git a/src/main.lib/Configuration/BaseArgumentsProvider.cs b/src/main.lib/Configuration/BaseArgumentsProvider.cs index ed7f14e..5d76c31 100644 --- a/src/main.lib/Configuration/BaseArgumentsProvider.cs +++ b/src/main.lib/Configuration/BaseArgumentsProvider.cs @@ -20,7 +20,7 @@ namespace PKISharp.WACS.Configuration public abstract string Name { get; } public abstract string Group { get; } - public abstract string Condition { get; } + public virtual string? Condition { get; } public virtual bool Default => false; public abstract void Configure(FluentCommandLineParser<T> parser); bool IArgumentsProvider.Active(object current) => IsActive(current); diff --git a/src/main.lib/Configuration/MainArguments.cs b/src/main.lib/Configuration/MainArguments.cs index 374e083..427240f 100644 --- a/src/main.lib/Configuration/MainArguments.cs +++ b/src/main.lib/Configuration/MainArguments.cs @@ -5,7 +5,7 @@ namespace PKISharp.WACS.Configuration public class MainArguments { [SuppressMessage("Design", "CA1056:Uri properties should not be strings", Justification = "Not supported by library")] - public string? BaseUri { get; set; } + public string BaseUri { get; set; } [SuppressMessage("Design", "CA1056:Uri properties should not be strings", Justification = "Not supported by library")] public string? ImportBaseUri { get; set; } diff --git a/src/main.lib/Configuration/NetworkCredentialArguments.cs b/src/main.lib/Configuration/NetworkCredentialArguments.cs index 1c9a7be..5774249 100644 --- a/src/main.lib/Configuration/NetworkCredentialArguments.cs +++ b/src/main.lib/Configuration/NetworkCredentialArguments.cs @@ -2,7 +2,7 @@ { internal class NetworkCredentialArguments { - public string UserName { get; set; } - public string Password { get; set; } + public string? UserName { get; set; } + public string? Password { get; set; } } } diff --git a/src/main.lib/Configuration/NetworkCredentialOptions.cs b/src/main.lib/Configuration/NetworkCredentialOptions.cs index e3c167d..51054b7 100644 --- a/src/main.lib/Configuration/NetworkCredentialOptions.cs +++ b/src/main.lib/Configuration/NetworkCredentialOptions.cs @@ -7,22 +7,22 @@ namespace PKISharp.WACS.Configuration { public class NetworkCredentialOptions { - public string UserName { get; set; } + public string? UserName { get; set; } [JsonProperty(propertyName: "PasswordSafe")] - public ProtectedString Password { get; set; } + public ProtectedString? Password { get; set; } public NetworkCredential GetCredential() => new NetworkCredential(UserName, Password?.Value); public void Show(IInputService input) { input.Show("Username", UserName); - input.Show("Password", new string('*', Password?.Value.Length ?? 0)); + input.Show("Password", new string('*', Password?.Value?.Length ?? 0)); } public NetworkCredentialOptions() { } - public NetworkCredentialOptions(string userName, string password) + public NetworkCredentialOptions(string? userName, string? password) { UserName = userName; Password = new ProtectedString(password); diff --git a/src/main.lib/DomainObjects/CertificateInfo.cs b/src/main.lib/DomainObjects/CertificateInfo.cs index 27912a5..dcc67b5 100644 --- a/src/main.lib/DomainObjects/CertificateInfo.cs +++ b/src/main.lib/DomainObjects/CertificateInfo.cs @@ -23,7 +23,7 @@ namespace PKISharp.WACS.DomainObjects public List<X509Certificate2> Chain { get; set; } = new List<X509Certificate2>(); public FileInfo? CacheFile { get; set; } public string? CacheFilePassword { get; set; } - public string? SubjectName => Certificate?.Subject.Replace("CN=", "").Trim(); + public string SubjectName => Certificate.Subject.Replace("CN=", "").Trim(); public Dictionary<Type, StoreInfo> StoreInfo { get; set; } = new Dictionary<Type, StoreInfo>(); diff --git a/src/main.lib/DomainObjects/RenewResult.cs b/src/main.lib/DomainObjects/RenewResult.cs index 1963f97..8ab75eb 100644 --- a/src/main.lib/DomainObjects/RenewResult.cs +++ b/src/main.lib/DomainObjects/RenewResult.cs @@ -7,8 +7,8 @@ namespace PKISharp.WACS.DomainObjects { public DateTime Date { get; set; } public bool Success { get; set; } - public string ErrorMessage { get; set; } - public string Thumbprint { get; set; } + public string? ErrorMessage { get; set; } + public string? Thumbprint { get; set; } private RenewResult() => Date = DateTime.UtcNow; diff --git a/src/main.lib/DomainObjects/Renewal.cs b/src/main.lib/DomainObjects/Renewal.cs index 2b056a7..8034313 100644 --- a/src/main.lib/DomainObjects/Renewal.cs +++ b/src/main.lib/DomainObjects/Renewal.cs @@ -84,7 +84,7 @@ namespace PKISharp.WACS.DomainObjects /// Plain text readable version of the PfxFile password /// </summary> [JsonProperty(PropertyName = "PfxPasswordProtected")] - public ProtectedString PfxPassword { get; set; } + public ProtectedString? PfxPassword { get; set; } public DateTime? GetDueDate() { @@ -107,17 +107,17 @@ namespace PKISharp.WACS.DomainObjects /// <summary> /// Store information about TargetPlugin /// </summary> - public TargetPluginOptions TargetPluginOptions { get; set; } + public TargetPluginOptions? TargetPluginOptions { get; set; } /// <summary> /// Store information about ValidationPlugin /// </summary> - public ValidationPluginOptions ValidationPluginOptions { get; set; } + public ValidationPluginOptions? ValidationPluginOptions { get; set; } /// <summary> /// Store information about CsrPlugin /// </summary> - public CsrPluginOptions CsrPluginOptions { get; set; } + public CsrPluginOptions? CsrPluginOptions { get; set; } /// <summary> /// Store information about StorePlugin @@ -144,7 +144,7 @@ namespace PKISharp.WACS.DomainObjects /// Pretty format /// </summary> /// <returns></returns> - public string ToString(IInputService inputService) + public string ToString(IInputService? inputService) { var success = History.FindAll(x => x.Success).Count; var errors = History.AsEnumerable().Reverse().TakeWhile(x => !x.Success); diff --git a/src/main.lib/DomainObjects/Target.cs b/src/main.lib/DomainObjects/Target.cs index 48d3dd9..84398df 100644 --- a/src/main.lib/DomainObjects/Target.cs +++ b/src/main.lib/DomainObjects/Target.cs @@ -13,17 +13,17 @@ namespace PKISharp.WACS.DomainObjects /// Suggest a FriendlyName for the certificate, /// but this may be overruled by the user /// </summary> - public string FriendlyName { get; set; } + public string? FriendlyName { get; set; } /// <summary> /// CommonName for the certificate /// </summary> - public string CommonName { get; set; } + public string? CommonName { get; set; } /// <summary> /// Different parts that make up this target /// </summary> - public IEnumerable<TargetPart> Parts { get; set; } + public IEnumerable<TargetPart>? Parts { get; set; } /// <summary> /// Check if all parts are IIS diff --git a/src/main.lib/DomainObjects/TargetPart.cs b/src/main.lib/DomainObjects/TargetPart.cs index 138ca02..10ab6dd 100644 --- a/src/main.lib/DomainObjects/TargetPart.cs +++ b/src/main.lib/DomainObjects/TargetPart.cs @@ -1,11 +1,21 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Linq; namespace PKISharp.WACS.DomainObjects { [DebuggerDisplay("TargetPart: ({Identifiers.Count} host(s) - IIS: {IIS})")] public class TargetPart { + public TargetPart(IEnumerable<string>? identifiers) + { + if (identifiers == null) + { + throw new ArgumentNullException(nameof(identifiers)); + } + Identifiers = identifiers.ToList(); + } /// <summary> /// Optional IIS site ID that sourced these hostnames /// </summary> @@ -20,6 +30,6 @@ namespace PKISharp.WACS.DomainObjects /// <summary> /// Different parts that make up this target /// </summary> - public List<string> Identifiers { get; set; } + public List<string> Identifiers { get; } } } diff --git a/src/main.lib/Extensions/RenewalExtensions.cs b/src/main.lib/Extensions/RenewalExtensions.cs index 6b7f2c1..ed28419 100644 --- a/src/main.lib/Extensions/RenewalExtensions.cs +++ b/src/main.lib/Extensions/RenewalExtensions.cs @@ -9,7 +9,7 @@ namespace PKISharp.WACS.Extensions /// Get the most recent thumbprint /// </summary> /// <returns></returns> - public static string Thumbprint(this Renewal renewal) + public static string? Thumbprint(this Renewal renewal) { return renewal. History?. diff --git a/src/main.lib/Extensions/StringExtensions.cs b/src/main.lib/Extensions/StringExtensions.cs index 6f8fa1e..204597e 100644 --- a/src/main.lib/Extensions/StringExtensions.cs +++ b/src/main.lib/Extensions/StringExtensions.cs @@ -62,8 +62,13 @@ namespace PKISharp.WACS.Extensions ToList(); } - public static bool ValidFile(this string input, ILogService logService) + public static bool ValidFile(this string? input, ILogService logService) { + if (string.IsNullOrWhiteSpace(input)) + { + logService.Error("No path specified"); + return false; + } try { var fi = new FileInfo(Environment.ExpandEnvironmentVariables(input)); @@ -81,7 +86,7 @@ namespace PKISharp.WACS.Extensions } } - public static bool ValidPath(this string input, ILogService logService) + public static bool ValidPath(this string? input, ILogService logService) { if (string.IsNullOrWhiteSpace(input)) { diff --git a/src/main.lib/Extensions/TypeExtensions.cs b/src/main.lib/Extensions/TypeExtensions.cs index d9678af..e924357 100644 --- a/src/main.lib/Extensions/TypeExtensions.cs +++ b/src/main.lib/Extensions/TypeExtensions.cs @@ -6,7 +6,7 @@ namespace PKISharp.WACS.Extensions { public static class TypeExtensions { - public static string PluginId(this Type type) + public static string? PluginId(this Type type) { var attr = type.GetCustomAttributes(true).OfType<PluginAttribute>(); if (attr.Any()) diff --git a/src/main.lib/Plugins/Base/OptionsFactories/CsrPluginOptionsFactory.cs b/src/main.lib/Plugins/Base/OptionsFactories/CsrPluginOptionsFactory.cs index fb1d754..1aa2e0b 100644 --- a/src/main.lib/Plugins/Base/OptionsFactories/CsrPluginOptionsFactory.cs +++ b/src/main.lib/Plugins/Base/OptionsFactories/CsrPluginOptionsFactory.cs @@ -17,7 +17,7 @@ namespace PKISharp.WACS.Plugins.Base.Factories { public abstract Task<TOptions> Aquire(IInputService inputService, RunLevel runLevel); public abstract Task<TOptions> Default(); - async Task<CsrPluginOptions> ICsrPluginOptionsFactory.Aquire(IInputService inputService, RunLevel runLevel) => await Aquire(inputService, runLevel); - async Task<CsrPluginOptions> ICsrPluginOptionsFactory.Default() => await Default(); + async Task<CsrPluginOptions?> ICsrPluginOptionsFactory.Aquire(IInputService inputService, RunLevel runLevel) => await Aquire(inputService, runLevel); + async Task<CsrPluginOptions?> ICsrPluginOptionsFactory.Default() => await Default(); } }
\ No newline at end of file diff --git a/src/main.lib/Plugins/Base/OptionsFactories/Null/NullCsrOptionsFactory.cs b/src/main.lib/Plugins/Base/OptionsFactories/Null/NullCsrOptionsFactory.cs index 36fda3a..58a23c6 100644 --- a/src/main.lib/Plugins/Base/OptionsFactories/Null/NullCsrOptionsFactory.cs +++ b/src/main.lib/Plugins/Base/OptionsFactories/Null/NullCsrOptionsFactory.cs @@ -14,11 +14,11 @@ namespace PKISharp.WACS.Plugins.Base.Factories.Null Type IPluginOptionsFactory.InstanceType => typeof(object); Type IPluginOptionsFactory.OptionsType => typeof(object); string IPluginOptionsFactory.Name => "None"; - string IPluginOptionsFactory.Description => null; + string? IPluginOptionsFactory.Description => null; int IPluginOptionsFactory.Order => int.MaxValue; bool IPluginOptionsFactory.Disabled => false; bool IPluginOptionsFactory.Match(string name) => false; - Task<CsrPluginOptions> ICsrPluginOptionsFactory.Aquire(IInputService inputService, RunLevel runLevel) => null; - Task<CsrPluginOptions> ICsrPluginOptionsFactory.Default() => null; + Task<CsrPluginOptions?> ICsrPluginOptionsFactory.Aquire(IInputService inputService, RunLevel runLevel) => Task.FromResult<CsrPluginOptions?>(null); + Task<CsrPluginOptions?> ICsrPluginOptionsFactory.Default() => Task.FromResult<CsrPluginOptions?>(null); } } diff --git a/src/main.lib/Plugins/Base/OptionsFactories/Null/NullStoreOptionsFactory.cs b/src/main.lib/Plugins/Base/OptionsFactories/Null/NullStoreOptionsFactory.cs index 801b481..a75759a 100644 --- a/src/main.lib/Plugins/Base/OptionsFactories/Null/NullStoreOptionsFactory.cs +++ b/src/main.lib/Plugins/Base/OptionsFactories/Null/NullStoreOptionsFactory.cs @@ -13,8 +13,8 @@ namespace PKISharp.WACS.Plugins.Base.Factories.Null { Type IPluginOptionsFactory.InstanceType => typeof(object); Type IPluginOptionsFactory.OptionsType => typeof(object); - Task<StorePluginOptions> IStorePluginOptionsFactory.Aquire(IInputService inputService, RunLevel runLevel) => null; - Task<StorePluginOptions> IStorePluginOptionsFactory.Default() => null; + Task<StorePluginOptions?> IStorePluginOptionsFactory.Aquire(IInputService inputService, RunLevel runLevel) => Task.FromResult<StorePluginOptions?>(null); + Task<StorePluginOptions?> IStorePluginOptionsFactory.Default() => Task.FromResult<StorePluginOptions?>(null); string IPluginOptionsFactory.Name => "None"; bool IPluginOptionsFactory.Disabled => false; string IPluginOptionsFactory.Description => "No additional storage steps required"; diff --git a/src/main.lib/Plugins/Base/OptionsFactories/Null/NullTargetOptionsFactory.cs b/src/main.lib/Plugins/Base/OptionsFactories/Null/NullTargetOptionsFactory.cs index df18653..b3c4612 100644 --- a/src/main.lib/Plugins/Base/OptionsFactories/Null/NullTargetOptionsFactory.cs +++ b/src/main.lib/Plugins/Base/OptionsFactories/Null/NullTargetOptionsFactory.cs @@ -16,10 +16,10 @@ namespace PKISharp.WACS.Plugins.Base.Factories.Null bool ITargetPluginOptionsFactory.Hidden => true; bool IPluginOptionsFactory.Disabled => true; bool IPluginOptionsFactory.Match(string name) => false; - Task<TargetPluginOptions> ITargetPluginOptionsFactory.Aquire(IInputService inputService, RunLevel runLevel) => null; - Task<TargetPluginOptions> ITargetPluginOptionsFactory.Default() => null; + Task<TargetPluginOptions?> ITargetPluginOptionsFactory.Aquire(IInputService inputService, RunLevel runLevel) => Task.FromResult<TargetPluginOptions?>(default); + Task<TargetPluginOptions?> ITargetPluginOptionsFactory.Default() => Task.FromResult<TargetPluginOptions?>(default); string IPluginOptionsFactory.Name => "None"; - string IPluginOptionsFactory.Description => null; + string? IPluginOptionsFactory.Description => null; int IPluginOptionsFactory.Order => int.MaxValue; } } diff --git a/src/main.lib/Plugins/Base/OptionsFactories/Null/NullValidationOptionsFactory.cs b/src/main.lib/Plugins/Base/OptionsFactories/Null/NullValidationOptionsFactory.cs index 32e8cca..676621f 100644 --- a/src/main.lib/Plugins/Base/OptionsFactories/Null/NullValidationOptionsFactory.cs +++ b/src/main.lib/Plugins/Base/OptionsFactories/Null/NullValidationOptionsFactory.cs @@ -15,11 +15,11 @@ namespace PKISharp.WACS.Plugins.Base.Factories.Null Type IPluginOptionsFactory.InstanceType => typeof(object); Type IPluginOptionsFactory.OptionsType => typeof(object); string IValidationPluginOptionsFactory.ChallengeType => string.Empty; - Task<ValidationPluginOptions> IValidationPluginOptionsFactory.Aquire(Target target, IInputService inputService, RunLevel runLevel) => null; - Task<ValidationPluginOptions> IValidationPluginOptionsFactory.Default(Target target) => null; + Task<ValidationPluginOptions?> IValidationPluginOptionsFactory.Aquire(Target target, IInputService inputService, RunLevel runLevel) => Task.FromResult<ValidationPluginOptions?>(default); + Task<ValidationPluginOptions?> IValidationPluginOptionsFactory.Default(Target target) => Task.FromResult<ValidationPluginOptions?>(default); bool IPluginOptionsFactory.Match(string name) => false; string IPluginOptionsFactory.Name => "None"; - string IPluginOptionsFactory.Description => null; + string? IPluginOptionsFactory.Description => null; bool IValidationPluginOptionsFactory.CanValidate(Target target) => false; int IPluginOptionsFactory.Order => int.MaxValue; bool IPluginOptionsFactory.Disabled => true; diff --git a/src/main.lib/Plugins/Base/OptionsFactories/PluginOptionsFactory.cs b/src/main.lib/Plugins/Base/OptionsFactories/PluginOptionsFactory.cs index c59576b..3ee7fc4 100644 --- a/src/main.lib/Plugins/Base/OptionsFactories/PluginOptionsFactory.cs +++ b/src/main.lib/Plugins/Base/OptionsFactories/PluginOptionsFactory.cs @@ -8,8 +8,8 @@ namespace PKISharp.WACS.Plugins.Base.Factories IPluginOptionsFactory where TOptions : PluginOptions, new() { - private readonly string _name; - private readonly string _description; + private readonly string? _name; + private readonly string? _description; public PluginOptionsFactory() { @@ -23,8 +23,8 @@ namespace PKISharp.WACS.Plugins.Base.Factories } public virtual int Order => 0; - string IPluginOptionsFactory.Name => _name; - string IPluginOptionsFactory.Description => _description; + string? IPluginOptionsFactory.Name => _name; + string? IPluginOptionsFactory.Description => _description; /// <summary> /// Virtual so that plugins can have multiple names diff --git a/src/main.lib/Plugins/Base/OptionsFactories/StorePluginOptionsFactory.cs b/src/main.lib/Plugins/Base/OptionsFactories/StorePluginOptionsFactory.cs index 4933454..6fcfa88 100644 --- a/src/main.lib/Plugins/Base/OptionsFactories/StorePluginOptionsFactory.cs +++ b/src/main.lib/Plugins/Base/OptionsFactories/StorePluginOptionsFactory.cs @@ -15,10 +15,10 @@ namespace PKISharp.WACS.Plugins.Base.Factories where TPlugin : IStorePlugin where TOptions : StorePluginOptions, new() { - public abstract Task<TOptions> Aquire(IInputService inputService, RunLevel runLevel); - public abstract Task<TOptions> Default(); - async Task<StorePluginOptions> IStorePluginOptionsFactory.Aquire(IInputService inputService, RunLevel runLevel) => await Aquire(inputService, runLevel); - async Task<StorePluginOptions> IStorePluginOptionsFactory.Default() => await Default(); + public abstract Task<TOptions?> Aquire(IInputService inputService, RunLevel runLevel); + public abstract Task<TOptions?> Default(); + async Task<StorePluginOptions?> IStorePluginOptionsFactory.Aquire(IInputService inputService, RunLevel runLevel) => await Aquire(inputService, runLevel); + async Task<StorePluginOptions?> IStorePluginOptionsFactory.Default() => await Default(); } diff --git a/src/main.lib/Plugins/Base/OptionsFactories/ValidationPluginOptionsFactory.cs b/src/main.lib/Plugins/Base/OptionsFactories/ValidationPluginOptionsFactory.cs index 0fb603b..690c89a 100644 --- a/src/main.lib/Plugins/Base/OptionsFactories/ValidationPluginOptionsFactory.cs +++ b/src/main.lib/Plugins/Base/OptionsFactories/ValidationPluginOptionsFactory.cs @@ -19,10 +19,10 @@ namespace PKISharp.WACS.Plugins.Base.Factories public virtual bool Hidden => false; public ValidationPluginOptionsFactory(string challengeType = Constants.Http01ChallengeType) => _challengeType = challengeType; - public abstract Task<TOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel); - public abstract Task<TOptions> Default(Target target); - async Task<ValidationPluginOptions> IValidationPluginOptionsFactory.Aquire(Target target, IInputService inputService, RunLevel runLevel) => await Aquire(target, inputService, runLevel); - async Task<ValidationPluginOptions> IValidationPluginOptionsFactory.Default(Target target) => await Default(target); + public abstract Task<TOptions?> Aquire(Target target, IInputService inputService, RunLevel runLevel); + public abstract Task<TOptions?> Default(Target target); + async Task<ValidationPluginOptions?> IValidationPluginOptionsFactory.Aquire(Target target, IInputService inputService, RunLevel runLevel) => await Aquire(target, inputService, runLevel); + async Task<ValidationPluginOptions?> IValidationPluginOptionsFactory.Default(Target target) => await Default(target); /// <summary> /// By default no plugin can validate wildcards, should be overridden diff --git a/src/main.lib/Plugins/CsrPlugins/CsrArgumentsProvider.cs b/src/main.lib/Plugins/CsrPlugins/CsrArgumentsProvider.cs index b7514f3..c9ac81f 100644 --- a/src/main.lib/Plugins/CsrPlugins/CsrArgumentsProvider.cs +++ b/src/main.lib/Plugins/CsrPlugins/CsrArgumentsProvider.cs @@ -7,7 +7,7 @@ namespace PKISharp.WACS.Plugins.CsrPlugins { public override string Name => "Common"; public override string Group => "CSR"; - public override string Condition => null; + public override string? Condition => null; public override void Configure(FluentCommandLineParser<CsrArguments> parser) { diff --git a/src/main.lib/Plugins/CsrPlugins/CsrPlugin.cs b/src/main.lib/Plugins/CsrPlugins/CsrPlugin.cs index 5670139..f6421e7 100644 --- a/src/main.lib/Plugins/CsrPlugins/CsrPlugin.cs +++ b/src/main.lib/Plugins/CsrPlugins/CsrPlugin.cs @@ -30,9 +30,10 @@ namespace PKISharp.WACS.Plugins.CsrPlugins protected readonly ILogService _log; protected readonly ISettingsService _settings; protected readonly TOptions _options; - protected string _cacheData; private readonly PemService _pemService; - private AsymmetricCipherKeyPair _keyPair; + + protected string? _cacheData; + private AsymmetricCipherKeyPair? _keyPair; public CsrPlugin(ILogService log, ISettingsService settings, TOptions options, PemService pemService) { diff --git a/src/main.lib/Plugins/CsrPlugins/Ec/Ec.cs b/src/main.lib/Plugins/CsrPlugins/Ec/Ec.cs index 7bb3de5..55cddbd 100644 --- a/src/main.lib/Plugins/CsrPlugins/Ec/Ec.cs +++ b/src/main.lib/Plugins/CsrPlugins/Ec/Ec.cs @@ -38,19 +38,22 @@ namespace PKISharp.WACS.Plugins.CsrPlugins try { var config = _settings.Security.ECCurve; - DerObjectIdentifier curveOid = null; - try + if (config != null) { - curveOid = SecNamedCurves.GetOid(config); - } - catch { } - if (curveOid != null) - { - ret = config; - } - else - { - _log.Warning("Unknown curve {ECCurve}", config); + DerObjectIdentifier? curveOid = null; + try + { + curveOid = SecNamedCurves.GetOid(config); + } + catch { } + if (curveOid != null) + { + ret = config; + } + else + { + _log.Warning("Unknown curve {ECCurve}", config); + } } } catch (Exception ex) diff --git a/src/main.lib/Plugins/CsrPlugins/Rsa/Rsa.cs b/src/main.lib/Plugins/CsrPlugins/Rsa/Rsa.cs index d531719..7e6dcf1 100644 --- a/src/main.lib/Plugins/CsrPlugins/Rsa/Rsa.cs +++ b/src/main.lib/Plugins/CsrPlugins/Rsa/Rsa.cs @@ -59,7 +59,7 @@ namespace PKISharp.WACS.Plugins.CsrPlugins var tempPfx = new X509Certificate2( original.Export(X509ContentType.Cert), - (string)null, + "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); diff --git a/src/main.lib/Plugins/InstallationPlugins/IISWeb/IISWebArguments.cs b/src/main.lib/Plugins/InstallationPlugins/IISWeb/IISWebArguments.cs index c46fbf8..4e1852c 100644 --- a/src/main.lib/Plugins/InstallationPlugins/IISWeb/IISWebArguments.cs +++ b/src/main.lib/Plugins/InstallationPlugins/IISWeb/IISWebArguments.cs @@ -4,6 +4,6 @@ { public long? InstallationSiteId { get; set; } public int SSLPort { get; set; } - public string SSLIPAddress { get; set; } + public string? SSLIPAddress { get; set; } } } diff --git a/src/main.lib/Plugins/InstallationPlugins/IISWeb/IISWebOptions.cs b/src/main.lib/Plugins/InstallationPlugins/IISWeb/IISWebOptions.cs index daa1189..ce40eb2 100644 --- a/src/main.lib/Plugins/InstallationPlugins/IISWeb/IISWebOptions.cs +++ b/src/main.lib/Plugins/InstallationPlugins/IISWeb/IISWebOptions.cs @@ -8,7 +8,7 @@ namespace PKISharp.WACS.Plugins.InstallationPlugins internal class IISWebOptions : InstallationPluginOptions<IISWeb> { public long? SiteId { get; set; } - public string NewBindingIp { get; set; } + public string? NewBindingIp { get; set; } public int? NewBindingPort { get; set; } public override string Name => "IIS"; diff --git a/src/main.lib/Plugins/InstallationPlugins/Script/Script.cs b/src/main.lib/Plugins/InstallationPlugins/Script/Script.cs index 5cb9df4..74cb1f7 100644 --- a/src/main.lib/Plugins/InstallationPlugins/Script/Script.cs +++ b/src/main.lib/Plugins/InstallationPlugins/Script/Script.cs @@ -22,28 +22,31 @@ namespace PKISharp.WACS.Plugins.InstallationPlugins public async Task Install(IEnumerable<IStorePlugin> store, CertificateInfo newCertificate, CertificateInfo oldCertificate) { - var defaultStoreType = store.First().GetType(); - var defaultStoreInfo = newCertificate.StoreInfo[defaultStoreType]; - var parameters = _options.ScriptParameters ?? ""; - parameters = parameters.Replace("{0}", newCertificate.SubjectName); - parameters = parameters.Replace("{1}", _renewal.PfxPassword?.Value); - parameters = parameters.Replace("{2}", newCertificate.CacheFile?.FullName); - parameters = parameters.Replace("{3}", defaultStoreInfo.Path); - parameters = parameters.Replace("{4}", newCertificate.Certificate.FriendlyName); - parameters = parameters.Replace("{5}", newCertificate.Certificate.Thumbprint); - parameters = parameters.Replace("{6}", newCertificate.CacheFile?.Directory.FullName); - parameters = parameters.Replace("{7}", _renewal.Id); + if (_options.Script != null) + { + var defaultStoreType = store.First().GetType(); + var defaultStoreInfo = newCertificate.StoreInfo[defaultStoreType]; + var parameters = _options.ScriptParameters ?? ""; + parameters = parameters.Replace("{0}", newCertificate.SubjectName); + parameters = parameters.Replace("{1}", _renewal.PfxPassword?.Value); + parameters = parameters.Replace("{2}", newCertificate.CacheFile?.FullName); + parameters = parameters.Replace("{3}", defaultStoreInfo.Path); + parameters = parameters.Replace("{4}", newCertificate.Certificate.FriendlyName); + parameters = parameters.Replace("{5}", newCertificate.Certificate.Thumbprint); + parameters = parameters.Replace("{6}", newCertificate.CacheFile?.Directory.FullName); + parameters = parameters.Replace("{7}", _renewal.Id); - parameters = parameters.Replace("{CachePassword}", _renewal.PfxPassword?.Value); - parameters = parameters.Replace("{CacheFile}", newCertificate.CacheFile?.FullName); - parameters = parameters.Replace("{CacheFolder}", newCertificate.CacheFile?.FullName); - parameters = parameters.Replace("{CertCommonName}", newCertificate.SubjectName); - parameters = parameters.Replace("{CertFriendlyName}", newCertificate.Certificate.FriendlyName); - parameters = parameters.Replace("{CertThumbprint}", newCertificate.Certificate.Thumbprint); - parameters = parameters.Replace("{StoreType}", defaultStoreInfo.Name); - parameters = parameters.Replace("{StorePath}", defaultStoreInfo.Path); - parameters = parameters.Replace("{RenewalId}", _renewal.Id); - await _client.RunScript(_options.Script, parameters); + parameters = parameters.Replace("{CachePassword}", _renewal.PfxPassword?.Value); + parameters = parameters.Replace("{CacheFile}", newCertificate.CacheFile?.FullName); + parameters = parameters.Replace("{CacheFolder}", newCertificate.CacheFile?.FullName); + parameters = parameters.Replace("{CertCommonName}", newCertificate.SubjectName); + parameters = parameters.Replace("{CertFriendlyName}", newCertificate.Certificate.FriendlyName); + parameters = parameters.Replace("{CertThumbprint}", newCertificate.Certificate.Thumbprint); + parameters = parameters.Replace("{StoreType}", defaultStoreInfo.Name); + parameters = parameters.Replace("{StorePath}", defaultStoreInfo.Path); + parameters = parameters.Replace("{RenewalId}", _renewal.Id); + await _client.RunScript(_options.Script, parameters); + } } public bool Disabled => false; diff --git a/src/main.lib/Plugins/InstallationPlugins/Script/ScriptArguments.cs b/src/main.lib/Plugins/InstallationPlugins/Script/ScriptArguments.cs index d635bb9..0c9318f 100644 --- a/src/main.lib/Plugins/InstallationPlugins/Script/ScriptArguments.cs +++ b/src/main.lib/Plugins/InstallationPlugins/Script/ScriptArguments.cs @@ -2,7 +2,7 @@ { internal class ScriptArguments { - public string Script { get; set; } - public string ScriptParameters { get; set; } + public string? Script { get; set; } + public string? ScriptParameters { get; set; } } } diff --git a/src/main.lib/Plugins/InstallationPlugins/Script/ScriptOptions.cs b/src/main.lib/Plugins/InstallationPlugins/Script/ScriptOptions.cs index 4e9be94..147ba58 100644 --- a/src/main.lib/Plugins/InstallationPlugins/Script/ScriptOptions.cs +++ b/src/main.lib/Plugins/InstallationPlugins/Script/ScriptOptions.cs @@ -10,8 +10,8 @@ namespace PKISharp.WACS.Plugins.InstallationPlugins public override string Name => "Script"; public override string Description => "Start external script or program"; - public string Script { get; set; } - public string ScriptParameters { get; set; } + public string? Script { get; set; } + public string? ScriptParameters { get; set; } /// <summary> /// Show details to the user diff --git a/src/main.lib/Plugins/Interfaces/ICore.cs b/src/main.lib/Plugins/Interfaces/ICore.cs index 54ff6e5..47eb8d7 100644 --- a/src/main.lib/Plugins/Interfaces/ICore.cs +++ b/src/main.lib/Plugins/Interfaces/ICore.cs @@ -7,7 +7,7 @@ namespace PKISharp.WACS.Plugins.Interfaces /// <summary> /// Unique identifier /// </summary> - string Name { get; } + string? Name { get; } /// <summary> /// Check if name matches @@ -19,7 +19,7 @@ namespace PKISharp.WACS.Plugins.Interfaces /// <summary> /// Human-understandable description /// </summary> - string Description { get; } + string? Description { get; } /// <summary> /// Which type is used as instance diff --git a/src/main.lib/Plugins/Interfaces/ICsrPluginOptionsFactory.cs b/src/main.lib/Plugins/Interfaces/ICsrPluginOptionsFactory.cs index d6bc52d..af45be2 100644 --- a/src/main.lib/Plugins/Interfaces/ICsrPluginOptionsFactory.cs +++ b/src/main.lib/Plugins/Interfaces/ICsrPluginOptionsFactory.cs @@ -10,12 +10,12 @@ namespace PKISharp.WACS.Plugins.Interfaces /// Check or get information needed for store (interactive) /// </summary> /// <param name="target"></param> - Task<CsrPluginOptions> Aquire(IInputService inputService, RunLevel runLevel); + Task<CsrPluginOptions?> Aquire(IInputService inputService, RunLevel runLevel); /// <summary> /// Check information needed for store (unattended) /// </summary> /// <param name="target"></param> - Task<CsrPluginOptions> Default(); + Task<CsrPluginOptions?> Default(); } } diff --git a/src/main.lib/Plugins/Interfaces/IResolver.cs b/src/main.lib/Plugins/Interfaces/IResolver.cs index c5e69d6..b46d8e8 100644 --- a/src/main.lib/Plugins/Interfaces/IResolver.cs +++ b/src/main.lib/Plugins/Interfaces/IResolver.cs @@ -8,18 +8,18 @@ namespace PKISharp.WACS.Plugins.Interfaces { public interface IResolver { - Task<IInstallationPluginOptionsFactory> GetInstallationPlugin( + Task<IInstallationPluginOptionsFactory?> GetInstallationPlugin( ILifetimeScope scope, IEnumerable<Type> storeType, IEnumerable<IInstallationPluginOptionsFactory> chosen); - Task<IStorePluginOptionsFactory> GetStorePlugin(ILifetimeScope scope, + Task<IStorePluginOptionsFactory?> GetStorePlugin(ILifetimeScope scope, IEnumerable<IStorePluginOptionsFactory> chosen); - Task<ITargetPluginOptionsFactory> GetTargetPlugin(ILifetimeScope scope); + Task<ITargetPluginOptionsFactory?> GetTargetPlugin(ILifetimeScope scope); - Task<ICsrPluginOptionsFactory> GetCsrPlugin(ILifetimeScope scope); + Task<ICsrPluginOptionsFactory?> GetCsrPlugin(ILifetimeScope scope); - Task<IValidationPluginOptionsFactory> GetValidationPlugin(ILifetimeScope scope, Target target); + Task<IValidationPluginOptionsFactory?> GetValidationPlugin(ILifetimeScope scope, Target target); } }
\ No newline at end of file diff --git a/src/main.lib/Plugins/Interfaces/IStorePluginOptionsFactory.cs b/src/main.lib/Plugins/Interfaces/IStorePluginOptionsFactory.cs index 6c282ed..3becd42 100644 --- a/src/main.lib/Plugins/Interfaces/IStorePluginOptionsFactory.cs +++ b/src/main.lib/Plugins/Interfaces/IStorePluginOptionsFactory.cs @@ -13,12 +13,12 @@ namespace PKISharp.WACS.Plugins.Interfaces /// Check or get information needed for store (interactive) /// </summary> /// <param name="target"></param> - Task<StorePluginOptions> Aquire(IInputService inputService, RunLevel runLevel); + Task<StorePluginOptions?> Aquire(IInputService inputService, RunLevel runLevel); /// <summary> /// Check information needed for store (unattended) /// </summary> /// <param name="target"></param> - Task<StorePluginOptions> Default(); + Task<StorePluginOptions?> Default(); } } diff --git a/src/main.lib/Plugins/Interfaces/IValidationPluginOptionsFactory.cs b/src/main.lib/Plugins/Interfaces/IValidationPluginOptionsFactory.cs index f156632..02dabef 100644 --- a/src/main.lib/Plugins/Interfaces/IValidationPluginOptionsFactory.cs +++ b/src/main.lib/Plugins/Interfaces/IValidationPluginOptionsFactory.cs @@ -16,13 +16,13 @@ namespace PKISharp.WACS.Plugins.Interfaces /// Check or get information needed for store (interactive) /// </summary> /// <param name="target"></param> - Task<ValidationPluginOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel); + Task<ValidationPluginOptions?> Aquire(Target target, IInputService inputService, RunLevel runLevel); /// <summary> /// Check information needed for store (unattended) /// </summary> /// <param name="target"></param> - Task<ValidationPluginOptions> Default(Target target); + Task<ValidationPluginOptions?> Default(Target target); /// <summary> /// Is the validation option available for a specific target? diff --git a/src/main.lib/Plugins/Resolvers/UnattendedResolver.cs b/src/main.lib/Plugins/Resolvers/UnattendedResolver.cs index a04ee62..daa6e43 100644 --- a/src/main.lib/Plugins/Resolvers/UnattendedResolver.cs +++ b/src/main.lib/Plugins/Resolvers/UnattendedResolver.cs @@ -32,22 +32,21 @@ namespace PKISharp.WACS.Plugins.Resolvers /// ScheduledRenewal /// </summary> /// <returns></returns> - public virtual Task<ITargetPluginOptionsFactory> GetTargetPlugin(ILifetimeScope scope) + public virtual async Task<ITargetPluginOptionsFactory?> GetTargetPlugin(ILifetimeScope scope) { // Get plugin factory - var nullResult = Task.FromResult<ITargetPluginOptionsFactory>(new NullTargetFactory()); var targetPluginFactory = _plugins.TargetPluginFactory(scope, _options.MainArguments.Target); if (targetPluginFactory == null) { _log.Error("Unable to find target plugin {PluginName}", _options.MainArguments.Target); - return nullResult; + return new NullTargetFactory(); } if (targetPluginFactory.Disabled) { _log.Error("Target plugin {PluginName} is not available to the current user, try running as administrator", _options.MainArguments.Target); - return nullResult; + return new NullTargetFactory(); } - return Task.FromResult(targetPluginFactory); + return targetPluginFactory; } /// <summary> @@ -55,31 +54,31 @@ namespace PKISharp.WACS.Plugins.Resolvers /// to validate this ScheduledRenewal /// </summary> /// <returns></returns> - public virtual Task<IValidationPluginOptionsFactory> GetValidationPlugin(ILifetimeScope scope, Target target) + public virtual async Task<IValidationPluginOptionsFactory?> GetValidationPlugin(ILifetimeScope scope, Target target) { // Get plugin factory var validationPluginFactory = string.IsNullOrEmpty(_options.MainArguments.Validation) ? scope.Resolve<SelfHostingOptionsFactory>() - : _plugins.ValidationPluginFactory(scope, _options.MainArguments.ValidationMode, _options.MainArguments.Validation); - - var nullResult = Task.FromResult<IValidationPluginOptionsFactory>(new NullValidationFactory()); + : _plugins.ValidationPluginFactory(scope, + _options.MainArguments.ValidationMode ?? Constants.Http01ChallengeType, + _options.MainArguments.Validation); if (validationPluginFactory == null) { _log.Error("Unable to find validation plugin {PluginName}", _options.MainArguments.Validation); - return nullResult; + return new NullValidationFactory(); } if (validationPluginFactory.Disabled) { _log.Error("Validation plugin {PluginName} is not available to the current user, try running as administrator", validationPluginFactory.Name); - return nullResult; + return new NullValidationFactory(); } if (!validationPluginFactory.CanValidate(target)) { _log.Error("Validation plugin {PluginName} cannot validate this target", validationPluginFactory.Name); - return nullResult; + return new NullValidationFactory(); } - return Task.FromResult(validationPluginFactory); + return validationPluginFactory; } /// <summary> @@ -87,14 +86,11 @@ namespace PKISharp.WACS.Plugins.Resolvers /// this ScheduledRenewal /// </summary> /// <returns></returns> - public virtual Task<IInstallationPluginOptionsFactory> GetInstallationPlugin(ILifetimeScope scope, IEnumerable<Type> storeTypes, IEnumerable<IInstallationPluginOptionsFactory> chosen) + public virtual async Task<IInstallationPluginOptionsFactory?> GetInstallationPlugin(ILifetimeScope scope, IEnumerable<Type> storeTypes, IEnumerable<IInstallationPluginOptionsFactory> chosen) { - var nullResult = Task.FromResult<IInstallationPluginOptionsFactory>(new NullInstallationOptionsFactory()); - var nothingResult = Task.FromResult<IInstallationPluginOptionsFactory>(null); - if (string.IsNullOrEmpty(_options.MainArguments.Installation)) { - return nullResult; + return new NullInstallationOptionsFactory(); } else { @@ -102,7 +98,7 @@ namespace PKISharp.WACS.Plugins.Resolvers var index = chosen.Count(); if (index == parts.Count) { - return nullResult; + return new NullInstallationOptionsFactory(); } var name = parts[index]; @@ -110,19 +106,19 @@ namespace PKISharp.WACS.Plugins.Resolvers if (factory == null) { _log.Error("Unable to find installation plugin {PluginName}", name); - return nothingResult; + return null; } if (factory.Disabled) { _log.Error("Installation plugin {PluginName} is not available to the current user, try running as administrator", name); - return nothingResult; + return null; } if (!factory.CanInstall(storeTypes)) { _log.Error("Installation plugin {PluginName} cannot install from selected store(s)", name); - return nothingResult; + return null; } - return Task.FromResult(factory); + return factory; } } @@ -130,10 +126,8 @@ namespace PKISharp.WACS.Plugins.Resolvers /// Get the StorePlugin which is used to persist the certificate /// </summary> /// <returns></returns> - public virtual Task<IStorePluginOptionsFactory> GetStorePlugin(ILifetimeScope scope, IEnumerable<IStorePluginOptionsFactory> chosen) + public virtual async Task<IStorePluginOptionsFactory?> GetStorePlugin(ILifetimeScope scope, IEnumerable<IStorePluginOptionsFactory> chosen) { - var nullResult = Task.FromResult<IStorePluginOptionsFactory>(new NullStoreOptionsFactory()); - var nothingResult = Task.FromResult<IStorePluginOptionsFactory>(null); var args = _options.MainArguments.Store; if (string.IsNullOrEmpty(args)) { @@ -143,15 +137,20 @@ namespace PKISharp.WACS.Plugins.Resolvers } else { - return nullResult; + return new NullStoreOptionsFactory(); } } var parts = args.ParseCsv(); + if (parts == null) + { + return null; + } + var index = chosen.Count(); if (index == parts.Count) { - return nullResult; + return new NullStoreOptionsFactory(); } var name = parts[index]; @@ -159,14 +158,14 @@ namespace PKISharp.WACS.Plugins.Resolvers if (factory == null) { _log.Error("Unable to find store plugin {PluginName}", name); - return nothingResult; + return null; } if (factory.Disabled) { _log.Error("Store plugin {PluginName} is not available to the current user, try running as administrator", name); - return nothingResult; + return null; } - return Task.FromResult(factory); + return factory; } /// <summary> @@ -174,26 +173,25 @@ namespace PKISharp.WACS.Plugins.Resolvers /// and request the certificate /// </summary> /// <returns></returns> - public virtual Task<ICsrPluginOptionsFactory> GetCsrPlugin(ILifetimeScope scope) + public virtual async Task<ICsrPluginOptionsFactory?> GetCsrPlugin(ILifetimeScope scope) { var pluginName = _options.MainArguments.Csr; - var nothingResult = Task.FromResult<ICsrPluginOptionsFactory>(new NullCsrFactory()); if (string.IsNullOrEmpty(pluginName)) { - return Task.FromResult<ICsrPluginOptionsFactory>(scope.Resolve<RsaOptionsFactory>()); + return scope.Resolve<RsaOptionsFactory>(); } var ret = _plugins.CsrPluginFactory(scope, pluginName); if (ret == null) { _log.Error("Unable to find csr plugin {PluginName}", pluginName); - return nothingResult; + return new NullCsrFactory(); } if (ret.Disabled) { _log.Error("CSR plugin {PluginName} is not available to the current user, try running as administrator", pluginName); - return nothingResult; + return new NullCsrFactory(); } - return Task.FromResult(ret); + return ret; } } } diff --git a/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSsl.cs b/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSsl.cs index 21d6fa5..3103e36 100644 --- a/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSsl.cs +++ b/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSsl.cs @@ -15,7 +15,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins { private readonly ILogService _log; private readonly string _path; - private readonly string _password; + private readonly string? _password; public CentralSsl(ILogService log, ISettingsService settings, CentralSslOptions options) { @@ -25,17 +25,18 @@ namespace PKISharp.WACS.Plugins.StorePlugins options.PfxPassword.Value : settings.Store.DefaultCentralSslPfxPassword; - _path = !string.IsNullOrWhiteSpace(options.Path) ? + var path = !string.IsNullOrWhiteSpace(options.Path) ? options.Path : settings.Store.DefaultCentralSslStore; - if (_path.ValidPath(log)) + if (path != null && path.ValidPath(log)) { + _path = path; _log.Debug("Using Centralized SSL path: {_path}", _path); } else { - throw new Exception($"Specified CentralSsl path {_path} is not valid."); + throw new Exception($"Specified CentralSsl path {path} is not valid."); } } @@ -89,9 +90,9 @@ namespace PKISharp.WACS.Plugins.StorePlugins /// </summary> /// <param name="fi"></param> /// <returns></returns> - private X509Certificate2 LoadCertificate(FileInfo fi) + private X509Certificate2? LoadCertificate(FileInfo fi) { - X509Certificate2 cert = null; + X509Certificate2? cert = null; try { cert = new X509Certificate2(fi.FullName, _password); diff --git a/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslArguments.cs b/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslArguments.cs index 81edb3b..fab782e 100644 --- a/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslArguments.cs +++ b/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslArguments.cs @@ -3,7 +3,7 @@ internal class CentralSslArguments { public bool KeepExisting { get; set; } - public string CentralSslStore { get; set; } - public string PfxPassword { get; set; } + public string? CentralSslStore { get; set; } + public string? PfxPassword { get; set; } } } diff --git a/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptions.cs b/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptions.cs index 35efe49..9579d47 100644 --- a/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptions.cs +++ b/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptions.cs @@ -12,13 +12,13 @@ namespace PKISharp.WACS.Plugins.StorePlugins /// <summary> /// Path to the Central Ssl store /// </summary> - public string Path { get; set; } + public string? Path { get; set; } /// <summary> /// PfxFile password /// </summary> [JsonProperty(propertyName: "PfxPasswordProtected")] - public ProtectedString PfxPassword { get; set; } + public ProtectedString? PfxPassword { get; set; } internal const string PluginName = "CentralSsl"; public override string Name => PluginName; diff --git a/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptionsFactory.cs b/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptionsFactory.cs index b22c69e..cd8fe09 100644 --- a/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptionsFactory.cs +++ b/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptionsFactory.cs @@ -20,7 +20,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins _settings = settings; } - public override async Task<CentralSslOptions> Aquire(IInputService input, RunLevel runLevel) + public override async Task<CentralSslOptions?> Aquire(IInputService input, RunLevel runLevel) { var args = _arguments.GetArguments<CentralSslArguments>(); @@ -45,10 +45,10 @@ namespace PKISharp.WACS.Plugins.StorePlugins { password = await input.ReadPassword("Password to use for the PFX files, or enter for none"); } - return await Create(path, password, args.KeepExisting); + return Create(path, password, args.KeepExisting); } - public override Task<CentralSslOptions> Default() + public override async Task<CentralSslOptions?> Default() { var args = _arguments.GetArguments<CentralSslArguments>(); var path = _settings.Store.DefaultCentralSslStore; @@ -63,7 +63,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins password = args.PfxPassword; } - if (path.ValidPath(_log)) + if (path != null && path.ValidPath(_log)) { return Create(path, password, args.KeepExisting); } @@ -73,7 +73,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins } } - private Task<CentralSslOptions> Create(string path, string password, bool keepExisting) + private CentralSslOptions Create(string path, string? password, bool keepExisting) { var ret = new CentralSslOptions { @@ -87,7 +87,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins { ret.Path = path; } - return Task.FromResult(ret); + return ret; } } } diff --git a/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStore.cs b/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStore.cs index 253fe2d..4f2e8aa 100644 --- a/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStore.cs +++ b/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStore.cs @@ -19,7 +19,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins private readonly ILogService _log; private readonly ISettingsService _settings; private const string _defaultStoreName = nameof(StoreName.My); - private string _storeName; + private string? _storeName; private readonly X509Store _store; private readonly IIISClient _iisClient; private readonly CertificateStoreOptions _options; @@ -152,9 +152,9 @@ namespace PKISharp.WACS.Plugins.StorePlugins return Task.CompletedTask; } - public CertificateInfo FindByThumbprint(string thumbprint) => ToInfo(GetCertificate(CertificateService.ThumbprintFilter(thumbprint))); + public CertificateInfo? FindByThumbprint(string thumbprint) => ToInfo(GetCertificate(CertificateService.ThumbprintFilter(thumbprint))); - private CertificateInfo? ToInfo(X509Certificate2 cert) + private CertificateInfo? ToInfo(X509Certificate2? cert) { if (cert != null) { @@ -265,7 +265,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins _store.Close(); } - private X509Certificate2 GetCertificate(Func<X509Certificate2, bool> filter) + private X509Certificate2? GetCertificate(Func<X509Certificate2, bool> filter) { var possibles = new List<X509Certificate2>(); try diff --git a/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStoreArguments.cs b/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStoreArguments.cs index e38a9c3..df0ea00 100644 --- a/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStoreArguments.cs +++ b/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStoreArguments.cs @@ -3,7 +3,7 @@ internal class CertificateStoreArguments { public bool KeepExisting { get; set; } - public string CertificateStore { get; set; } - public string AclFullControl { get; set; } + public string? CertificateStore { get; set; } + public string? AclFullControl { get; set; } } } diff --git a/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStoreOptions.cs b/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStoreOptions.cs index fa4ec5f..b217d8a 100644 --- a/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStoreOptions.cs +++ b/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStoreOptions.cs @@ -15,12 +15,12 @@ namespace PKISharp.WACS.Plugins.StorePlugins /// <summary> /// Name of the certificate store to use /// </summary> - public string StoreName { get; set; } + public string? StoreName { get; set; } /// <summary> /// Name of the certificate store to use /// </summary> - public List<string> AclFullControl { get; set; } + public List<string>? AclFullControl { get; set; } public override void Show(IInputService input) { diff --git a/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStoreOptionsFactory.cs b/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStoreOptionsFactory.cs index 03dc288..edcb802 100644 --- a/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStoreOptionsFactory.cs +++ b/src/main.lib/Plugins/StorePlugins/CertificateStore/CertificateStoreOptionsFactory.cs @@ -15,9 +15,9 @@ namespace PKISharp.WACS.Plugins.StorePlugins Disabled = !userRoleService.IsAdmin; } - public override Task<CertificateStoreOptions> Aquire(IInputService inputService, RunLevel runLevel) => Default(); + public override Task<CertificateStoreOptions?> Aquire(IInputService inputService, RunLevel runLevel) => Default(); - public override Task<CertificateStoreOptions> Default() + public override async Task<CertificateStoreOptions?> Default() { var args = _arguments.GetArguments<CertificateStoreArguments>(); var ret = new CertificateStoreOptions { @@ -25,7 +25,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins KeepExisting = args.KeepExisting, AclFullControl = args.AclFullControl.ParseCsv() }; - return Task.FromResult(ret); + return ret; } } } diff --git a/src/main.lib/Plugins/StorePlugins/CertificateStore/FindPrivateKey.cs b/src/main.lib/Plugins/StorePlugins/CertificateStore/FindPrivateKey.cs index 7f8efb0..7c2c07b 100644 --- a/src/main.lib/Plugins/StorePlugins/CertificateStore/FindPrivateKey.cs +++ b/src/main.lib/Plugins/StorePlugins/CertificateStore/FindPrivateKey.cs @@ -16,7 +16,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins public FindPrivateKey(ILogService log) => _log = log; - internal FileInfo Find(X509Certificate2 cert) + internal FileInfo? Find(X509Certificate2 cert) { string file; string dir; @@ -47,7 +47,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins var freeProvider = false; // Do we need to free the CSP ? uint acquireFlags = 0; var _keyNumber = 0; - string keyFileName = null; + string? keyFileName = null; // Determine whether there is private key information available for this certificate in the key store if (CryptAcquireCertificatePrivateKey(cert.Handle, acquireFlags, IntPtr.Zero, ref hProvider, ref _keyNumber, ref freeProvider)) diff --git a/src/main.lib/Plugins/StorePlugins/PemFiles/PemFiles.cs b/src/main.lib/Plugins/StorePlugins/PemFiles/PemFiles.cs index be7e2fb..4966053 100644 --- a/src/main.lib/Plugins/StorePlugins/PemFiles/PemFiles.cs +++ b/src/main.lib/Plugins/StorePlugins/PemFiles/PemFiles.cs @@ -24,16 +24,17 @@ namespace PKISharp.WACS.Plugins.StorePlugins { _log = log; _pemService = pemService; - _path = !string.IsNullOrWhiteSpace(options.Path) ? + var path = !string.IsNullOrWhiteSpace(options.Path) ? options.Path : settings.Store.DefaultPemFilesPath; - if (_path.ValidPath(log)) + if (path != null && _path.ValidPath(log)) { - _log.Debug("Using .pem certificate path: {_path}", _path); + _log.Debug("Using .pem certificate path: {path}", path); + _path = path; } else { - throw new Exception($"Specified PemFiles path {_path} is not valid."); + throw new Exception($"Specified PemFiles path {path} is not valid."); } } @@ -106,7 +107,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins public Task Delete(CertificateInfo input) => Task.CompletedTask; - public CertificateInfo FindByThumbprint() => null; + public CertificateInfo? FindByThumbprint() => null; bool IPlugin.Disabled => false; } diff --git a/src/main.lib/Plugins/StorePlugins/PemFiles/PemFilesArguments.cs b/src/main.lib/Plugins/StorePlugins/PemFiles/PemFilesArguments.cs index 0f6b2b9..034fcc8 100644 --- a/src/main.lib/Plugins/StorePlugins/PemFiles/PemFilesArguments.cs +++ b/src/main.lib/Plugins/StorePlugins/PemFiles/PemFilesArguments.cs @@ -2,6 +2,6 @@ { internal class PemFilesArguments { - public string PemFilesPath { get; set; } + public string? PemFilesPath { get; set; } } } diff --git a/src/main.lib/Plugins/StorePlugins/PemFiles/PemFilesOptions.cs b/src/main.lib/Plugins/StorePlugins/PemFiles/PemFilesOptions.cs index 14b60c6..4fb5892 100644 --- a/src/main.lib/Plugins/StorePlugins/PemFiles/PemFilesOptions.cs +++ b/src/main.lib/Plugins/StorePlugins/PemFiles/PemFilesOptions.cs @@ -7,15 +7,16 @@ namespace PKISharp.WACS.Plugins.StorePlugins [Plugin("e57c70e4-cd60-4ba6-80f6-a41703e21031")] internal class PemFilesOptions : StorePluginOptions<PemFiles> { - /// <summary> - /// Path to the .pem directory - /// </summary> - public string Path { get; set; } internal const string PluginName = "PemFiles"; public override string Name => PluginName; public override string Description => "PEM encoded files (Apache, nginx, etc.)"; /// <summary> + /// Path to the .pem directory + /// </summary> + public string? Path { get; set; } + + /// <summary> /// Show details to the user /// </summary> /// <param name="input"></param> diff --git a/src/main.lib/Plugins/StorePlugins/PemFiles/PemFilesOptionsFactory.cs b/src/main.lib/Plugins/StorePlugins/PemFiles/PemFilesOptionsFactory.cs index 6429c66..02a26cf 100644 --- a/src/main.lib/Plugins/StorePlugins/PemFiles/PemFilesOptionsFactory.cs +++ b/src/main.lib/Plugins/StorePlugins/PemFiles/PemFilesOptionsFactory.cs @@ -19,7 +19,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins _settings = settings; } - public override async Task<PemFilesOptions> Aquire(IInputService input, RunLevel runLevel) + public override async Task<PemFilesOptions?> Aquire(IInputService input, RunLevel runLevel) { var args = _arguments.GetArguments<PemFilesArguments>(); var path = args.PemFilesPath; @@ -31,10 +31,10 @@ namespace PKISharp.WACS.Plugins.StorePlugins { path = await input.RequestString("Path to folder where .pem files are stored"); } - return await Create(path); + return Create(path); } - public override Task<PemFilesOptions> Default() + public override async Task<PemFilesOptions?> Default() { var args = _arguments.GetArguments<PemFilesArguments>(); var path = _settings.Store.DefaultPemFilesPath; @@ -52,14 +52,14 @@ namespace PKISharp.WACS.Plugins.StorePlugins } } - private Task<PemFilesOptions> Create(string path) + private PemFilesOptions Create(string path) { var ret = new PemFilesOptions(); if (!string.Equals(path, _settings.Store.DefaultPemFilesPath, StringComparison.CurrentCultureIgnoreCase)) { ret.Path = path; } - return Task.FromResult(ret); + return ret; } } diff --git a/src/main.lib/Plugins/TargetPlugins/Csr/Csr.cs b/src/main.lib/Plugins/TargetPlugins/Csr/Csr.cs index 78b2b1b..eb819f5 100644 --- a/src/main.lib/Plugins/TargetPlugins/Csr/Csr.cs +++ b/src/main.lib/Plugins/TargetPlugins/Csr/Csr.cs @@ -28,7 +28,7 @@ namespace PKISharp.WACS.Plugins.TargetPlugins _options = options; } - public Task<Target> Generate() + public async Task<Target?> Generate() { // Read CSR string csrString; @@ -39,7 +39,7 @@ namespace PKISharp.WACS.Plugins.TargetPlugins catch (Exception ex) { _log.Error(ex, "Unable to read CSR from {CsrFile}", _options.CsrFile); - return Task.FromResult<Target>(null); + return null; } // Parse CSR @@ -49,6 +49,10 @@ namespace PKISharp.WACS.Plugins.TargetPlugins try { var pem = _pem.ParsePem<Pkcs10CertificationRequest>(csrString); + if (pem == null) + { + throw new Exception("Unable decode PEM bytes to Pkcs10CertificationRequest"); + } var info = pem.GetCertificationRequestInfo(); csrBytes = pem.GetEncoded(); commonName = ParseCn(info); @@ -61,10 +65,10 @@ namespace PKISharp.WACS.Plugins.TargetPlugins catch (Exception ex) { _log.Error(ex, "Unable to parse CSR"); - return Task.FromResult<Target>(null); + return null; } - AsymmetricKeyParameter pkBytes = null; + AsymmetricKeyParameter? pkBytes = null; if (!string.IsNullOrWhiteSpace(_options.PkFile)) { // Read PK @@ -100,18 +104,16 @@ namespace PKISharp.WACS.Plugins.TargetPlugins } } - return Task.FromResult(new Target() + return new Target() { FriendlyName = $"[{nameof(Csr)}] {_options.CsrFile}", CommonName = commonName, Parts = new List<TargetPart> { - new TargetPart { - Identifiers = alternativeNames - } + new TargetPart(alternativeNames) }, CsrBytes = csrBytes, PrivateKey = pkBytes - }); + }; } /// <summary> @@ -173,7 +175,7 @@ namespace PKISharp.WACS.Plugins.TargetPlugins return names.GetNames().Select(x => ProcessName(x.Name.ToString())); } - private T GetAsn1ObjectRecursive<T>(DerSequence sequence, string id) where T : Asn1Object + private T? GetAsn1ObjectRecursive<T>(DerSequence sequence, string id) where T : Asn1Object { if (sequence.OfType<DerObjectIdentifier>().Any(o => o.Id == id)) { diff --git a/src/main.lib/Plugins/TargetPlugins/Csr/CsrArguments.cs b/src/main.lib/Plugins/TargetPlugins/Csr/CsrArguments.cs index b2eb910..0564831 100644 --- a/src/main.lib/Plugins/TargetPlugins/Csr/CsrArguments.cs +++ b/src/main.lib/Plugins/TargetPlugins/Csr/CsrArguments.cs @@ -2,8 +2,8 @@ { internal class CsrArguments { - public string CsrFile { get; set; } + public string? CsrFile { get; set; } - public string PkFile { get; set; } + public string? PkFile { get; set; } } } diff --git a/src/main.lib/Plugins/TargetPlugins/Csr/CsrOptionsFactory.cs b/src/main.lib/Plugins/TargetPlugins/Csr/CsrOptionsFactory.cs index 2e4b7e2..a51ac09 100644 --- a/src/main.lib/Plugins/TargetPlugins/Csr/CsrOptionsFactory.cs +++ b/src/main.lib/Plugins/TargetPlugins/Csr/CsrOptionsFactory.cs @@ -18,7 +18,7 @@ namespace PKISharp.WACS.Plugins.TargetPlugins public override int Order => 6; - public override async Task<CsrOptions> Aquire(IInputService inputService, RunLevel runLevel) + public override async Task<CsrOptions?> Aquire(IInputService inputService, RunLevel runLevel) { var args = _arguments.GetArguments<CsrArguments>(); var ret = new CsrOptions(); @@ -31,7 +31,7 @@ namespace PKISharp.WACS.Plugins.TargetPlugins } while (!ret.CsrFile.ValidFile(_log)); - string pkFile; + string? pkFile; do { pkFile = await _arguments.TryGetArgument(args.CsrFile, @@ -48,25 +48,25 @@ namespace PKISharp.WACS.Plugins.TargetPlugins return ret; } - public override Task<CsrOptions> Default() + public override async Task<CsrOptions?> Default() { var args = _arguments.GetArguments<CsrArguments>(); if (!args.CsrFile.ValidFile(_log)) { - return Task.FromResult(default(CsrOptions)); + return null; } if (!string.IsNullOrEmpty(args.PkFile)) { if (!args.PkFile.ValidFile(_log)) { - return Task.FromResult(default(CsrOptions)); + return null; } } - return Task.FromResult(new CsrOptions() + return new CsrOptions() { CsrFile = args.CsrFile, PkFile = string.IsNullOrWhiteSpace(args.PkFile) ? null : args.PkFile - }); + }; } } } diff --git a/src/main.lib/Plugins/TargetPlugins/IIS/IIS.cs b/src/main.lib/Plugins/TargetPlugins/IIS/IIS.cs index bcfa395..2a70663 100644 --- a/src/main.lib/Plugins/TargetPlugins/IIS/IIS.cs +++ b/src/main.lib/Plugins/TargetPlugins/IIS/IIS.cs @@ -80,10 +80,9 @@ namespace PKISharp.WACS.Plugins.TargetPlugins CommonName = cnValid ? cn : filteredBindings.First().HostUnicode, Parts = filteredBindings. GroupBy(x => x.SiteId). - Select(group => new TargetPart + Select(group => new TargetPart(group.Select(x => x.HostUnicode)) { - SiteId = group.Key, - Identifiers = group.Select(x => x.HostUnicode).ToList() + SiteId = group.Key }). ToList() }; diff --git a/src/main.lib/Plugins/TargetPlugins/IIS/IISOptionsFactory.cs b/src/main.lib/Plugins/TargetPlugins/IIS/IISOptionsFactory.cs index 53bcb53..fa6333d 100644 --- a/src/main.lib/Plugins/TargetPlugins/IIS/IISOptionsFactory.cs +++ b/src/main.lib/Plugins/TargetPlugins/IIS/IISOptionsFactory.cs @@ -218,7 +218,7 @@ namespace PKISharp.WACS.Plugins.TargetPlugins } // Now the common name - if (filtered.Count > 1) + if (filtered.Select(x => x.HostUnicode).Distinct().Count() > 1) { // If no bindings have been excluded, we can re-use // the previously printed list @@ -399,21 +399,18 @@ namespace PKISharp.WACS.Plugins.TargetPlugins if (!runLevel.HasFlag(RunLevel.Advanced) && binding.Wildcard) { return ConsoleColor.Red; - } - if (binding.HostUnicode == highlight) + } + else if (binding.HostUnicode == highlight) { return ConsoleColor.Green; } + else if (binding.Https) + { + return ConsoleColor.DarkGray; + } else { - if (binding.Https) - { - return ConsoleColor.DarkGray; - } - else - { - return default(ConsoleColor); - } + return default(ConsoleColor?); } } diff --git a/src/main.lib/Plugins/TargetPlugins/Manual/Manual.cs b/src/main.lib/Plugins/TargetPlugins/Manual/Manual.cs index 72edb90..de82b5a 100644 --- a/src/main.lib/Plugins/TargetPlugins/Manual/Manual.cs +++ b/src/main.lib/Plugins/TargetPlugins/Manual/Manual.cs @@ -11,18 +11,16 @@ namespace PKISharp.WACS.Plugins.TargetPlugins public Manual(ManualOptions options) => _options = options; - public Task<Target> Generate() + public async Task<Target?> Generate() { - return Task.FromResult(new Target() + return new Target() { FriendlyName = $"[{nameof(Manual)}] {_options.CommonName}", CommonName = _options.CommonName, Parts = new List<TargetPart> { - new TargetPart { - Identifiers = _options.AlternativeNames - } + new TargetPart(_options.AlternativeNames) } - }); + }; } bool IPlugin.Disabled => false; diff --git a/src/main.lib/Plugins/TargetPlugins/Manual/ManualArguments.cs b/src/main.lib/Plugins/TargetPlugins/Manual/ManualArguments.cs index a6199b3..b887b1d 100644 --- a/src/main.lib/Plugins/TargetPlugins/Manual/ManualArguments.cs +++ b/src/main.lib/Plugins/TargetPlugins/Manual/ManualArguments.cs @@ -2,7 +2,7 @@ { internal class ManualArguments { - public string CommonName { get; set; } - public string Host { get; set; } + public string? CommonName { get; set; } + public string? Host { get; set; } } } diff --git a/src/main.lib/Plugins/TargetPlugins/Manual/ManualOptions.cs b/src/main.lib/Plugins/TargetPlugins/Manual/ManualOptions.cs index 2b72f70..f7a8e47 100644 --- a/src/main.lib/Plugins/TargetPlugins/Manual/ManualOptions.cs +++ b/src/main.lib/Plugins/TargetPlugins/Manual/ManualOptions.cs @@ -13,8 +13,8 @@ namespace PKISharp.WACS.Plugins.TargetPlugins public override string Name => "Manual"; public override string Description => DescriptionText; - public string CommonName { get; set; } - public List<string> AlternativeNames { get; set; } + public string? CommonName { get; set; } + public List<string>? AlternativeNames { get; set; } public override void Show(IInputService input) { diff --git a/src/main.lib/Plugins/TargetPlugins/Manual/ManualOptionsFactory.cs b/src/main.lib/Plugins/TargetPlugins/Manual/ManualOptionsFactory.cs index c0b3fb6..363f839 100644 --- a/src/main.lib/Plugins/TargetPlugins/Manual/ManualOptionsFactory.cs +++ b/src/main.lib/Plugins/TargetPlugins/Manual/ManualOptionsFactory.cs @@ -11,7 +11,7 @@ namespace PKISharp.WACS.Plugins.TargetPlugins private readonly IArgumentsService _arguments; public ManualOptionsFactory(IArgumentsService arguments) => _arguments = arguments; public override int Order => 5; - public override async Task<ManualOptions> Aquire(IInputService inputService, RunLevel runLevel) + public override async Task<ManualOptions?> Aquire(IInputService inputService, RunLevel runLevel) { var input = await inputService.RequestString("Enter comma-separated list of host names, starting with the common name"); if (string.IsNullOrEmpty(input)) @@ -24,25 +24,28 @@ namespace PKISharp.WACS.Plugins.TargetPlugins } } - public override Task<ManualOptions> Default() + public override async Task<ManualOptions?> Default() { var args = _arguments.GetArguments<ManualArguments>(); var input = _arguments.TryGetRequiredArgument(nameof(args.Host), args.Host); var ret = Create(input); - var commonName = args.CommonName; - if (!string.IsNullOrWhiteSpace(commonName)) + if (ret != null) { - commonName = commonName.ToLower().Trim().ConvertPunycode(); - ret.CommonName = commonName; - if (!ret.AlternativeNames.Contains(commonName)) + var commonName = args.CommonName; + if (!string.IsNullOrWhiteSpace(commonName)) { - ret.AlternativeNames.Insert(0, commonName); + commonName = commonName.ToLower().Trim().ConvertPunycode(); + ret.CommonName = commonName; + if (!ret.AlternativeNames.Contains(commonName)) + { + ret.AlternativeNames.Insert(0, commonName); + } } } - return Task.FromResult(ret); + return ret; } - private ManualOptions Create(string input) + private ManualOptions? Create(string? input) { var sanList = input.ParseCsv().Select(x => x.ConvertPunycode()); if (sanList != null) diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Manual/ManualOptionsFactory.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Manual/ManualOptionsFactory.cs index 323243f..2c6eeb8 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Dns/Manual/ManualOptionsFactory.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Manual/ManualOptionsFactory.cs @@ -8,8 +8,8 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns internal class ManualOptionsFactory : ValidationPluginOptionsFactory<Manual, ManualOptions> { public ManualOptionsFactory() : base(Constants.Dns01ChallengeType) { } - public override Task<ManualOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel) => Task.FromResult(new ManualOptions()); - public override Task<ManualOptions> Default(Target target) => Task.FromResult(new ManualOptions()); + public override async Task<ManualOptions?> Aquire(Target target, IInputService inputService, RunLevel runLevel) => new ManualOptions(); + public override async Task<ManualOptions?> Default(Target target) => new ManualOptions(); public override bool CanValidate(Target target) => true; } } diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptArguments.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptArguments.cs index 85e879f..74109f5 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptArguments.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptArguments.cs @@ -2,10 +2,10 @@ { internal class ScriptArguments { - public string DnsScript { get; set; } - public string DnsCreateScript { get; set; } - public string DnsCreateScriptArguments { get; set; } - public string DnsDeleteScript { get; set; } - public string DnsDeleteScriptArguments { get; set; } + public string? DnsScript { get; set; } + public string? DnsCreateScript { get; set; } + public string? DnsCreateScriptArguments { get; set; } + public string? DnsDeleteScript { get; set; } + public string? DnsDeleteScriptArguments { get; set; } } } diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptOptionsFactory.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptOptionsFactory.cs index ad4c34f..c974b2a 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptOptionsFactory.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptOptionsFactory.cs @@ -30,7 +30,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns _arguments = arguments; } - public override async Task<ScriptOptions> Aquire(Target target, IInputService input, RunLevel runLevel) + public override async Task<ScriptOptions?> Aquire(Target target, IInputService input, RunLevel runLevel) { var args = _arguments.GetArguments<ScriptArguments>(); var ret = new ScriptOptions(); @@ -79,7 +79,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns return ret; } - public override Task<ScriptOptions> Default(Target target) + public override async Task<ScriptOptions?> Default(Target target) { var args = _arguments.GetArguments<ScriptArguments>(); var ret = new ScriptOptions(); @@ -89,7 +89,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns if (!ret.Script.ValidFile(_log)) { _log.Error($"Invalid argument --{nameof(args.DnsScript).ToLower()}"); - return Task.FromResult(default(ScriptOptions)); + return null; } } else @@ -97,20 +97,20 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns if (!ret.CreateScript.ValidFile(_log)) { _log.Error($"Invalid argument --{nameof(args.DnsCreateScript).ToLower()}"); - return Task.FromResult(default(ScriptOptions)); + return null; } if (!string.IsNullOrEmpty(ret.DeleteScript)) { if (!ret.DeleteScript.ValidFile(_log)) { _log.Error($"Invalid argument --{nameof(args.DnsDeleteScript).ToLower()}"); - return Task.FromResult(default(ScriptOptions)); + return null; } } } ProcessArgs(ret, args.DnsCreateScriptArguments, args.DnsDeleteScriptArguments); - return Task.FromResult(ret); + return ret; } /// <summary> @@ -120,7 +120,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns /// <param name="commonInput"></param> /// <param name="createInput"></param> /// <param name="deleteInput"></param> - private void ProcessScripts(ScriptOptions options, string commonInput, string createInput, string deleteInput) + private void ProcessScripts(ScriptOptions options, string? commonInput, string? createInput, string? deleteInput) { if (!string.IsNullOrWhiteSpace(commonInput)) { @@ -151,7 +151,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns } } - private void ProcessArgs(ScriptOptions options, string createInput, string deleteInput) + private void ProcessArgs(ScriptOptions options, string? createInput, string? deleteInput) { if (!string.IsNullOrWhiteSpace(createInput) && createInput != Script.DefaultCreateArguments) diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/FileSystem/FileSystemOptionsFactory.cs b/src/main.lib/Plugins/ValidationPlugins/Http/FileSystem/FileSystemOptionsFactory.cs index c56ddf4..aa86b9b 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/FileSystem/FileSystemOptionsFactory.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/FileSystem/FileSystemOptionsFactory.cs @@ -25,7 +25,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http public override bool PathIsValid(string path) => path.ValidPath(_log); public override bool AllowEmtpy(Target target) => target.IIS; - public override Task<FileSystemOptions> Default(Target target) + public override async Task<FileSystemOptions?> Default(Target target) { var args = _arguments.GetArguments<FileSystemArguments>(); var ret = new FileSystemOptions(BaseDefault(target)); @@ -40,10 +40,10 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http ret.SiteId = args.ValidationSiteId.Value; } } - return Task.FromResult(ret); + return ret; } - public override async Task<FileSystemOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel) + public override async Task<FileSystemOptions?> Aquire(Target target, IInputService inputService, RunLevel runLevel) { // Choose alternative site for validation var ret = new FileSystemOptions(await BaseAquire(target, inputService)); diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/Ftp.cs b/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/Ftp.cs index 7c3d2bf..5ceadec 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/Ftp.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/Ftp.cs @@ -6,7 +6,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http { internal class Ftp : HttpValidation<FtpOptions, Ftp> { - private FtpClient _ftpClient; + private FtpClient? _ftpClient; public Ftp(FtpOptions options, HttpValidationParameters pars, RunLevel runLevel) : base(options, runLevel, pars) => _ftpClient = new FtpClient(_options.Credential, pars.LogService); diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/FtpOptions.cs b/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/FtpOptions.cs index a90764d..fd9710d 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/FtpOptions.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/FtpOptions.cs @@ -16,7 +16,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http /// <summary> /// Credentials to use for WebDav connection /// </summary> - public NetworkCredentialOptions Credential { get; set; } + public NetworkCredentialOptions? Credential { get; set; } /// <summary> /// Show settings to user diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/FtpOptionsFactory.cs b/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/FtpOptionsFactory.cs index 8510b30..a71763b 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/FtpOptionsFactory.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/Ftp/FtpOptionsFactory.cs @@ -37,15 +37,15 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http }; } - public override Task<FtpOptions> Default(Target target) + public override async Task<FtpOptions?> Default(Target target) { - return Task.FromResult(new FtpOptions(BaseDefault(target)) + return new FtpOptions(BaseDefault(target)) { Credential = new NetworkCredentialOptions(_arguments) - }); + }; } - public override async Task<FtpOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel) + public override async Task<FtpOptions?> Aquire(Target target, IInputService inputService, RunLevel runLevel) { return new FtpOptions(await BaseAquire(target, inputService)) { diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidation.cs b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidation.cs index ab791cf..3335cea 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidation.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidation.cs @@ -34,7 +34,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// Path used for the current renewal, may not be same as _options.Path /// because of the "Split" function employed by IISSites target /// </summary> - protected string _path; + protected string? _path; /// <summary> /// Provides proxy settings for site warmup @@ -145,6 +145,10 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// <param name="fileContents">the contents of the file to write</param> private void WriteAuthorizationFile() { + if (_path == null || _challenge == null) + { + throw new InvalidOperationException(); + } WriteFile(CombinePath(_path, _challenge.HttpResourcePath), _challenge.HttpResourceValue); _challengeWritten = true; } @@ -157,6 +161,10 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// <param name="token"></param> private void WriteWebConfig() { + if (_path == null) + { + throw new InvalidOperationException(); + } if (_options.CopyWebConfig == true) { _log.Debug("Writing web.config"); @@ -182,6 +190,10 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// <param name="token"></param> private void DeleteWebConfig() { + if (_path == null || _challenge == null) + { + throw new InvalidOperationException(); + } if (_webConfigWritten) { _log.Debug("Deleting web.config"); @@ -202,7 +214,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins { try { - if (_challengeWritten) + if (_path != null && _challenge != null && _challengeWritten) { _log.Debug("Deleting answer"); var path = CombinePath(_path, _challenge.HttpResourcePath); diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationArguments.cs b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationArguments.cs index 0774419..b10e384 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationArguments.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationArguments.cs @@ -2,7 +2,7 @@ { internal class HttpValidationArguments { - public string WebRoot { get; set; } + public string? WebRoot { get; set; } public bool Warmup { get; set; } public bool ManualTargetIsIIS { get; set; } } diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationOptions.cs b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationOptions.cs index 6546a9a..2a83a98 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationOptions.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationOptions.cs @@ -6,7 +6,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins { internal abstract class HttpValidationOptions<T> : ValidationPluginOptions<T> where T : IValidationPlugin { - public string Path { get; set; } + public string? Path { get; set; } public bool? CopyWebConfig { get; set; } public HttpValidationOptions() { } diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationOptionsFactory.cs b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationOptionsFactory.cs index 377bdf8..f98a2e8 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationOptionsFactory.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/HttpValidationOptionsFactory.cs @@ -56,7 +56,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// </summary> public HttpValidationOptions<TPlugin> BaseDefault(Target target) { - string path = null; + string? path = null; var allowEmpty = AllowEmtpy(target); var args = _arguments.GetArguments<HttpValidationArguments>(); if (string.IsNullOrEmpty(path) && !allowEmpty) diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/SelfHosting/SelfHosting.cs b/src/main.lib/Plugins/ValidationPlugins/Http/SelfHosting/SelfHosting.cs index 5eeae60..d646ae8 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/SelfHosting/SelfHosting.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/SelfHosting/SelfHosting.cs @@ -10,7 +10,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http internal class SelfHosting : Validation<Http01ChallengeValidationDetails> { internal const int DefaultValidationPort = 80; - private HttpListener _listener; + private HttpListener? _listener; private readonly Dictionary<string, string> _files; private readonly SelfHostingOptions _options; private readonly ILogService _log; diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/SelfHosting/SelfHostingOptionsFactory.cs b/src/main.lib/Plugins/ValidationPlugins/Http/SelfHosting/SelfHostingOptionsFactory.cs index 2eb55cc..d2696a7 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/SelfHosting/SelfHostingOptionsFactory.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/SelfHosting/SelfHostingOptionsFactory.cs @@ -18,15 +18,15 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http public override bool Disabled => SelfHosting.IsDisabled(_userRoleService); - public override Task<SelfHostingOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel) => Default(target); + public override Task<SelfHostingOptions?> Aquire(Target target, IInputService inputService, RunLevel runLevel) => Default(target); - public override Task<SelfHostingOptions> Default(Target target) + public override async Task<SelfHostingOptions?> Default(Target target) { var args = _arguments.GetArguments<SelfHostingArguments>(); - return Task.FromResult(new SelfHostingOptions() + return new SelfHostingOptions() { Port = args.ValidationPort - }); + }; } } }
\ No newline at end of file diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/Sftp/Sftp.cs b/src/main.lib/Plugins/ValidationPlugins/Http/Sftp/Sftp.cs index 91981d5..f3f536c 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/Sftp/Sftp.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/Sftp/Sftp.cs @@ -6,7 +6,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http { internal class Sftp : HttpValidation<SftpOptions, Sftp> { - private SshFtpClient _sshFtpClient; + private SshFtpClient? _sshFtpClient; public Sftp(SftpOptions options, HttpValidationParameters pars, RunLevel runLevel) : base(options, runLevel, pars) => _sshFtpClient = new SshFtpClient(_options.Credential.GetCredential(), pars.LogService); diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/Sftp/SftpOptionsFactory.cs b/src/main.lib/Plugins/ValidationPlugins/Http/Sftp/SftpOptionsFactory.cs index 754bba3..31c2c3b 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/Sftp/SftpOptionsFactory.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/Sftp/SftpOptionsFactory.cs @@ -22,15 +22,15 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http }; } - public override Task<SftpOptions> Default(Target target) + public override async Task<SftpOptions?> Default(Target target) { - return Task.FromResult(new SftpOptions(BaseDefault(target)) + return new SftpOptions(BaseDefault(target)) { Credential = new NetworkCredentialOptions(_arguments) - }); + }; } - public override async Task<SftpOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel) + public override async Task<SftpOptions?> Aquire(Target target, IInputService inputService, RunLevel runLevel) { return new SftpOptions(await BaseAquire(target, inputService)) { diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDav.cs b/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDav.cs index dcead5c..990f338 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDav.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDav.cs @@ -6,7 +6,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http { internal class WebDav : HttpValidation<WebDavOptions, WebDav> { - private WebDavClientWrapper _webdavClient; + private readonly WebDavClientWrapper _webdavClient; public WebDav( WebDavOptions options, HttpValidationParameters pars, @@ -25,7 +25,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http public override Task CleanUp() { base.CleanUp(); - _webdavClient = null; + _webdavClient.Dispose(); return Task.CompletedTask; } } diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDavOptions.cs b/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDavOptions.cs index 540f135..bcb9a20 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDavOptions.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDavOptions.cs @@ -16,7 +16,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http /// <summary> /// Credentials to use for WebDav connection /// </summary> - public NetworkCredentialOptions Credential { get; set; } + public NetworkCredentialOptions? Credential { get; set; } /// <summary> /// Show settings to user diff --git a/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDavOptionsFactory.cs b/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDavOptionsFactory.cs index 49ea451..f9f358c 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDavOptionsFactory.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Http/WebDav/WebDavOptionsFactory.cs @@ -28,15 +28,15 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Http }; } - public override Task<WebDavOptions> Default(Target target) + public override async Task<WebDavOptions?> Default(Target target) { - return Task.FromResult(new WebDavOptions(BaseDefault(target)) + return new WebDavOptions(BaseDefault(target)) { Credential = new NetworkCredentialOptions(_arguments) - }); + }; } - public override async Task<WebDavOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel) + public override async Task<WebDavOptions?> Aquire(Target target, IInputService inputService, RunLevel runLevel) { return new WebDavOptions(await BaseAquire(target, inputService)) { diff --git a/src/main.lib/Plugins/ValidationPlugins/Tls/SelfHosting/SelfHosting.cs b/src/main.lib/Plugins/ValidationPlugins/Tls/SelfHosting/SelfHosting.cs index 44dbc74..37a9cea 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Tls/SelfHosting/SelfHosting.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Tls/SelfHosting/SelfHosting.cs @@ -18,8 +18,8 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Tls internal class SelfHosting : Validation<TlsAlpn01ChallengeValidationDetails> { internal const int DefaultValidationPort = 443; - private TcpListener _listener; - private X509Certificate2 _certificate; + private TcpListener? _listener; + private X509Certificate2? _certificate; private readonly string _identifier; private readonly SelfHostingOptions _options; private readonly ILogService _log; diff --git a/src/main.lib/Plugins/ValidationPlugins/Tls/SelfHosting/SelfHostingOptionsFactory.cs b/src/main.lib/Plugins/ValidationPlugins/Tls/SelfHosting/SelfHostingOptionsFactory.cs index 1d6d962..f2a7e49 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Tls/SelfHosting/SelfHostingOptionsFactory.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Tls/SelfHosting/SelfHostingOptionsFactory.cs @@ -20,15 +20,15 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Tls public override bool Disabled => SelfHosting.IsDisabled(_userRoleService); - public override Task<SelfHostingOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel) => Default(target); + public override Task<SelfHostingOptions?> Aquire(Target target, IInputService inputService, RunLevel runLevel) => Default(target); - public override Task<SelfHostingOptions> Default(Target target) + public override async Task<SelfHostingOptions?> Default(Target target) { var args = _arguments.GetArguments<SelfHostingArguments>(); - return Task.FromResult(new SelfHostingOptions() + return new SelfHostingOptions() { Port = args.ValidationPort - }); + }; } } }
\ No newline at end of file diff --git a/src/main.lib/Plugins/ValidationPlugins/Validation.cs b/src/main.lib/Plugins/ValidationPlugins/Validation.cs index a5fd057..0743469 100644 --- a/src/main.lib/Plugins/ValidationPlugins/Validation.cs +++ b/src/main.lib/Plugins/ValidationPlugins/Validation.cs @@ -8,9 +8,9 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins /// <summary> /// Base implementation for all validation plugins /// </summary> - public abstract class Validation<TChallenge> : IValidationPlugin where TChallenge : IChallengeValidationDetails + public abstract class Validation<TChallenge> : IValidationPlugin where TChallenge : class, IChallengeValidationDetails { - protected TChallenge _challenge; + protected TChallenge? _challenge; /// <summary> /// Handle the challenge diff --git a/src/main.lib/RenewalExecutor.cs b/src/main.lib/RenewalExecutor.cs index 9574dbb..2e5824c 100644 --- a/src/main.lib/RenewalExecutor.cs +++ b/src/main.lib/RenewalExecutor.cs @@ -41,7 +41,7 @@ namespace PKISharp.WACS _container = container; } - public async Task<RenewResult> Renew(Renewal renewal, RunLevel runLevel) + public async Task<RenewResult?> Renew(Renewal renewal, RunLevel runLevel) { using var ts = _scopeBuilder.Target(_container, renewal, runLevel); using var es = _scopeBuilder.Execution(ts, renewal, runLevel); @@ -352,7 +352,7 @@ namespace PKISharp.WACS else { using var validation = _scopeBuilder.Validation(execute, options, targetPart, identifier); - IValidationPlugin validationPlugin = null; + IValidationPlugin? validationPlugin = null; try { validationPlugin = validation.Resolve<IValidationPlugin>(); @@ -397,7 +397,7 @@ namespace PKISharp.WACS options.Name); try { - var details = client.DecodeChallengeValidation(authorization, challenge); + var details = await client.DecodeChallengeValidation(authorization, challenge); await validationPlugin.PrepareChallenge(details); } catch (Exception ex) diff --git a/src/main.lib/RenewalManager.cs b/src/main.lib/RenewalManager.cs index 1b22b11..b450a8f 100644 --- a/src/main.lib/RenewalManager.cs +++ b/src/main.lib/RenewalManager.cs @@ -376,9 +376,13 @@ namespace PKISharp.WACS // Try to run for the first time var renewal = await CreateRenewal(tempRenewal, runLevel); var result = await _renewalExecution.Renew(renewal, runLevel); - if (!result.Success) + if (result == null) { - _exceptionHandler.HandleException(message: $"Create certificate failed: {result.ErrorMessage}"); + _exceptionHandler.HandleException(message: $"Create certificate cancelled"); + } + else if (!result.Success) + { + _exceptionHandler.HandleException(message: $"Create certificate failed: {result?.ErrorMessage}"); } else { diff --git a/src/main.lib/Services/ArgumentsParser.cs b/src/main.lib/Services/ArgumentsParser.cs index bf9d079..30e40a6 100644 --- a/src/main.lib/Services/ArgumentsParser.cs +++ b/src/main.lib/Services/ArgumentsParser.cs @@ -11,16 +11,16 @@ namespace PKISharp.WACS.Configuration private readonly string[] _args; private readonly List<IArgumentsProvider> _providers; - public T? GetArguments<T>() where T : class, new() + public T GetArguments<T>() where T : class, new() { foreach (var provider in _providers) { - if (provider is IArgumentsProvider<T?>) + if (provider is IArgumentsProvider<T> typedProvider) { - return ((IArgumentsProvider<T?>)provider).GetResult(_args); + return typedProvider.GetResult(_args); } } - return default; + throw new InvalidOperationException($"Unable to find class that implements IArgumentsProvider<{typeof(T).Name}>"); } public ArgumentsParser(ILogService log, IPluginService plugins, string[] args) diff --git a/src/main.lib/Services/ArgumentsService.cs b/src/main.lib/Services/ArgumentsService.cs index 3bf802b..fe6dbbe 100644 --- a/src/main.lib/Services/ArgumentsService.cs +++ b/src/main.lib/Services/ArgumentsService.cs @@ -26,11 +26,11 @@ namespace PKISharp.WACS.Services } } - public T? GetArguments<T>() where T : class, new() => _parser.GetArguments<T>(); + public T GetArguments<T>() where T : class, new() => _parser.GetArguments<T>(); - public async Task<string> TryGetArgument(string providedValue, IInputService input, string what, bool secret = false) => await TryGetArgument(providedValue, input, new[] { what }, secret); + public async Task<string?> TryGetArgument(string? providedValue, IInputService input, string what, bool secret = false) => await TryGetArgument(providedValue, input, new[] { what }, secret); - public async Task<string> TryGetArgument(string providedValue, IInputService input, string[] what, bool secret = false) + public async Task<string?> TryGetArgument(string? providedValue, IInputService input, string[] what, bool secret = false) { if (!string.IsNullOrWhiteSpace(providedValue)) { @@ -53,7 +53,7 @@ namespace PKISharp.WACS.Services } } - public string TryGetRequiredArgument(string optionName, string providedValue) + public string TryGetRequiredArgument(string optionName, string? providedValue) { if (string.IsNullOrWhiteSpace(providedValue)) { diff --git a/src/main.lib/Services/ExceptionHandler.cs b/src/main.lib/Services/ExceptionHandler.cs index 2d8063e..6b41177 100644 --- a/src/main.lib/Services/ExceptionHandler.cs +++ b/src/main.lib/Services/ExceptionHandler.cs @@ -15,7 +15,7 @@ namespace PKISharp.WACS.Services /// Handle exceptions by logging them and setting negative exit code /// </summary> /// <param name="innerex"></param> - public string HandleException(Exception original = null, string message = null) + public string? HandleException(Exception? original = null, string? message = null) { var outMessage = message; var exceptionStack = new List<Exception>(); diff --git a/src/main.lib/Services/InputService.cs b/src/main.lib/Services/InputService.cs index 7bd62cb..0845e23 100644 --- a/src/main.lib/Services/InputService.cs +++ b/src/main.lib/Services/InputService.cs @@ -82,7 +82,7 @@ namespace PKISharp.WACS.Services return ""; } - public void Show(string label, string value, bool newLine = false, int level = 0) + public void Show(string? label, string? value, bool newLine = false, int level = 0) { if (newLine) { @@ -228,7 +228,7 @@ namespace PKISharp.WACS.Services // Replaces the characters of the typed in password with asterisks // More info: http://rajeshbailwal.blogspot.com/2012/03/password-in-c-console-application.html - public Task<string> ReadPassword(string what) + public async Task<string?> ReadPassword(string what) { Validate(what); CreateSpace(); @@ -278,11 +278,11 @@ namespace PKISharp.WACS.Services var ret = password.ToString(); if (string.IsNullOrEmpty(ret)) { - return Task.FromResult<string>(null); + return null; } else { - return Task.FromResult(ret); + return ret; } } @@ -290,7 +290,11 @@ namespace PKISharp.WACS.Services /// Print a (paged) list of targets for the user to choose from /// </summary> /// <param name="targets"></param> - public async Task<T> ChooseFromList<S, T>(string what, IEnumerable<S> options, Func<S, Choice<T>> creator, string nullLabel = null) + public async Task<T> ChooseFromList<S, T>( + string what, + IEnumerable<S> options, + Func<S, Choice<T>> creator, + string? nullLabel = null) { var baseChoices = options.Select(creator).ToList(); var allowNull = !string.IsNullOrEmpty(nullLabel); diff --git a/src/main.lib/Services/Interfaces/IArgumentsProvider.cs b/src/main.lib/Services/Interfaces/IArgumentsProvider.cs index a31b71c..58c6a16 100644 --- a/src/main.lib/Services/Interfaces/IArgumentsProvider.cs +++ b/src/main.lib/Services/Interfaces/IArgumentsProvider.cs @@ -20,7 +20,7 @@ namespace PKISharp.WACS.Services /// <summary> /// Precondition to use these parameters /// </summary> - string Condition { get; } + string? Condition { get; } /// <summary> /// Precondition to use these parameters diff --git a/src/main.lib/Services/Interfaces/IArgumentsService.cs b/src/main.lib/Services/Interfaces/IArgumentsService.cs index e613119..0f5621a 100644 --- a/src/main.lib/Services/Interfaces/IArgumentsService.cs +++ b/src/main.lib/Services/Interfaces/IArgumentsService.cs @@ -6,12 +6,12 @@ namespace PKISharp.WACS.Services public interface IArgumentsService { MainArguments MainArguments { get; } - T? GetArguments<T>() where T : class, new(); + T GetArguments<T>() where T : class, new(); bool Active(); bool HasFilter(); - Task<string> TryGetArgument(string providedValue, IInputService input, string what, bool secret = false); - Task<string> TryGetArgument(string providedValue, IInputService input, string[] what, bool secret = false); - string TryGetRequiredArgument(string optionName, string providedValue); + Task<string?> TryGetArgument(string? providedValue, IInputService input, string what, bool secret = false); + Task<string?> TryGetArgument(string? providedValue, IInputService input, string[] what, bool secret = false); + string TryGetRequiredArgument(string optionName, string? providedValue); void ShowHelp(); void ShowCommandLine(); } diff --git a/src/main.lib/Services/Interfaces/IAutofacBuilder.cs b/src/main.lib/Services/Interfaces/IAutofacBuilder.cs index c2a3893..2401cfe 100644 --- a/src/main.lib/Services/Interfaces/IAutofacBuilder.cs +++ b/src/main.lib/Services/Interfaces/IAutofacBuilder.cs @@ -50,6 +50,6 @@ namespace PKISharp.WACS.Services /// <param name="target"></param> /// <param name="identifier"></param> /// <returns></returns> - ILifetimeScope Validation(ILifetimeScope execution, ValidationPluginOptions options, TargetPart target, string identifier); + ILifetimeScope Validation(ILifetimeScope execution, ValidationPluginOptions? options, TargetPart target, string identifier); } } diff --git a/src/main.lib/Services/Interfaces/IInputService.cs b/src/main.lib/Services/Interfaces/IInputService.cs index a756845..d9dd8fd 100644 --- a/src/main.lib/Services/Interfaces/IInputService.cs +++ b/src/main.lib/Services/Interfaces/IInputService.cs @@ -6,10 +6,10 @@ namespace PKISharp.WACS.Services { public interface IInputService { - Task<TResult> ChooseFromList<TSource, TResult>(string what, IEnumerable<TSource> options, Func<TSource, Choice<TResult>> creator, string nullChoiceLabel = null); + Task<TResult> ChooseFromList<TSource, TResult>(string what, IEnumerable<TSource> options, Func<TSource, Choice<TResult>> creator, string? nullChoiceLabel = null); Task<TResult> ChooseFromList<TResult>(string what, List<Choice<TResult>> choices); Task<bool> PromptYesNo(string message, bool defaultOption); - Task<string> ReadPassword(string what); + Task<string?> ReadPassword(string what); Task<string> RequestString(string what); Task<string> RequestString(string[] what); void Show(string? label, string? value = null, bool first = false, int level = 0); diff --git a/src/main.lib/Services/Interfaces/ILogService.cs b/src/main.lib/Services/Interfaces/ILogService.cs index 2cfd996..62f5b39 100644 --- a/src/main.lib/Services/Interfaces/ILogService.cs +++ b/src/main.lib/Services/Interfaces/ILogService.cs @@ -17,13 +17,13 @@ namespace PKISharp.WACS.Services { bool Dirty { get; set; } - void Debug(string message, params object[] items); - void Error(Exception ex, string message, params object[] items); - void Error(string message, params object[] items); - void Information(string message, params object[] items); - void Information(LogType logType, string message, params object[] items); + void Debug(string message, params object?[] items); + void Error(Exception ex, string message, params object?[] items); + void Error(string message, params object?[] items); + void Information(string message, params object?[] items); + void Information(LogType logType, string message, params object?[] items); void SetVerbose(); - void Verbose(string message, params object[] items); - void Warning(string message, params object[] items); + void Verbose(string message, params object?[] items); + void Warning(string message, params object?[] items); } }
\ No newline at end of file diff --git a/src/main.lib/Services/Interfaces/IRenewalService.cs b/src/main.lib/Services/Interfaces/IRenewalService.cs index d8368fc..9a52c45 100644 --- a/src/main.lib/Services/Interfaces/IRenewalService.cs +++ b/src/main.lib/Services/Interfaces/IRenewalService.cs @@ -5,7 +5,7 @@ namespace PKISharp.WACS.Services { internal interface IRenewalStore { - IEnumerable<Renewal> FindByArguments(string id, string friendlyName); + IEnumerable<Renewal> FindByArguments(string? id, string? friendlyName); void Save(Renewal renewal, RenewResult result); void Cancel(Renewal renewal); void Clear(); diff --git a/src/main.lib/Services/Legacy/BaseLegacyRenewalService.cs b/src/main.lib/Services/Legacy/BaseLegacyRenewalService.cs index a09830e..3c0220f 100644 --- a/src/main.lib/Services/Legacy/BaseLegacyRenewalService.cs +++ b/src/main.lib/Services/Legacy/BaseLegacyRenewalService.cs @@ -10,8 +10,8 @@ namespace PKISharp.WACS.Services.Legacy internal abstract class BaseLegacyRenewalService : ILegacyRenewalService { internal ILogService _log; - internal List<LegacyScheduledRenewal> _renewalsCache; - internal string _configPath = null; + internal List<LegacyScheduledRenewal>? _renewalsCache; + internal string? _configPath = null; public BaseLegacyRenewalService( LegacySettingsService settings, @@ -28,7 +28,7 @@ namespace PKISharp.WACS.Services.Legacy /// </summary> /// <param name="BaseUri"></param> /// <returns></returns> - internal abstract string[] RenewalsRaw { get; } + internal abstract string[]? RenewalsRaw { get; } /// <summary> /// Parse renewals from store @@ -41,7 +41,10 @@ namespace PKISharp.WACS.Services.Legacy var list = new List<LegacyScheduledRenewal>(); if (read != null) { - list.AddRange(read.Select(x => Load(x)).Where(x => x != null)); + list.AddRange( + read.Select(x => Load(x)). + Where(x => x != null). + OfType<LegacyScheduledRenewal>()); } _renewalsCache = list; } @@ -54,7 +57,7 @@ namespace PKISharp.WACS.Services.Legacy /// <param name="renewal"></param> /// <param name="path"></param> /// <returns></returns> - private LegacyScheduledRenewal Load(string renewal) + private LegacyScheduledRenewal? Load(string renewal) { LegacyScheduledRenewal result; try diff --git a/src/main.lib/Services/Legacy/CompatibleAzureDnsOptions.cs b/src/main.lib/Services/Legacy/CompatibleAzureDnsOptions.cs index a45a5ee..4c2b05e 100644 --- a/src/main.lib/Services/Legacy/CompatibleAzureDnsOptions.cs +++ b/src/main.lib/Services/Legacy/CompatibleAzureDnsOptions.cs @@ -13,13 +13,13 @@ namespace PKISharp.WACS.Services.Legacy [Plugin("aa57b028-45fb-4aca-9cac-a63d94c76b4a")] internal class CompatibleAzureOptions : ValidationPluginOptions, IIgnore { - public string ClientId { get; set; } - public string ResourceGroupName { get; set; } + public string? ClientId { get; set; } + public string? ResourceGroupName { get; set; } [JsonProperty(propertyName: "SecretSafe")] - public ProtectedString Secret { get; set; } + public ProtectedString? Secret { get; set; } - public string SubscriptionId { get; set; } - public string TenantId { get; set; } + public string? SubscriptionId { get; set; } + public string? TenantId { get; set; } } }
\ No newline at end of file diff --git a/src/main.lib/Services/Legacy/FileLegacyRenewalService.cs b/src/main.lib/Services/Legacy/FileLegacyRenewalService.cs index 40152a3..8ae5808 100644 --- a/src/main.lib/Services/Legacy/FileLegacyRenewalService.cs +++ b/src/main.lib/Services/Legacy/FileLegacyRenewalService.cs @@ -14,7 +14,7 @@ namespace PKISharp.WACS.Services.Legacy private string FileName => Path.Combine(_configPath, _renewalsKey); - internal override string[] RenewalsRaw + internal override string[]? RenewalsRaw { get { diff --git a/src/main.lib/Services/Legacy/Importer.cs b/src/main.lib/Services/Legacy/Importer.cs index 32b5ac8..10c2268 100644 --- a/src/main.lib/Services/Legacy/Importer.cs +++ b/src/main.lib/Services/Legacy/Importer.cs @@ -173,7 +173,7 @@ namespace PKISharp.WACS.Services.Legacy { CopyWebConfig = legacy.Binding.IIS == true, Path = legacy.Binding.WebRootPath, - Credential = new NetworkCredentialOptions(legacy.Binding.HttpFtpOptions.UserName, legacy.Binding.HttpFtpOptions.Password) + Credential = new NetworkCredentialOptions(legacy.Binding.HttpFtpOptions?.UserName, legacy.Binding.HttpFtpOptions.Password) }; break; case "http-01.sftp": @@ -181,16 +181,22 @@ namespace PKISharp.WACS.Services.Legacy { CopyWebConfig = legacy.Binding.IIS == true, Path = legacy.Binding.WebRootPath, - Credential = new NetworkCredentialOptions(legacy.Binding.HttpFtpOptions.UserName, legacy.Binding.HttpFtpOptions.Password) + Credential = new NetworkCredentialOptions(legacy.Binding.HttpFtpOptions?.UserName, legacy.Binding.HttpFtpOptions.Password) }; break; case "http-01.webdav": - ret.ValidationPluginOptions = new http.WebDavOptions() + var options = new http.WebDavOptions() { CopyWebConfig = legacy.Binding.IIS == true, - Path = legacy.Binding.WebRootPath, - Credential = new NetworkCredentialOptions(legacy.Binding.HttpWebDavOptions.UserName, legacy.Binding.HttpWebDavOptions.Password) + Path = legacy.Binding.WebRootPath }; + if (legacy.Binding.HttpWebDavOptions != null) + { + options.Credential = new NetworkCredentialOptions( + legacy.Binding.HttpWebDavOptions.UserName, + legacy.Binding.HttpWebDavOptions.Password); + } + ret.ValidationPluginOptions = options; break; case "tls-sni-01.iis": _log.Warning("TLS-SNI-01 validation was removed from ACMEv2, changing to SelfHosting. Note that this requires port 80 to be public rather than port 443."); @@ -276,7 +282,10 @@ namespace PKISharp.WACS.Services.Legacy case "iisftp": ret.InstallationPluginOptions.Add(new install.IISFtpOptions() { - SiteId = legacy.Binding.FtpSiteId.Value + SiteId = legacy.Binding.FtpSiteId ?? + legacy.Binding.InstallationSiteId ?? + legacy.Binding.SiteId ?? + 0 }); break; case "manual": diff --git a/src/main.lib/Services/Legacy/LegacyAzureDnsOptions.cs b/src/main.lib/Services/Legacy/LegacyAzureDnsOptions.cs index de299a0..75a1794 100644 --- a/src/main.lib/Services/Legacy/LegacyAzureDnsOptions.cs +++ b/src/main.lib/Services/Legacy/LegacyAzureDnsOptions.cs @@ -2,10 +2,10 @@ { internal class LegacyAzureDnsOptions { - public string ClientId { get; set; } - public string ResourceGroupName { get; set; } - public string Secret { get; set; } - public string SubscriptionId { get; set; } - public string TenantId { get; set; } + public string? ClientId { get; set; } + public string? ResourceGroupName { get; set; } + public string? Secret { get; set; } + public string? SubscriptionId { get; set; } + public string? TenantId { get; set; } } } diff --git a/src/main.lib/Services/Legacy/LegacyCredentials.cs b/src/main.lib/Services/Legacy/LegacyCredentials.cs index 535cf4e..2203049 100644 --- a/src/main.lib/Services/Legacy/LegacyCredentials.cs +++ b/src/main.lib/Services/Legacy/LegacyCredentials.cs @@ -2,7 +2,7 @@ { internal class LegacyCredentials { - public string UserName { get; set; } - public string Password { get; set; } + public string? UserName { get; set; } + public string? Password { get; set; } } } diff --git a/src/main.lib/Services/Legacy/LegacyScheduledRenewal.cs b/src/main.lib/Services/Legacy/LegacyScheduledRenewal.cs index 2c22b99..aefa5d5 100644 --- a/src/main.lib/Services/Legacy/LegacyScheduledRenewal.cs +++ b/src/main.lib/Services/Legacy/LegacyScheduledRenewal.cs @@ -42,17 +42,17 @@ namespace PKISharp.WACS.Services.Legacy /// <summary> /// Name of the plugins to use for validation, in order of execution /// </summary> - public List<string> InstallationPluginNames { get; set; } + public List<string>? InstallationPluginNames { get; set; } /// <summary> /// Script to run on succesful renewal /// </summary> - public string Script { get; set; } + public string? Script { get; set; } /// <summary> /// Parameters for script /// </summary>e - public string ScriptParameters { get; set; } + public string? ScriptParameters { get; set; } /// <summary> /// Warmup target website (applies to http-01 validation) diff --git a/src/main.lib/Services/Legacy/LegacySettingsService.cs b/src/main.lib/Services/Legacy/LegacySettingsService.cs index 4c55380..71be4c3 100644 --- a/src/main.lib/Services/Legacy/LegacySettingsService.cs +++ b/src/main.lib/Services/Legacy/LegacySettingsService.cs @@ -13,17 +13,17 @@ namespace PKISharp.WACS.Host.Services.Legacy { private readonly ILogService _log; - public UiSettings UI { get; private set; } - public AcmeSettings Acme { get; private set; } - public ProxySettings Proxy { get; private set; } - public CacheSettings Cache { get; private set; } - public ScheduledTaskSettings ScheduledTask { get; private set; } - public NotificationSettings Notification { get; private set; } - public SecuritySettings Security { get; private set; } - public ScriptSettings Script { get; private set; } - public ClientSettings Client { get; private set; } - public ValidationSettings Validation { get; private set; } - public StoreSettings Store { get; private set; } + public ClientSettings Client { get; private set; } = new ClientSettings(); + public UiSettings UI { get; private set; } = new UiSettings(); + public AcmeSettings Acme { get; private set; } = new AcmeSettings(); + public ProxySettings Proxy { get; private set; } = new ProxySettings(); + public CacheSettings Cache { get; private set; } = new CacheSettings(); + public ScheduledTaskSettings ScheduledTask { get; private set; } = new ScheduledTaskSettings(); + public NotificationSettings Notification { get; private set; } = new NotificationSettings(); + public SecuritySettings Security { get; private set; } = new SecuritySettings(); + public ScriptSettings Script { get; private set; } = new ScriptSettings(); + public ValidationSettings Validation { get; private set; } = new ValidationSettings(); + public StoreSettings Store { get; private set; } = new StoreSettings(); public string ExePath { get; private set; } public List<string> ClientNames { get; private set; } @@ -83,7 +83,7 @@ namespace PKISharp.WACS.Host.Services.Legacy CreateConfigPath(main, userRoot); } - private void CreateConfigPath(MainArguments options, string userRoot) + private void CreateConfigPath(MainArguments options, string? userRoot) { var configRoot = ""; if (!string.IsNullOrEmpty(userRoot)) diff --git a/src/main.lib/Services/Legacy/RegistryLegacyRenewalService.cs b/src/main.lib/Services/Legacy/RegistryLegacyRenewalService.cs index f34dd91..2f36fa3 100644 --- a/src/main.lib/Services/Legacy/RegistryLegacyRenewalService.cs +++ b/src/main.lib/Services/Legacy/RegistryLegacyRenewalService.cs @@ -1,7 +1,7 @@ using Microsoft.Win32; using PKISharp.WACS.Configuration; using PKISharp.WACS.Host.Services.Legacy; -using System.Linq; +using System; namespace PKISharp.WACS.Services.Legacy { @@ -18,6 +18,10 @@ namespace PKISharp.WACS.Services.Legacy LegacySettingsService settings) : base(settings, log) { + if (main.BaseUri == null) + { + throw new InvalidOperationException("Missing main.BaseUri"); + } _baseUri = main.BaseUri; _hive = $"HKEY_CURRENT_USER{Key}"; if (RenewalsRaw == null) @@ -29,6 +33,6 @@ namespace PKISharp.WACS.Services.Legacy private string Key => $"\\Software\\{_clientName}\\{_baseUri}"; - internal override string[] RenewalsRaw => Registry.GetValue(_hive, _renewalsKey, null) as string[]; + internal override string[] RenewalsRaw => Registry.GetValue(_hive, _renewalsKey, null) as string[] ?? new string[] { }; } } diff --git a/src/main.lib/Services/LogService.cs b/src/main.lib/Services/LogService.cs index c6eb929..479a20f 100644 --- a/src/main.lib/Services/LogService.cs +++ b/src/main.lib/Services/LogService.cs @@ -11,9 +11,9 @@ namespace PKISharp.WACS.Services { public class LogService : ILogService { - private readonly Logger _screenLogger; - private readonly Logger _eventLogger; - private Logger _diskLogger; + private readonly Logger? _screenLogger; + private readonly Logger? _eventLogger; + private Logger? _diskLogger; private readonly LoggingLevelSwitch _levelSwitch; public bool Dirty { get; set; } private IConfigurationRoot ConfigurationRoot { get; } @@ -89,37 +89,37 @@ namespace PKISharp.WACS.Services Verbose("Verbose mode logging enabled"); } - public void Verbose(string message, params object[] items) => Verbose(LogType.Screen, message, items); + public void Verbose(string message, params object?[] items) => Verbose(LogType.Screen, message, items); - public void Debug(string message, params object[] items) => Debug(LogType.Screen, message, items); + public void Debug(string message, params object?[] items) => Debug(LogType.Screen, message, items); - public void Warning(string message, params object[] items) => Warning(LogType.Screen | LogType.Event, message, items); + public void Warning(string message, params object?[] items) => Warning(LogType.Screen | LogType.Event, message, items); - public void Error(string message, params object[] items) => Error(LogType.Screen | LogType.Event, message, items); + public void Error(string message, params object?[] items) => Error(LogType.Screen | LogType.Event, message, items); - public void Error(Exception ex, string message, params object[] items) => Error(LogType.Screen | LogType.Event, ex, message, items); + public void Error(Exception ex, string message, params object?[] items) => Error(LogType.Screen | LogType.Event, ex, message, items); - public void Information(string message, params object[] items) => Information(LogType.Screen, message, items); + public void Information(string message, params object?[] items) => Information(LogType.Screen, message, items); - public void Information(LogType logType, string message, params object[] items) => _Information(logType, message, items); + public void Information(LogType logType, string message, params object?[] items) => _Information(logType, message, items); - private void Verbose(LogType type, string message, params object[] items) => Write(type, LogEventLevel.Verbose, message, items); + private void Verbose(LogType type, string message, params object?[] items) => Write(type, LogEventLevel.Verbose, message, items); - private void Debug(LogType type, string message, params object[] items) => Write(type, LogEventLevel.Debug, message, items); + private void Debug(LogType type, string message, params object?[] items) => Write(type, LogEventLevel.Debug, message, items); - private void _Information(LogType type, string message, params object[] items) => Write(type, LogEventLevel.Information, message, items); + private void _Information(LogType type, string message, params object?[] items) => Write(type, LogEventLevel.Information, message, items); - private void Warning(LogType type, string message, params object[] items) => Write(type, LogEventLevel.Warning, message, items); + private void Warning(LogType type, string message, params object?[] items) => Write(type, LogEventLevel.Warning, message, items); - private void Error(LogType type, string message, params object[] items) => Write(type, LogEventLevel.Error, message, items); + private void Error(LogType type, string message, params object?[] items) => Write(type, LogEventLevel.Error, message, items); - private void Error(LogType type, Exception ex, string message, params object[] items) => Write(type, LogEventLevel.Error, ex, message, items); + private void Error(LogType type, Exception ex, string message, params object?[] items) => Write(type, LogEventLevel.Error, ex, message, items); - private void Write(LogType type, LogEventLevel level, string message, params object[] items) => Write(type, level, null, message, items); + private void Write(LogType type, LogEventLevel level, string message, params object?[] items) => Write(type, level, null, message, items); - private void Write(LogType type, LogEventLevel level, Exception ex, string message, params object[] items) + private void Write(LogType type, LogEventLevel level, Exception? ex, string message, params object?[] items) { - if (type.HasFlag(LogType.Screen)) + if (_screenLogger != null && type.HasFlag(LogType.Screen)) { _screenLogger.Write(level, ex, message, items); } diff --git a/src/main.lib/Services/NotificationService.cs b/src/main.lib/Services/NotificationService.cs index 5ba2f54..f9e4ee6 100644 --- a/src/main.lib/Services/NotificationService.cs +++ b/src/main.lib/Services/NotificationService.cs @@ -48,14 +48,14 @@ namespace PKISharp.WACS.Services /// </summary> /// <param name="runLevel"></param> /// <param name="renewal"></param> - internal void NotifyFailure(RunLevel runLevel, Renewal renewal, string errorMessage) + internal void NotifyFailure(RunLevel runLevel, Renewal renewal, string? errorMessage) { // Do not send emails when running interactively _log.Error("Renewal for {friendlyName} failed, will retry on next run", renewal.LastFriendlyName); if (runLevel.HasFlag(RunLevel.Unattended)) { _email.Send("Error processing certificate renewal", - $"<p>Renewal for <b>{renewal.LastFriendlyName}</b> failed with error <b>{errorMessage}</b>, will retry on next run.</p> {NotificationInformation(renewal)}", + $"<p>Renewal for <b>{renewal.LastFriendlyName}</b> failed with error <b>{errorMessage ?? "(null)"}</b>, will retry on next run.</p> {NotificationInformation(renewal)}", MailPriority.High); } } @@ -67,11 +67,26 @@ namespace PKISharp.WACS.Services var extraMessage = ""; extraMessage += $"<p>Hosts: {NotificationHosts(renewal)}</p>"; extraMessage += "<p><table><tr><td>Plugins</td><td></td></tr>"; - extraMessage += $"<tr><td>Target: </td><td> {renewal.TargetPluginOptions.Name}</td></tr>"; - extraMessage += $"<tr><td>Validation: </td><td> {renewal.ValidationPluginOptions.Name}</td></tr>"; - extraMessage += $"<tr><td>CSR: </td><td> {renewal.CsrPluginOptions.Name}</td></tr>"; - extraMessage += $"<tr><td>Store: </td><td> {string.Join(", ", renewal.StorePluginOptions.Select(x => x.Name))}</td></tr>"; - extraMessage += $"<tr><td>Installation: </td><td> {string.Join(", ", renewal.InstallationPluginOptions.Select(x => x.Name))}</td></tr>"; + if (renewal.TargetPluginOptions != null) + { + extraMessage += $"<tr><td>Target: </td><td> {renewal.TargetPluginOptions.Name}</td></tr>"; + } + if (renewal.ValidationPluginOptions != null) + { + extraMessage += $"<tr><td>Validation: </td><td> {renewal.ValidationPluginOptions.Name}</td></tr>"; + } + if (renewal.CsrPluginOptions != null) + { + extraMessage += $"<tr><td>CSR: </td><td> {renewal.CsrPluginOptions.Name}</td></tr>"; + } + if (renewal.StorePluginOptions != null) + { + extraMessage += $"<tr><td>Store: </td><td> {string.Join(", ", renewal.StorePluginOptions.Select(x => x.Name))}</td></tr>"; + } + if (renewal.InstallationPluginOptions != null) + { + extraMessage += $"<tr><td>Installation: </td><td> {string.Join(", ", renewal.InstallationPluginOptions.Select(x => x.Name))}</td></tr>"; + } extraMessage += "</table></p>"; return extraMessage; } diff --git a/src/main.lib/Services/PemService.cs b/src/main.lib/Services/PemService.cs index ca7a6e2..9d5a00c 100644 --- a/src/main.lib/Services/PemService.cs +++ b/src/main.lib/Services/PemService.cs @@ -30,7 +30,7 @@ namespace PKISharp.WACS.Services /// <typeparam name="T"></typeparam> /// <param name="pem"></param> /// <returns></returns> - public T ParsePem<T>(string pem) where T: class + public T? ParsePem<T>(string pem) where T: class { using var tr = new StringReader(pem); var pr = new bc.OpenSsl.PemReader(tr); diff --git a/src/main.lib/Services/ProxyService.cs b/src/main.lib/Services/ProxyService.cs index 10ba47d..22e0353 100644 --- a/src/main.lib/Services/ProxyService.cs +++ b/src/main.lib/Services/ProxyService.cs @@ -46,7 +46,7 @@ namespace PKISharp.WACS.Services /// Get proxy server to use for web requests /// </summary> /// <returns></returns> - public IWebProxy GetWebProxy() + public IWebProxy? GetWebProxy() { if (_proxy == null) { diff --git a/src/main.lib/Services/RenewalService.cs b/src/main.lib/Services/RenewalService.cs index 9268ff6..606fea7 100644 --- a/src/main.lib/Services/RenewalService.cs +++ b/src/main.lib/Services/RenewalService.cs @@ -37,7 +37,7 @@ namespace PKISharp.WACS.Services _log.Debug("Renewal period: {RenewalDays} days", _settings.ScheduledTask.RenewalDays); } - public IEnumerable<Renewal> FindByArguments(string id, string friendlyName) + public IEnumerable<Renewal> FindByArguments(string? id, string? friendlyName) { // AND filtering by input parameters var ret = Renewals; diff --git a/src/main.lib/Services/Serialization/PluginOptionsConverter.cs b/src/main.lib/Services/Serialization/PluginOptionsConverter.cs index ced8e9d..2160cc1 100644 --- a/src/main.lib/Services/Serialization/PluginOptionsConverter.cs +++ b/src/main.lib/Services/Serialization/PluginOptionsConverter.cs @@ -16,7 +16,7 @@ namespace PKISharp.WACS.Services.Serialization /// <summary> /// Contains the unique GUID of the plugin /// </summary> - public string Plugin { get; set; } + public string? Plugin { get; set; } /// <summary> /// Describe the plugin to the user @@ -25,19 +25,19 @@ namespace PKISharp.WACS.Services.Serialization public virtual void Show(IInputService input) { } [JsonIgnore] - public virtual Type Instance { get; } + public virtual Type? Instance { get; } /// <summary> /// Short name for the plugin to be shown in the menu and e-mails /// </summary> [JsonIgnore] - public virtual string Name => null; + public virtual string? Name => null; /// <summary> /// One-line description for the plugin to be shown in the menu /// </summary> [JsonIgnore] - public virtual string Description => null; + public virtual string? Description => null; } /// <summary> @@ -88,7 +88,7 @@ namespace PKISharp.WACS.Services.Serialization /// <param name="existingValue"></param> /// <param name="serializer"></param> /// <returns></returns> - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var data = JObject.Load(reader); var key = data.Property("Plugin").Value.Value<string>(); diff --git a/src/main.lib/Services/Serialization/ProtectedString.cs b/src/main.lib/Services/Serialization/ProtectedString.cs index ee8ae11..3523afb 100644 --- a/src/main.lib/Services/Serialization/ProtectedString.cs +++ b/src/main.lib/Services/Serialization/ProtectedString.cs @@ -27,7 +27,7 @@ namespace PKISharp.WACS.Services.Serialization /// <summary> /// Logging service, used only by the JsonConverter /// </summary> - private readonly ILogService _log; + private readonly ILogService? _log; /// <summary> /// Indicates if there was an error decoding or decrypting the string @@ -37,18 +37,18 @@ namespace PKISharp.WACS.Services.Serialization /// <summary> /// Clear value, should be used for operations /// </summary> - public string Value { get; private set; } + public string? Value { get; private set; } /// <summary> /// Value to save to disk, based on the setting /// </summary> - public string DiskValue(bool encrypt) => encrypt ? ProtectedValue : EncodedValue; + public string? DiskValue(bool encrypt) => encrypt ? ProtectedValue : EncodedValue; /// <summary> /// Constructor for user input, always starting with clear text /// </summary> /// <param name="clearValue"></param> - public ProtectedString(string clearValue) => Value = clearValue; + public ProtectedString(string? clearValue) => Value = clearValue; /// <summary> /// Constructor for deserialisation, may be any format @@ -100,7 +100,7 @@ namespace PKISharp.WACS.Services.Serialization /// <summary> /// Encrypted value should be used when the "EncryptConfig" setting is true /// </summary> - internal string ProtectedValue + internal string? ProtectedValue { get { @@ -118,7 +118,7 @@ namespace PKISharp.WACS.Services.Serialization /// <summary> /// Encoded value should be used when the "EncryptConfig" setting is false /// </summary> - internal string EncodedValue + internal string? EncodedValue { get { @@ -151,7 +151,7 @@ namespace PKISharp.WACS.Services.Serialization /// <param name="optionalEntropy"></param> /// <param name="scope"></param> /// <returns></returns> - private string Protect(string clearText, string optionalEntropy = null, DataProtectionScope scope = DataProtectionScope.LocalMachine) + private string Protect(string clearText, string? optionalEntropy = null, DataProtectionScope scope = DataProtectionScope.LocalMachine) { var clearBytes = Encoding.UTF8.GetBytes(clearText); var entropyBytes = string.IsNullOrEmpty(optionalEntropy) @@ -168,18 +168,18 @@ namespace PKISharp.WACS.Services.Serialization /// <param name="optionalEntropy"></param> /// <param name="scope"></param> /// <returns></returns> - private string Unprotect(string encryptedText, string optionalEntropy = null, DataProtectionScope scope = DataProtectionScope.LocalMachine) + private string? Unprotect(string encryptedText, string? optionalEntropy = null, DataProtectionScope scope = DataProtectionScope.LocalMachine) { if (encryptedText == null) { return null; } - byte[] clearBytes = null; + var encryptedBytes = Convert.FromBase64String(encryptedText); var entropyBytes = string.IsNullOrEmpty(optionalEntropy) ? null : Encoding.UTF8.GetBytes(optionalEntropy); - clearBytes = ProtectedData.Unprotect(encryptedBytes, entropyBytes, scope); + var clearBytes = ProtectedData.Unprotect(encryptedBytes, entropyBytes, scope); return Encoding.UTF8.GetString(clearBytes); } } diff --git a/src/main.lib/Services/SettingsService.cs b/src/main.lib/Services/SettingsService.cs index 4267382..345a729 100644 --- a/src/main.lib/Services/SettingsService.cs +++ b/src/main.lib/Services/SettingsService.cs @@ -64,19 +64,27 @@ namespace PKISharp.WACS.Services { get { - if (_arguments.MainArguments == null) + var ret = Acme.DefaultBaseUri; + if (_arguments.MainArguments != null) { - if (Acme.DefaultBaseUri != null) + if (!string.IsNullOrEmpty(_arguments.MainArguments.BaseUri)) { - return Acme.DefaultBaseUri; + ret = new Uri(_arguments.MainArguments.BaseUri); } - + else if (_arguments.MainArguments.Test) + { + ret = Acme.DefaultBaseUriTest; + } + else + { + ret = Acme.DefaultBaseUri; + } + } + if (ret == null) + { + throw new Exception("Unable to determine BaseUri"); } - return !string.IsNullOrEmpty(_arguments.MainArguments.BaseUri) ? - new Uri(_arguments.MainArguments.BaseUri) : - _arguments.MainArguments.Test ? - Acme.DefaultBaseUriTest : - Acme.DefaultBaseUri; + return ret; } } diff --git a/src/main.lib/Wacs.cs b/src/main.lib/Wacs.cs index 8f33152..2db0c13 100644 --- a/src/main.lib/Wacs.cs +++ b/src/main.lib/Wacs.cs @@ -360,6 +360,10 @@ namespace PKISharp.WACS.Host { var acmeClient = _container.Resolve<AcmeClient>(); var acmeAccount = await acmeClient.GetAccount(); + if (acmeAccount == null) + { + throw new InvalidOperationException(); + } _input.Show("Account ID", acmeAccount.Payload.Id, true); _input.Show("Created", acmeAccount.Payload.CreatedAt); _input.Show("Initial IP", acmeAccount.Payload.InitialIp); |