private static void Main(string[] args) { // Setup DI _container = AutofacBuilder.Global(args, _clientName, new PluginService(_log)); // Basic services _log = _container.Resolve <ILogService>(); _optionsService = _container.Resolve <IOptionsService>(); _options = _optionsService.Options; if (_options == null) { return; } _input = _container.Resolve <IInputService>(); // .NET Framework check var dn = _container.Resolve <DotNetVersionService>(); if (!dn.Check()) { return; } // Show version information _input.ShowBanner(); // Advanced services _renewalService = _container.Resolve <IRenewalService>(); ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; // Main loop do { try { if (_options.Renew) { CheckRenewals(_options.ForceRenewal); CloseDefault(); } else if (!string.IsNullOrEmpty(_options.Plugin)) { if (_options.Cancel) { CancelRenewal(); } else { CreateNewCertificate(RunLevel.Unattended); } CloseDefault(); } else { MainMenu(); } } catch (Exception e) { HandleException(e); Environment.ExitCode = e.HResult; } if (!_options.CloseOnFinish) { _options.Plugin = null; _options.Renew = false; _options.ForceRenewal = false; Environment.ExitCode = 0; } } while (!_options.CloseOnFinish); }
/// <summary> /// Make sure we have authorization for every host in target /// </summary> /// <param name="target"></param> /// <returns></returns> private static AuthorizationState Authorize(ILifetimeScope renewalScope, Target target) { var invalid = new AuthorizationState { Status = _authorizationInvalid }; try { List <string> identifiers = target.GetHosts(false); List <AuthorizationState> authStatus = new List <AuthorizationState>(); var client = renewalScope.Resolve <AcmeClientWrapper>(); foreach (var identifier in identifiers) { _log.Information("Authorize identifier: {identifier}", identifier); var authzState = client.Acme.AuthorizeIdentifier(identifier); if (authzState.Status == _authorizationValid && !_options.Test) { _log.Information("Cached authorization result: {Status}", authzState.Status); authStatus.Add(authzState); } else { using (var identifierScope = AutofacBuilder.Identifier(renewalScope, target, identifier)) { IValidationPluginFactory validationPluginFactory = null; IValidationPlugin validationPlugin = null; try { validationPluginFactory = identifierScope.Resolve <IValidationPluginFactory>(); validationPlugin = identifierScope.Resolve <IValidationPlugin>(); } catch (Exception ex) { _log.Error(ex, "Error resolving validation plugin"); } if (validationPluginFactory == null || validationPluginFactory is INull || validationPlugin == null) { _log.Error("Validation plugin not found or not created."); return(invalid); } if (!authzState.Challenges.Any(c => c.Type == validationPluginFactory.ChallengeType)) { _log.Error("Expected challenge type {type} not available for {identifier}.", validationPluginFactory.ChallengeType, identifier); return(invalid); } _log.Information("Authorizing {dnsIdentifier} using {challengeType} validation ({name})", identifier, validationPluginFactory.ChallengeType, validationPluginFactory.Name); var challenge = client.Acme.DecodeChallenge(authzState, validationPluginFactory.ChallengeType); try { validationPlugin.PrepareChallenge(challenge); } catch (Exception ex) { _log.Error(ex, "Error preparing for challenge answer"); return(invalid); } _log.Debug("Submitting answer"); authzState.Challenges = new AuthorizeChallenge[] { challenge }; client.Acme.SubmitChallengeAnswer(authzState, validationPluginFactory.ChallengeType, true); // have to loop to wait for server to stop being pending. // TODO: put timeout/retry limit in this loop while (authzState.Status == _authorizationPending) { _log.Debug("Refreshing authorization"); Thread.Sleep(4000); // this has to be here to give ACME server a chance to think var newAuthzState = client.Acme.RefreshIdentifierAuthorization(authzState); if (newAuthzState.Status != _authorizationPending) { authzState = newAuthzState; } } if (authzState.Status != _authorizationValid) { _log.Error("Authorization result: {Status}", authzState.Status); } else { _log.Information("Authorization result: {Status}", authzState.Status); } authStatus.Add(authzState); } } } foreach (var authState in authStatus) { if (authState.Status != _authorizationValid) { return(authState); } } return(new AuthorizationState { Status = _authorizationValid }); } catch (Exception ex) { _log.Error("Error authorizing {target}", target); HandleException(ex); return(invalid); } }
private static void CreateNewCertificate(RunLevel runLevel) { _log.Information(true, "Running in {runLevel} mode", runLevel); var tempRenewal = CreateRenewal(_options); using (var scope = AutofacBuilder.Renewal(_container, tempRenewal, runLevel)) { // Choose target plugin var targetPluginFactory = scope.Resolve <ITargetPluginFactory>(); if (targetPluginFactory is INull) { return; // User cancelled or unable to resolve } // Aquire target var targetPlugin = scope.Resolve <ITargetPlugin>(); var target = runLevel == RunLevel.Unattended ? targetPlugin.Default(_optionsService) : targetPlugin.Aquire(_optionsService, _input, runLevel); var originalTarget = tempRenewal.Binding; tempRenewal.Binding = target; if (target == null) { _log.Error("Plugin {name} was unable to generate a target", targetPluginFactory.Name); return; } tempRenewal.Binding.TargetPluginName = targetPluginFactory.Name; tempRenewal.Binding.SSLPort = _options.SSLPort; tempRenewal.Binding.ValidationPort = _options.ValidationPort; tempRenewal.Binding.ValidationPluginName = originalTarget.ValidationPluginName; _log.Information("Plugin {name} generated target {target}", targetPluginFactory.Name, tempRenewal.Binding); // Choose validation plugin var validationPluginFactory = scope.Resolve <IValidationPluginFactory>(); if (validationPluginFactory is INull) { return; // User cancelled } else if (!validationPluginFactory.CanValidate(target)) { // Might happen in unattended mode _log.Error("Validation plugin {name} is unable to validate target", validationPluginFactory.Name); return; } // Configure validation try { if (runLevel == RunLevel.Unattended) { validationPluginFactory.Default(target, _optionsService); } else { validationPluginFactory.Aquire(target, _optionsService, _input, runLevel); } tempRenewal.Binding.ValidationPluginName = $"{validationPluginFactory.ChallengeType}.{validationPluginFactory.Name}"; } catch (Exception ex) { _log.Error(ex, "Invalid validation input"); return; } // Choose and configure installation plugins try { var installFactories = scope.Resolve <List <IInstallationPluginFactory> >(); if (installFactories.Count == 0) { // User cancelled, otherwise we would at least have the Null-installer return; } foreach (var installFactory in installFactories) { if (runLevel == RunLevel.Unattended) { installFactory.Default(tempRenewal, _optionsService); } else { installFactory.Aquire(tempRenewal, _optionsService, _input, runLevel); } } tempRenewal.InstallationPluginNames = installFactories.Select(f => f.Name).ToList(); } catch (Exception ex) { _log.Error(ex, "Invalid installation input"); return; } var result = Renew(scope, CreateRenewal(tempRenewal)); if (!result.Success) { _log.Error("Create certificate failed"); } } }