/// <summary> /// Remove renewal from the list of scheduled items /// </summary> internal async Task CancelRenewal(RunLevel runLevel) { if (runLevel.HasFlag(RunLevel.Unattended)) { if (!_arguments.HasFilter()) { _log.Error("Specify which renewal to cancel using the parameter --id or --friendlyname."); return; } var targets = _renewalStore.FindByArguments( _arguments.MainArguments.Id, _arguments.MainArguments.FriendlyName); if (targets.Count() == 0) { _log.Error("No renewals matched."); return; } foreach (var r in targets) { _renewalStore.Cancel(r); } } else { var renewal = await _input.ChooseOptional( "Which renewal would you like to cancel?", _renewalStore.Renewals, x => Choice.Create <Renewal?>(x), "Back"); if (renewal != null) { if (await _input.PromptYesNo($"Are you sure you want to cancel the renewal for {renewal}", false)) { _renewalStore.Cancel(renewal); } } } }
/// <summary> /// Renewal management mode /// </summary> /// <returns></returns> internal async Task ManageRenewals() { IEnumerable <Renewal> originalSelection = _renewalStore.Renewals.OrderBy(x => x.LastFriendlyName); var selectedRenewals = originalSelection; var quit = false; var displayAll = false; do { var all = selectedRenewals.Count() == originalSelection.Count(); var none = !selectedRenewals.Any(); var totalLabel = originalSelection.Count() != 1 ? "renewals" : "renewal"; var renewalSelectedLabel = selectedRenewals.Count() != 1 ? "renewals" : "renewal"; var selectionLabel = all ? selectedRenewals.Count() == 1 ? "the renewal" : "*all* renewals" : none ? "no renewals" : $"{selectedRenewals.Count()} of {originalSelection.Count()} {totalLabel}"; _input.CreateSpace(); _input.Show(null, "Welcome to the renewal manager. Actions selected in the menu below will " + "be applied to the following list of renewals. You may filter the list to target " + "your action at a more specific set of renewals, or sort it to make it easier to " + "find what you're looking for."); var displayRenewals = selectedRenewals; var displayLimited = !displayAll && selectedRenewals.Count() >= _settings.UI.PageSize; var displayHidden = 0; var displayHiddenLabel = ""; if (displayLimited) { displayRenewals = displayRenewals.Take(_settings.UI.PageSize - 1); displayHidden = selectedRenewals.Count() - displayRenewals.Count(); displayHiddenLabel = displayHidden != 1 ? "renewals" : "renewal"; } var choices = displayRenewals.Select(x => Choice.Create <Renewal?>(x, description: x.ToString(_input), color: x.History.LastOrDefault()?.Success ?? false ? x.IsDue() ? ConsoleColor.DarkYellow : ConsoleColor.Green : ConsoleColor.Red)).ToList(); if (displayLimited) { choices.Add(Choice.Create <Renewal?>(null, command: "More", description: $"{displayHidden} additional {displayHiddenLabel} selected but currently not displayed")); } await _input.WritePagedList(choices); displayAll = false; var options = new List <Choice <Func <Task> > >(); if (displayLimited) { options.Add( Choice.Create <Func <Task> >( () => { displayAll = true; return(Task.CompletedTask); }, "List all selected renewals", "A")); } options.Add( Choice.Create <Func <Task> >( async() => { quit = true; await EditRenewal(selectedRenewals.First()); }, "Edit renewal", "E", @disabled: (selectedRenewals.Count() != 1, none ? "No renewals selected." : "Multiple renewals selected."))); if (selectedRenewals.Count() > 1) { options.Add( Choice.Create <Func <Task> >( async() => selectedRenewals = await FilterRenewalsMenu(selectedRenewals), all ? "Apply filter" : "Apply additional filter", "F", @disabled: (selectedRenewals.Count() < 2, "Not enough renewals to filter."))); options.Add( Choice.Create <Func <Task> >( async() => selectedRenewals = await SortRenewalsMenu(selectedRenewals), "Sort renewals", "S", @disabled: (selectedRenewals.Count() < 2, "Not enough renewals to sort."))); } if (!all) { options.Add( Choice.Create <Func <Task> >( () => { selectedRenewals = originalSelection; return(Task.CompletedTask); }, "Reset sorting and filtering", "X", @disabled: (all, "No filters have been applied yet."))); } options.Add( Choice.Create <Func <Task> >( async() => { foreach (var renewal in selectedRenewals) { var index = selectedRenewals.ToList().IndexOf(renewal) + 1; _log.Information("Details for renewal {n}/{m}", index, selectedRenewals.Count()); await ShowRenewal(renewal); var cont = false; if (index != selectedRenewals.Count()) { cont = await _input.Wait("Press <Enter> to continue or <Esc> to abort"); if (!cont) { break; } } else { await _input.Wait(); } } }, $"Show details for {selectionLabel}", "D", @disabled: (none, "No renewals selected."))); options.Add( Choice.Create <Func <Task> >( async() => { WarnAboutRenewalArguments(); foreach (var renewal in selectedRenewals) { var runLevel = RunLevel.Interactive | RunLevel.ForceRenew; if (_args.Force) { runLevel |= RunLevel.IgnoreCache; } await ProcessRenewal(renewal, runLevel); } }, $"Run {selectionLabel}", "R", @disabled: (none, "No renewals selected."))); options.Add( Choice.Create <Func <Task> >( async() => selectedRenewals = await Analyze(selectedRenewals), $"Analyze duplicates for {selectionLabel}", "U", @disabled: (none, "No renewals selected."))); options.Add( Choice.Create <Func <Task> >( async() => { var confirm = await _input.PromptYesNo($"Are you sure you want to cancel {selectedRenewals.Count()} currently selected {renewalSelectedLabel}?", false); if (confirm) { foreach (var renewal in selectedRenewals) { _renewalStore.Cancel(renewal); } ; originalSelection = _renewalStore.Renewals.OrderBy(x => x.LastFriendlyName); selectedRenewals = originalSelection; } }, $"Cancel {selectionLabel}", "C", @disabled: (none, "No renewals selected."))); options.Add( Choice.Create <Func <Task> >( async() => { var confirm = await _input.PromptYesNo($"Are you sure you want to revoke the most recently issued certificate for {selectedRenewals.Count()} currently selected {renewalSelectedLabel}? This should only be done in case of a (suspected) security breach. Cancel the {renewalSelectedLabel} if you simply don't need the certificates anymore.", false); if (confirm) { await RevokeCertificates(selectedRenewals); } }, $"Revoke certificate(s) for {selectionLabel}", "V", @disabled: (none, "No renewals selected."))); options.Add( Choice.Create <Func <Task> >( () => { quit = true; return(Task.CompletedTask); }, "Back", "Q", @default: !originalSelection.Any())); if (selectedRenewals.Count() > 1) { _input.CreateSpace(); _input.Show(null, $"Currently selected {selectedRenewals.Count()} of {originalSelection.Count()} {totalLabel}"); } var chosen = await _input.ChooseFromMenu( "Choose an action or type numbers to select renewals", options, (string unexpected) => Choice.Create <Func <Task> >( async() => selectedRenewals = await FilterRenewalsById(selectedRenewals, unexpected))); await chosen.Invoke(); }while (!quit); }
/// <summary> /// Renewal management mode /// </summary> /// <returns></returns> internal async Task ManageRenewals() { IEnumerable <Renewal> originalSelection = _renewalStore.Renewals.OrderBy(x => x.LastFriendlyName); var selectedRenewals = originalSelection; var quit = false; do { var all = selectedRenewals.Count() == originalSelection.Count(); var none = selectedRenewals.Count() == 0; var totalLabel = originalSelection.Count() != 1 ? "renewals" : "renewal"; var selectionLabel = all ? $"*all* renewals" : none ? "no renewals" : $"{selectedRenewals.Count()} of {originalSelection.Count()} {totalLabel}"; var renewalSelectedLabel = selectedRenewals.Count() != 1 ? "renewals" : "renewal"; _input.Show(null, "Welcome to the renewal manager. Actions selected in the menu below will " + "be applied to the following list of renewals. You may filter the list to target " + "your action at a more specific set of renewals, or sort it to make it easier to " + "find what you're looking for.", true); await _input.WritePagedList( selectedRenewals.Select(x => Choice.Create <Renewal?>(x, description: x.ToString(_input), color: x.History.Last().Success ? x.IsDue() ? ConsoleColor.DarkYellow : ConsoleColor.Green : ConsoleColor.Red))); var options = new List <Choice <Func <Task> > >(); options.Add( Choice.Create <Func <Task> >( async() => selectedRenewals = await FilterRenewalsMenu(selectedRenewals), all ? "Apply filter" : "Apply additional filter", "F", @disabled: selectedRenewals.Count() < 2, disabledReason: "Not enough renewals to filter.", @default: !(selectedRenewals.Count() < 2))); options.Add( Choice.Create <Func <Task> >( async() => selectedRenewals = await SortRenewalsMenu(selectedRenewals), "Sort renewals", "S", @disabled: selectedRenewals.Count() < 2, disabledReason: "Not enough renewals to sort.")); options.Add( Choice.Create <Func <Task> >( () => { selectedRenewals = originalSelection; return(Task.CompletedTask); }, "Reset sorting and filtering", "X", @disabled: all, disabledReason: "No filters have been applied yet.", @default: originalSelection.Count() > 0 && none)); options.Add( Choice.Create <Func <Task> >( async() => { foreach (var renewal in selectedRenewals) { var index = selectedRenewals.ToList().IndexOf(renewal) + 1; _log.Information("Details for renewal {n}/{m}", index, selectedRenewals.Count()); await ShowRenewal(renewal); var cont = false; if (index != selectedRenewals.Count()) { cont = await _input.Wait("Press <Enter> to continue or <Esc> to abort"); if (!cont) { break; } } else { await _input.Wait(); } } }, $"Show details for {selectionLabel}", "D", @disabled: none, disabledReason: "No renewals selected.")); options.Add( Choice.Create <Func <Task> >( async() => { WarnAboutRenewalArguments(); foreach (var renewal in selectedRenewals) { var runLevel = RunLevel.Interactive | RunLevel.ForceRenew; if (_args.Force) { runLevel |= RunLevel.IgnoreCache; } await ProcessRenewal(renewal, runLevel); } }, $"Run {selectionLabel}", "R", @disabled: none, disabledReason: "No renewals selected.")); options.Add( Choice.Create <Func <Task> >( async() => { var confirm = await _input.PromptYesNo($"Are you sure you want to cancel {selectedRenewals.Count()} currently selected {renewalSelectedLabel}?", false); if (confirm) { foreach (var renewal in selectedRenewals) { _renewalStore.Cancel(renewal); } ; originalSelection = _renewalStore.Renewals.OrderBy(x => x.LastFriendlyName); selectedRenewals = originalSelection; } }, $"Cancel {selectionLabel}", "C", @disabled: none, disabledReason: "No renewals selected.")); options.Add( Choice.Create <Func <Task> >( async() => { var confirm = await _input.PromptYesNo($"Are you sure you want to revoke the most recently issued certificate for {selectedRenewals.Count()} currently selected {renewalSelectedLabel}? This should only be done in case of a (suspected) security breach. Cancel the {renewalSelectedLabel} if you simply don't need the certificates anymore.", false); if (confirm) { foreach (var renewal in selectedRenewals) { using var scope = _scopeBuilder.Execution(_container, renewal, RunLevel.Interactive); var cs = scope.Resolve <ICertificateService>(); try { await cs.RevokeCertificate(renewal); renewal.History.Add(new RenewResult("Certificate revoked")); } catch (Exception ex) { _exceptionHandler.HandleException(ex); } } ; } }, $"Revoke {selectionLabel}", "V", @disabled: none, disabledReason: "No renewals selected.")); options.Add( Choice.Create <Func <Task> >( () => { quit = true; return(Task.CompletedTask); }, "Back", "Q", @default: originalSelection.Count() == 0)); _input.Show(null, $"Currently selected {selectedRenewals.Count()} of {originalSelection.Count()} {totalLabel}", true); var chosen = await _input.ChooseFromMenu("Please choose from the menu", options); await chosen.Invoke(); }while (!quit); }