/// <summary> /// Check if there are multiple renewals installing to the same site /// or requesting certificates for the same domains /// </summary> /// <param name="selectedRenewals"></param> /// <returns></returns> private async Task <IEnumerable <Renewal> > Analyze(IEnumerable <Renewal> selectedRenewals) { var foundHosts = new Dictionary <Identifier, List <Renewal> >(); var foundSites = new Dictionary <long, List <Renewal> >(); foreach (var renewal in selectedRenewals) { using var targetScope = _scopeBuilder.Target(_container, renewal, RunLevel.Unattended); var target = targetScope.Resolve <Target>(); foreach (var targetPart in target.Parts) { if (targetPart.SiteId != null) { var siteId = targetPart.SiteId.Value; if (!foundSites.ContainsKey(siteId)) { foundSites.Add(siteId, new List <Renewal>()); } foundSites[siteId].Add(renewal); } foreach (var host in targetPart.GetIdentifiers(true)) { if (!foundHosts.ContainsKey(host)) { foundHosts.Add(host, new List <Renewal>()); } foundHosts[host].Add(renewal); } } } // List results var options = new List <Choice <List <Renewal> > >(); foreach (var site in foundSites) { if (site.Value.Count > 1) { options.Add( Choice.Create( site.Value, $"Select {site.Value.Count} renewals covering IIS site {site.Key}")); } } foreach (var host in foundHosts) { if (host.Value.Count > 1) { options.Add( Choice.Create( host.Value, $"Select {host.Value.Count} renewals covering host {host.Key}")); } } _input.CreateSpace(); if (options.Count == 0) { _input.Show(null, "Analysis didn't find any overlap between renewals."); return(selectedRenewals); } else { options.Add( Choice.Create( selectedRenewals.ToList(), $"Back")); _input.Show(null, "Analysis found some overlap between renewals. You can select the overlapping renewals from the menu."); return(await _input.ChooseFromMenu("Please choose from the menu", options)); } }
/// <summary> /// Setup a new scheduled renewal /// </summary> /// <param name="runLevel"></param> internal async Task SetupRenewal(RunLevel runLevel, Renewal?tempRenewal = null) { if (_args.Test) { runLevel |= RunLevel.Test; } if (_args.Force) { runLevel |= RunLevel.IgnoreCache; } _log.Information(LogType.All, "Running in mode: {runLevel}", runLevel); if (tempRenewal == null) { tempRenewal = Renewal.Create(_args.Id, _settings.ScheduledTask.RenewalDays, _passwordGenerator); } using var configScope = _scopeBuilder.Configuration(_container, tempRenewal, runLevel); // Choose target plugin var targetPluginOptionsFactory = configScope.Resolve <ITargetPluginOptionsFactory>(); if (targetPluginOptionsFactory is INull) { _exceptionHandler.HandleException(message: $"No source plugin could be selected"); return; } var(targetPluginDisabled, targetPluginDisabledReason) = targetPluginOptionsFactory.Disabled; if (targetPluginDisabled) { _exceptionHandler.HandleException(message: $"Source plugin {targetPluginOptionsFactory.Name} is not available. {targetPluginDisabledReason}"); return; } var targetPluginOptions = runLevel.HasFlag(RunLevel.Unattended) ? await targetPluginOptionsFactory.Default() : await targetPluginOptionsFactory.Aquire(_input, runLevel); if (targetPluginOptions == null) { _exceptionHandler.HandleException(message: $"Source plugin {targetPluginOptionsFactory.Name} aborted or failed"); return; } tempRenewal.TargetPluginOptions = targetPluginOptions; // Generate Target and validation plugin choice using var targetScope = _scopeBuilder.Target(_container, tempRenewal, runLevel); var initialTarget = targetScope.Resolve <Target>(); if (initialTarget is INull) { _exceptionHandler.HandleException(message: $"Source plugin {targetPluginOptionsFactory.Name} was unable to generate a target"); return; } if (!initialTarget.IsValid(_log)) { _exceptionHandler.HandleException(message: $"Source plugin {targetPluginOptionsFactory.Name} generated an invalid target"); return; } _log.Information("Source generated using plugin {name}: {target}", targetPluginOptions.Name, initialTarget); // Choose FriendlyName if (!string.IsNullOrEmpty(_args.FriendlyName)) { tempRenewal.FriendlyName = _args.FriendlyName; } else if (runLevel.HasFlag(RunLevel.Advanced | RunLevel.Interactive)) { var alt = await _input.RequestString($"Suggested friendly name '{initialTarget.FriendlyName}', press <Enter> to accept or type an alternative"); if (!string.IsNullOrEmpty(alt)) { tempRenewal.FriendlyName = alt; } } tempRenewal.LastFriendlyName = tempRenewal.FriendlyName ?? initialTarget.FriendlyName; // Choose validation plugin var validationPluginOptionsFactory = targetScope.Resolve <IValidationPluginOptionsFactory>(); if (validationPluginOptionsFactory is INull) { _exceptionHandler.HandleException(message: $"No validation plugin could be selected"); return; } // Configure validation try { var validationOptions = runLevel.HasFlag(RunLevel.Unattended) ? await validationPluginOptionsFactory.Default(initialTarget) : await validationPluginOptionsFactory.Aquire(initialTarget, _input, runLevel); if (validationOptions == null) { _exceptionHandler.HandleException(message: $"Validation plugin {validationPluginOptionsFactory.Name} was unable to generate options"); return; } tempRenewal.ValidationPluginOptions = validationOptions; } catch (Exception ex) { _exceptionHandler.HandleException(ex, $"Validation plugin {validationPluginOptionsFactory.Name} aborted or failed"); return; } // Choose order plugin var orderPluginOptionsFactory = targetScope.Resolve <IOrderPluginOptionsFactory>(); if (orderPluginOptionsFactory is INull) { _exceptionHandler.HandleException(message: $"No order plugin could be selected"); return; } // Configure order try { var orderOptions = runLevel.HasFlag(RunLevel.Unattended) ? await orderPluginOptionsFactory.Default() : await orderPluginOptionsFactory.Aquire(_input, runLevel); if (orderOptions == null) { _exceptionHandler.HandleException(message: $"Order plugin {orderPluginOptionsFactory.Name} was unable to generate options"); return; } tempRenewal.OrderPluginOptions = orderOptions; } catch (Exception ex) { _exceptionHandler.HandleException(ex, $"Order plugin {orderPluginOptionsFactory.Name} aborted or failed"); return; } // Choose CSR plugin if (initialTarget.CsrBytes == null) { var csrPluginOptionsFactory = configScope.Resolve <ICsrPluginOptionsFactory>(); if (csrPluginOptionsFactory is INull) { _exceptionHandler.HandleException(message: $"No CSR plugin could be selected"); return; } // Configure CSR try { var csrOptions = runLevel.HasFlag(RunLevel.Unattended) ? await csrPluginOptionsFactory.Default() : await csrPluginOptionsFactory.Aquire(_input, runLevel); if (csrOptions == null) { _exceptionHandler.HandleException(message: $"CSR plugin {csrPluginOptionsFactory.Name} was unable to generate options"); return; } tempRenewal.CsrPluginOptions = csrOptions; } catch (Exception ex) { _exceptionHandler.HandleException(ex, $"CSR plugin {csrPluginOptionsFactory.Name} aborted or failed"); return; } } // Choose and configure store plugins var resolver = configScope.Resolve <IResolver>(); var storePluginOptionsFactories = new List <IStorePluginOptionsFactory>(); try { while (true) { var storePluginOptionsFactory = await resolver.GetStorePlugin(configScope, storePluginOptionsFactories); if (storePluginOptionsFactory == null) { _exceptionHandler.HandleException(message: $"Store could not be selected"); return; } StorePluginOptions?storeOptions; try { storeOptions = runLevel.HasFlag(RunLevel.Unattended) ? await storePluginOptionsFactory.Default() : await storePluginOptionsFactory.Aquire(_input, runLevel); } catch (Exception ex) { _exceptionHandler.HandleException(ex, $"Store plugin {storePluginOptionsFactory.Name} aborted or failed"); return; } if (storeOptions == null) { _exceptionHandler.HandleException(message: $"Store plugin {storePluginOptionsFactory.Name} was unable to generate options"); return; } var isNull = storePluginOptionsFactory is NullStoreOptionsFactory; if (!isNull || storePluginOptionsFactories.Count == 0) { tempRenewal.StorePluginOptions.Add(storeOptions); storePluginOptionsFactories.Add(storePluginOptionsFactory); } if (isNull) { break; } } } catch (Exception ex) { _exceptionHandler.HandleException(ex, "Invalid selection of store plugins"); return; } // Choose and configure installation plugins var installationPluginFactories = new List <IInstallationPluginOptionsFactory>(); try { while (true) { var installationPluginOptionsFactory = await resolver.GetInstallationPlugin(configScope, tempRenewal.StorePluginOptions.Select(x => x.Instance), installationPluginFactories); if (installationPluginOptionsFactory == null) { _exceptionHandler.HandleException(message: $"Installation plugin could not be selected"); return; } InstallationPluginOptions installOptions; try { installOptions = runLevel.HasFlag(RunLevel.Unattended) ? await installationPluginOptionsFactory.Default(initialTarget) : await installationPluginOptionsFactory.Aquire(initialTarget, _input, runLevel); } catch (Exception ex) { _exceptionHandler.HandleException(ex, $"Installation plugin {installationPluginOptionsFactory.Name} aborted or failed"); return; } if (installOptions == null) { _exceptionHandler.HandleException(message: $"Installation plugin {installationPluginOptionsFactory.Name} was unable to generate options"); return; } var isNull = installationPluginOptionsFactory is NullInstallationOptionsFactory; if (!isNull || installationPluginFactories.Count == 0) { tempRenewal.InstallationPluginOptions.Add(installOptions); installationPluginFactories.Add(installationPluginOptionsFactory); } if (isNull) { break; } } } catch (Exception ex) { _exceptionHandler.HandleException(ex, "Invalid selection of installation plugins"); return; } // Try to run for the first time var renewal = await CreateRenewal(tempRenewal, runLevel); retry: var result = await _renewalExecution.HandleRenewal(renewal, runLevel); if (result.Abort) { _exceptionHandler.HandleException(message: $"Create certificate cancelled"); } else if (!result.Success) { if (runLevel.HasFlag(RunLevel.Interactive) && await _input.PromptYesNo("Create certificate failed, retry?", false)) { goto retry; } if (!renewal.New && await _input.PromptYesNo("Save these new settings anyway?", false)) { _renewalStore.Save(renewal, result); } _exceptionHandler.HandleException(message: $"Create certificate failed: {string.Join("\n\t- ", result.ErrorMessages)}"); } else { try { _renewalStore.Save(renewal, result); await _notification.NotifyCreated(renewal, _log.Lines); } catch (Exception ex) { _exceptionHandler.HandleException(ex); } } }
/// <summary> /// Determine if the renewal should be executes /// </summary> /// <param name="renewal"></param> /// <param name="runLevel"></param> /// <returns></returns> public async Task <RenewResult> HandleRenewal(Renewal renewal, RunLevel runLevel) { _input.CreateSpace(); _log.Reset(); using var ts = _scopeBuilder.Target(_container, renewal, runLevel); using var es = _scopeBuilder.Execution(ts, renewal, runLevel); // Generate the target var targetPlugin = es.Resolve <ITargetPlugin>(); var(disabled, disabledReason) = targetPlugin.Disabled; if (disabled) { return(new RenewResult($"Target plugin is not available. {disabledReason}")); } var target = await targetPlugin.Generate(); if (target is INull) { return(new RenewResult($"Target plugin did not generate a target")); } if (!target.IsValid(_log)) { return(new RenewResult($"Target plugin generated an invalid target")); } // Check if our validation plugin is (still) up to the task var validationPlugin = es.Resolve <IValidationPluginOptionsFactory>(); if (!validationPlugin.CanValidate(target)) { return(new RenewResult($"Validation plugin is unable to validate the target. A wildcard host was introduced into a HTTP validated renewal.")); } // Create one or more orders based on the target var orderPlugin = es.Resolve <IOrderPlugin>(); var orders = orderPlugin.Split(renewal, target); if (orders == null || orders.Count() == 0) { return(new RenewResult("Order plugin failed to create order(s)")); } _log.Verbose("Targeted convert into {n} order(s)", orders.Count()); // Check if renewal is needed if (!runLevel.HasFlag(RunLevel.ForceRenew) && !renewal.Updated) { _log.Verbose("Checking {renewal}", renewal.LastFriendlyName); if (!renewal.IsDue()) { var cs = es.Resolve <ICertificateService>(); var abort = true; foreach (var order in orders) { var cache = cs.CachedInfo(order); if (cache == null && !renewal.New) { _log.Information(LogType.All, "Renewal for {renewal} running prematurely due to detected target change", renewal.LastFriendlyName); abort = false; break; } } if (abort) { _log.Information("Renewal for {renewal} is due after {date}", renewal.LastFriendlyName, renewal.GetDueDate()); return(new RenewResult() { Abort = true }); } } else if (!renewal.New) { _log.Information(LogType.All, "Renewing certificate for {renewal}", renewal.LastFriendlyName); } } else if (runLevel.HasFlag(RunLevel.ForceRenew)) { _log.Information(LogType.All, "Force renewing certificate for {renewal}", renewal.LastFriendlyName); } // If at this point we haven't retured already with an error/abort // actually execute the renewal var result = await ExecuteRenewal(es, orders.ToList(), runLevel); // Configure task scheduler if (result.Success && !result.Abort) { if ((renewal.New || renewal.Updated) && !_args.NoTaskScheduler) { if (runLevel.HasFlag(RunLevel.Test) && !await _input.PromptYesNo($"[--test] Do you want to automatically renew with these settings?", true)) { // Early out for test runs result.Abort = true; return(result); } else { // Make sure the Task Scheduler is configured await es.Resolve <TaskSchedulerService>().EnsureTaskScheduler(runLevel, false); } } } return(result); }
/// <summary> /// Setup a new scheduled renewal /// </summary> /// </summary> /// <param name="runLevel"></param> /// <param name="steps"></param> /// <param name="tempRenewal"></param> /// <returns></returns> internal async Task SetupRenewal(RunLevel runLevel, Steps steps = Steps.All, Renewal?tempRenewal = null) { if (_args.Test) { runLevel |= RunLevel.Test; } if (_args.Force) { runLevel |= RunLevel.IgnoreCache; } _log.Information(LogType.All, "Running in mode: {runLevel}", runLevel); if (tempRenewal == null) { tempRenewal = Renewal.Create(_args.Id, _passwordGenerator); } using var configScope = _scopeBuilder.Configuration(_container, tempRenewal, runLevel); // Choose the target plugin if (steps.HasFlag(Steps.Target)) { var targetOptions = await SetupTarget(configScope, runLevel); if (targetOptions == null) { return; } tempRenewal.TargetPluginOptions = targetOptions; } // Generate initial target using var targetScope = _scopeBuilder.Target(_container, tempRenewal, runLevel); var initialTarget = targetScope.Resolve <Target>(); if (initialTarget is INull) { _exceptionHandler.HandleException(message: $"Source plugin {tempRenewal.TargetPluginOptions.Name} was unable to generate the certificate parameters."); return; } if (!initialTarget.IsValid(_log)) { _exceptionHandler.HandleException(message: $"Source plugin {tempRenewal.TargetPluginOptions.Name} generated invalid certificate parameters"); return; } _log.Information("Source generated using plugin {name}: {target}", tempRenewal.TargetPluginOptions.Name, initialTarget); // Setup the friendly name var ask = runLevel.HasFlag(RunLevel.Advanced | RunLevel.Interactive) && steps.HasFlag(Steps.Target); await SetupFriendlyName(tempRenewal, initialTarget, ask); // Choose the validation plugin if (steps.HasFlag(Steps.Validation)) { var validationOptions = await SetupValidation(targetScope, initialTarget, runLevel); if (validationOptions == null) { return; } tempRenewal.ValidationPluginOptions = validationOptions; } // Choose the order plugin if (steps.HasFlag(Steps.Order)) { tempRenewal.OrderPluginOptions = await SetupOrder(targetScope, runLevel); if (tempRenewal.OrderPluginOptions == null) { return; } } // Choose the CSR plugin if (initialTarget.UserCsrBytes != null) { tempRenewal.CsrPluginOptions = null; } else if (steps.HasFlag(Steps.Csr)) { tempRenewal.CsrPluginOptions = await SetupCsr(configScope, runLevel); if (tempRenewal.CsrPluginOptions == null) { return; } } // Choose store plugin(s) if (steps.HasFlag(Steps.Store)) { var store = await SetupStore(configScope, runLevel); if (store != null) { tempRenewal.StorePluginOptions = store; } else { return; } } // Choose installation plugin(s) if (steps.HasFlag(Steps.Installation)) { var install = await SetupInstallation(configScope, runLevel, tempRenewal, initialTarget); if (install != null) { tempRenewal.InstallationPluginOptions = install; } else { return; } } // Try to run for the first time var renewal = await CreateRenewal(tempRenewal, runLevel); retry: var result = await _renewalExecution.HandleRenewal(renewal, runLevel); if (result.Abort) { _log.Information($"Create certificate cancelled"); } else if (result.Success != true) { if (runLevel.HasFlag(RunLevel.Interactive) && await _input.PromptYesNo("Create certificate failed, retry?", false)) { goto retry; } if (!renewal.New && runLevel.HasFlag(RunLevel.Interactive) && await _input.PromptYesNo("Save these new settings anyway?", false)) { _renewalStore.Save(renewal, result); } _exceptionHandler.HandleException(message: $"Create certificate failed: {string.Join("\n\t- ", result.ErrorMessages)}"); } else { try { _renewalStore.Save(renewal, result); await _notification.NotifyCreated(renewal, _log.Lines); } catch (Exception ex) { _exceptionHandler.HandleException(ex); } } }
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); // Generate the target var targetPlugin = es.Resolve <ITargetPlugin>(); if (targetPlugin.Disabled) { throw new Exception($"Target plugin is not available to the current user, try running as administrator"); } var target = await targetPlugin.Generate(); if (target == null) { throw new Exception($"Target plugin did not generate a target"); } if (!target.IsValid(_log)) { throw new Exception($"Target plugin generated an invalid target"); } // Check if our validation plugin is (still) up to the task var validationPlugin = es.Resolve <IValidationPluginOptionsFactory>(); if (!validationPlugin.CanValidate(target)) { throw new Exception($"Validation plugin is unable to validate the target. A wildcard host was introduced into a HTTP validated renewal."); } // Check if renewal is needed if (!runLevel.HasFlag(RunLevel.ForceRenew) && !renewal.Updated) { _log.Verbose("Checking {renewal}", renewal.LastFriendlyName); if (!renewal.IsDue()) { var cs = es.Resolve <ICertificateService>(); var cache = cs.CachedInfo(renewal); if (cache != null && cache.Match(target)) { _log.Information(LogType.All, "Renewal for {renewal} is due after {date}", renewal.LastFriendlyName, renewal.GetDueDate()); return(null); } else if (!renewal.New) { _log.Information(LogType.All, "Renewal for {renewal} running prematurely due to detected target change", renewal.LastFriendlyName); } } else if (!renewal.New) { _log.Information(LogType.All, "Renewing certificate for {renewal}", renewal.LastFriendlyName); } } else if (runLevel.HasFlag(RunLevel.ForceRenew)) { _log.Information(LogType.All, "Force renewing certificate for {renewal}", renewal.LastFriendlyName); } // Create the order var client = es.Resolve <AcmeClient>(); var identifiers = target.GetHosts(false); var order = await client.CreateOrder(identifiers); // Check if the order is valid if (order.Payload.Status != AcmeClient.OrderReady && order.Payload.Status != AcmeClient.OrderPending) { return(OnRenewFail(new Challenge() { Error = order.Payload.Error })); } // Answer the challenges foreach (var authUrl in order.Payload.Authorizations) { // Get authorization details var authorization = await client.GetAuthorizationDetails(authUrl); // Find a targetPart that matches the challenge var targetPart = target.Parts. FirstOrDefault(tp => tp.GetHosts(false). Any(h => authorization.Identifier.Value == h.Replace("*.", ""))); if (targetPart == null) { return(OnRenewFail(new Challenge() { Error = "Unable to match challenge to target" })); } // Run the validation plugin var challenge = await Authorize(es, runLevel, renewal.ValidationPluginOptions, targetPart, authorization); if (challenge.Status != AcmeClient.AuthorizationValid) { return(OnRenewFail(challenge)); } } return(await OnValidationSuccess(es, renewal, target, order, runLevel)); }
/// <summary> /// Determine if the renewal should be executes /// </summary> /// <param name="renewal"></param> /// <param name="runLevel"></param> /// <returns></returns> public async Task <RenewResult> HandleRenewal(Renewal renewal, RunLevel runLevel) { _input.CreateSpace(); _log.Reset(); using var ts = _scopeBuilder.Target(_container, renewal, runLevel); using var es = _scopeBuilder.Execution(ts, renewal, runLevel); // Generate the target var targetPlugin = es.Resolve <ITargetPlugin>(); var(disabled, disabledReason) = targetPlugin.Disabled; if (disabled) { return(new RenewResult($"Source plugin is not available. {disabledReason}")); } var target = await targetPlugin.Generate(); if (target is INull) { return(new RenewResult($"Source plugin did not generate source")); } // Create one or more orders based on the target var orderPlugin = es.Resolve <IOrderPlugin>(); var orders = orderPlugin.Split(renewal, target); if (orders == null || !orders.Any()) { return(new RenewResult("Order plugin failed to create order(s)")); } _log.Verbose("Source converted into {n} order(s)", orders.Count()); foreach (var order in orders) { if (!order.Target.IsValid(_log)) { return(new RenewResult($"Source plugin generated invalid source")); } } /// Start to check the renewal var result = await HandleOrders(es, renewal, orders.ToList(), runLevel); // Configure task scheduler var setupTaskScheduler = _args.SetupTaskScheduler; if (!setupTaskScheduler && !_args.NoTaskScheduler) { setupTaskScheduler = result.Success == true && !result.Abort && (renewal.New || renewal.Updated); } if (setupTaskScheduler && runLevel.HasFlag(RunLevel.Test)) { setupTaskScheduler = await _input.PromptYesNo($"[--test] Do you want to automatically renew with these settings?", true); if (!setupTaskScheduler) { result.Abort = true; } } if (setupTaskScheduler) { var taskLevel = runLevel; if (_args.SetupTaskScheduler) { taskLevel |= RunLevel.ForceRenew; } await es.Resolve <TaskSchedulerService>().EnsureTaskScheduler(runLevel); } return(result); }
/// <summary> /// Determine if the renewal should be executes /// </summary> /// <param name="renewal"></param> /// <param name="runLevel"></param> /// <returns></returns> public async Task <RenewResult> HandleRenewal(Renewal renewal, RunLevel runLevel) { _input.CreateSpace(); _log.Reset(); using var ts = _scopeBuilder.Target(_container, renewal, runLevel); using var es = _scopeBuilder.Execution(ts, renewal, runLevel); // Generate the target var targetPlugin = es.Resolve <ITargetPlugin>(); var(disabled, disabledReason) = targetPlugin.Disabled; if (disabled) { return(new RenewResult($"Source plugin is not available. {disabledReason}")); } var target = await targetPlugin.Generate(); if (target is INull) { return(new RenewResult($"Source plugin did not generate source")); } if (!target.IsValid(_log)) { return(new RenewResult($"Source plugin generated invalid source")); } // Check if our validation plugin is (still) up to the task var validationPlugin = es.Resolve <IValidationPluginOptionsFactory>(); if (!validationPlugin.CanValidate(target)) { return(new RenewResult($"Validation plugin is unable to validate the source. A wildcard host was introduced into a HTTP validated renewal.")); } // Create one or more orders based on the target var orderPlugin = es.Resolve <IOrderPlugin>(); var orders = orderPlugin.Split(renewal, target); if (orders == null || !orders.Any()) { return(new RenewResult("Order plugin failed to create order(s)")); } _log.Verbose("Targeted convert into {n} order(s)", orders.Count()); // Test if this renewal should run right now if (!ShouldRun(es, orders, renewal, runLevel)) { return(new RenewResult() { Abort = true }); } // If at this point we haven't retured already with an error/abort // actually execute the renewal var preScript = _settings.Execution?.DefaultPreExecutionScript; var scriptClient = es.Resolve <ScriptClient>(); if (!string.IsNullOrWhiteSpace(preScript)) { await scriptClient.RunScript(preScript, $"{renewal.Id}"); } var result = await ExecuteRenewal(es, orders.ToList(), runLevel); var postScript = _settings.Execution?.DefaultPostExecutionScript; if (!string.IsNullOrWhiteSpace(postScript)) { await scriptClient.RunScript(postScript, $"{renewal.Id}"); } // Configure task scheduler var setupTaskScheduler = _args.SetupTaskScheduler; if (!setupTaskScheduler && !_args.NoTaskScheduler) { setupTaskScheduler = result.Success && !result.Abort && (renewal.New || renewal.Updated); } if (setupTaskScheduler && runLevel.HasFlag(RunLevel.Test)) { setupTaskScheduler = await _input.PromptYesNo($"[--test] Do you want to automatically renew with these settings?", true); if (!setupTaskScheduler) { result.Abort = true; } } if (setupTaskScheduler) { var taskLevel = runLevel; if (_args.SetupTaskScheduler) { taskLevel |= RunLevel.ForceRenew; } await es.Resolve <TaskSchedulerService>().EnsureTaskScheduler(runLevel); } return(result); }
/// <summary> /// Setup a new scheduled renewal /// </summary> /// <param name="runLevel"></param> internal async Task SetupRenewal(RunLevel runLevel) { if (_args.Test) { runLevel |= RunLevel.Test; } if (_args.Force) { runLevel |= RunLevel.IgnoreCache; } _log.Information(LogType.All, "Running in mode: {runLevel}", runLevel); var tempRenewal = Renewal.Create(_args.Id, _settings.ScheduledTask.RenewalDays, _passwordGenerator); using var configScope = _scopeBuilder.Configuration(_container, tempRenewal, runLevel); // Choose target plugin var targetPluginOptionsFactory = configScope.Resolve <ITargetPluginOptionsFactory>(); if (targetPluginOptionsFactory is INull) { _exceptionHandler.HandleException(message: $"No target plugin could be selected"); return; } if (targetPluginOptionsFactory.Disabled) { _exceptionHandler.HandleException(message: $"Target plugin {targetPluginOptionsFactory.Name} is not available to the current user, try running as administrator"); return; } var targetPluginOptions = runLevel.HasFlag(RunLevel.Unattended) ? await targetPluginOptionsFactory.Default() : await targetPluginOptionsFactory.Aquire(_input, runLevel); if (targetPluginOptions == null) { _exceptionHandler.HandleException(message: $"Target plugin {targetPluginOptionsFactory.Name} aborted or failed"); return; } tempRenewal.TargetPluginOptions = targetPluginOptions; // Generate Target and validation plugin choice Target initialTarget = null; IValidationPluginOptionsFactory validationPluginOptionsFactory = null; using (var targetScope = _scopeBuilder.Target(_container, tempRenewal, runLevel)) { initialTarget = targetScope.Resolve <Target>(); if (initialTarget == null) { _exceptionHandler.HandleException(message: $"Target plugin {targetPluginOptionsFactory.Name} was unable to generate a target"); return; } if (!initialTarget.IsValid(_log)) { _exceptionHandler.HandleException(message: $"Target plugin {targetPluginOptionsFactory.Name} generated an invalid target"); return; } _log.Information("Target generated using plugin {name}: {target}", targetPluginOptions.Name, initialTarget); // Choose FriendlyName if (runLevel.HasFlag(RunLevel.Advanced) && runLevel.HasFlag(RunLevel.Interactive) && string.IsNullOrEmpty(_args.FriendlyName)) { var alt = await _input.RequestString($"Suggested FriendlyName is '{initialTarget.FriendlyName}', press enter to accept or type an alternative"); if (!string.IsNullOrEmpty(alt)) { tempRenewal.FriendlyName = alt; } } tempRenewal.LastFriendlyName = initialTarget.FriendlyName; // Choose validation plugin validationPluginOptionsFactory = targetScope.Resolve <IValidationPluginOptionsFactory>(); if (validationPluginOptionsFactory is INull) { _exceptionHandler.HandleException(message: $"No validation plugin could be selected"); return; } } // Configure validation try { var validationOptions = runLevel.HasFlag(RunLevel.Unattended) ? await validationPluginOptionsFactory.Default(initialTarget) : await validationPluginOptionsFactory.Aquire(initialTarget, _input, runLevel); if (validationOptions == null) { _exceptionHandler.HandleException(message: $"Validation plugin {validationPluginOptionsFactory.Name} was unable to generate options"); return; } tempRenewal.ValidationPluginOptions = validationOptions; } catch (Exception ex) { _exceptionHandler.HandleException(ex, $"Validation plugin {validationPluginOptionsFactory.Name} aborted or failed"); return; } // Choose CSR plugin if (initialTarget.CsrBytes == null) { var csrPluginOptionsFactory = configScope.Resolve <ICsrPluginOptionsFactory>(); if (csrPluginOptionsFactory is INull) { _exceptionHandler.HandleException(message: $"No CSR plugin could be selected"); return; } // Configure CSR try { var csrOptions = runLevel.HasFlag(RunLevel.Unattended) ? await csrPluginOptionsFactory.Default() : await csrPluginOptionsFactory.Aquire(_input, runLevel); if (csrOptions == null) { _exceptionHandler.HandleException(message: $"CSR plugin {csrPluginOptionsFactory.Name} was unable to generate options"); return; } tempRenewal.CsrPluginOptions = csrOptions; } catch (Exception ex) { _exceptionHandler.HandleException(ex, $"CSR plugin {csrPluginOptionsFactory.Name} aborted or failed"); return; } } // Choose and configure store plugins var resolver = configScope.Resolve <IResolver>(); var storePluginOptionsFactories = new List <IStorePluginOptionsFactory>(); try { while (true) { var storePluginOptionsFactory = await resolver.GetStorePlugin(configScope, storePluginOptionsFactories); if (storePluginOptionsFactory == null) { _exceptionHandler.HandleException(message: $"Store could not be selected"); } if (storePluginOptionsFactory is NullStoreOptionsFactory) { if (storePluginOptionsFactories.Count == 0) { throw new Exception(); } break; } StorePluginOptions storeOptions; try { storeOptions = runLevel.HasFlag(RunLevel.Unattended) ? await storePluginOptionsFactory.Default() : await storePluginOptionsFactory.Aquire(_input, runLevel); } catch (Exception ex) { _exceptionHandler.HandleException(ex, $"Store plugin {storePluginOptionsFactory.Name} aborted or failed"); return; } if (storeOptions == null) { _exceptionHandler.HandleException(message: $"Store plugin {storePluginOptionsFactory.Name} was unable to generate options"); return; } tempRenewal.StorePluginOptions.Add(storeOptions); storePluginOptionsFactories.Add(storePluginOptionsFactory); } } catch (Exception ex) { _exceptionHandler.HandleException(ex, "Invalid selection of store plugins"); return; } // Choose and configure installation plugins var installationPluginFactories = new List <IInstallationPluginOptionsFactory>(); try { while (true) { var installationPluginFactory = await resolver.GetInstallationPlugin(configScope, tempRenewal.StorePluginOptions.Select(x => x.Instance), installationPluginFactories); if (installationPluginFactory == null) { _exceptionHandler.HandleException(message: $"Installation plugin could not be selected"); } InstallationPluginOptions installOptions; try { installOptions = runLevel.HasFlag(RunLevel.Unattended) ? await installationPluginFactory.Default(initialTarget) : await installationPluginFactory.Aquire(initialTarget, _input, runLevel); } catch (Exception ex) { _exceptionHandler.HandleException(ex, $"Installation plugin {installationPluginFactory.Name} aborted or failed"); return; } if (installOptions == null) { _exceptionHandler.HandleException(message: $"Installation plugin {installationPluginFactory.Name} was unable to generate options"); return; } if (installationPluginFactory is NullInstallationOptionsFactory) { if (installationPluginFactories.Count == 0) { tempRenewal.InstallationPluginOptions.Add(installOptions); installationPluginFactories.Add(installationPluginFactory); } break; } tempRenewal.InstallationPluginOptions.Add(installOptions); installationPluginFactories.Add(installationPluginFactory); } } catch (Exception ex) { _exceptionHandler.HandleException(ex, "Invalid selection of installation plugins"); return; } // Try to run for the first time var renewal = await CreateRenewal(tempRenewal, runLevel); var result = await _renewalExecution.Renew(renewal, runLevel); if (!result.Success) { _exceptionHandler.HandleException(message: $"Create certificate failed: {result.ErrorMessage}"); } else { _renewalStore.Save(renewal, result); } }