public static void AddCcsBinding( [Required(Description = "Host name")] string hostName, [Optional(false, "sni", Description = "Require SNI for newly created binding")] bool requireSni, [Optional("localhost", "s", Description = "IIS server name")] string serverName, [Optional(false, Description = "Show verbose error messages")] bool verbose) { Log.VerboseMode = verbose; hostName = hostName.ToAsciiHostName(); using (var sc = new ServerContext(serverName)) { try { Log.Write($"Getting bindings from {serverName}..."); var bindings = sc.GetBindings().ToArray(); Log.WriteLine("OK"); Log.Write($"Checking for already existing HTTPS binding for {hostName.ExplainHostName()}..."); var exists = bindings.Any(x => x.Host.Equals(hostName, StringComparison.OrdinalIgnoreCase) && x.Protocol.Equals("https", StringComparison.OrdinalIgnoreCase)); if (exists) { AcmeEnvironment.CrashExit("Binding already exists"); } Log.WriteLine("OK"); Log.Write("Getting site..."); var site = bindings.FirstOrDefault(x => x.Host.Equals(hostName, StringComparison.OrdinalIgnoreCase) && x.Protocol.Equals("http", StringComparison.OrdinalIgnoreCase)); if (site == null) { AcmeEnvironment.CrashExit("HTTP binding not found"); } Log.WriteLine($"OK, found site '{site.SiteName}', ID {site.SiteId}"); Log.Write("Adding new binding..."); sc.AddCcsBinding(site.SiteName, hostName, requireSni); Log.WriteLine("OK"); } catch (Exception ex) { AcmeEnvironment.CrashExit(ex); } } }
public static void AddHosts( [Optional(false, "ccs", Description = "Add CCS binding to hosts without one and add them as well")] bool addCcsBinding, [Optional(false, "sni", Description = "Require SNI for newly created bindings")] bool requireSni, [Optional("localhost", "s", Description = "IIS server name")] string serverName, [Optional(AcmeEnvironment.DEFAULT_CONFIG_NAME, "cfg", Description = "Configuration file name")] string cfgFileName, [Optional(false, Description = "Show verbose error messages")] bool verbose) { Log.VerboseMode = verbose; AcmeEnvironment.LoadConfig(cfgFileName); using (var sc = new ServerContext(serverName)) { IEnumerable <BindingInfo> bindings = null; try { Log.Write($"Getting bindings from '{serverName}'..."); // Get all bindings bindings = sc.GetBindings(); } catch (Exception ex) { AcmeEnvironment.CrashExit(ex); } // Get only bindings matching the following criteria // - host name specified // - site is running // - site is running on default port bindings = from b in bindings where !string.IsNullOrEmpty(b.Host) && b.SiteStarted && b.IsDefaultPort select b; // Get only CCS enabled sites, unless overriden if (!addCcsBinding) { bindings = bindings.Where(x => x.CentralCertStore); } Log.WriteLine($"OK, {bindings.Count()} bindings found"); // Find new hosts Log.Write("Finding new hosts to add..."); bindings = bindings.Where(x => !AcmeEnvironment.CfgStore.Hosts.SelectMany(h => h.GetNames()).Any(h => h.Equals(x.Host, StringComparison.OrdinalIgnoreCase))); if (!bindings.Any()) { Log.WriteLine("None"); return; } Log.WriteLine($"OK"); using (var ac = new AutoAcmeContext(AcmeEnvironment.CfgStore.ServerUri)) { ac.ChallengeVerificationRetryCount = AcmeEnvironment.CfgStore.ChallengeVerificationRetryCount; ac.ChallengeVerificationWait = TimeSpan.FromSeconds(AcmeEnvironment.CfgStore.ChallengeVerificationWaitSeconds); // Login to Let's Encrypt service if (string.IsNullOrEmpty(AcmeEnvironment.CfgStore.SerializedAccountData)) { AcmeEnvironment.CfgStore.SerializedAccountData = ac.RegisterAndLogin(AcmeEnvironment.CfgStore.EmailAddress); AcmeEnvironment.SaveConfig(cfgFileName); } else { ac.Login(AcmeEnvironment.CfgStore.SerializedAccountData); } // Add new hosts Log.Indent(); using (var challengeManager = AcmeEnvironment.CreateChallengeManager()) { foreach (var binding in bindings.ToArray()) { // Check if was already added before if (AcmeEnvironment.CfgStore.Hosts.SelectMany(h => h.GetNames()).Any(h => h.Equals(binding.Host, StringComparison.OrdinalIgnoreCase))) { continue; } Log.WriteLine($"Adding new host {binding.Host.ExplainHostName()}:"); Log.Indent(); // Request certificate CertificateRequestResult result = null; try { result = ac.GetCertificate(new[] { binding.Host }, AcmeEnvironment.CfgStore.PfxPassword, challengeManager); } catch (Exception ex) { Log.Exception(ex, "Request failed"); continue; } // Export files Log.WriteLine("Exporting files:"); Log.Indent(); result.Export(binding.Host, AcmeEnvironment.CfgStore.PfxFolder, AcmeEnvironment.CfgStore.PemFolder); Log.Unindent(); // Update database entry Log.Write("Updating database entry..."); AcmeEnvironment.CfgStore.Hosts.Add(new Host { CommonName = binding.Host, NotBefore = result.Certificate.NotBefore, NotAfter = result.Certificate.NotAfter, SerialNumber = result.Certificate.SerialNumber, Thumbprint = result.Certificate.Thumbprint }); Log.WriteLine("OK"); AcmeEnvironment.SaveConfig(cfgFileName); // Add HTTPS + CCS binding var alreadyHasHttpsWithCcs = bindings.Any(b => b.Host.Equals(binding.Host, StringComparison.OrdinalIgnoreCase) && b.Protocol.Equals("https", StringComparison.OrdinalIgnoreCase) && b.CentralCertStore); if (addCcsBinding && !alreadyHasHttpsWithCcs) { try { Log.Write($"Adding HTTPS CCS binding for {binding.Host.ExplainHostName()}..."); sc.AddCcsBinding(binding.SiteName, binding.Host, requireSni); Log.WriteLine("OK"); } catch (Exception ex) { AcmeEnvironment.CrashExit(ex); } } Log.Unindent(); } Log.Unindent(); } } } }