diff --git a/src/LetsEncryptConsole/App.cs b/src/LetsEncryptConsole/App.cs deleted file mode 100644 index cd397de..0000000 --- a/src/LetsEncryptConsole/App.cs +++ /dev/null @@ -1,300 +0,0 @@ -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -using MaksIT.Core.Extensions; - -using MaksIT.LetsEncrypt.Services; -using MaksIT.LetsEncrypt.Entities; -using MaksIT.LetsEncryptConsole.Services; - -using MaksIT.SSHProvider; - -namespace MaksIT.LetsEncryptConsole; - -public interface IApp { - - Task Run(string[] args); -} - - - - -public class App : IApp { - - private readonly string _appPath = AppDomain.CurrentDomain.BaseDirectory; - - private readonly ILogger _logger; - private readonly Configuration _appSettings; - private readonly ILetsEncryptService _letsEncryptService; - private readonly ITerminalService _terminalService; - - private static readonly string _registerAccount = "--register-account"; - private static readonly string _server = "--server"; - private static readonly string _mail = "-m"; - - public App( - ILogger logger, - IOptions appSettings, - ILetsEncryptService letsEncryptService, - ITerminalService terminalService - ) { - _logger = logger; - _appSettings = appSettings.Value; - _letsEncryptService = letsEncryptService; - _terminalService = terminalService; - } - - public async Task Run(string[] args) { - - - - var parsedArgs = args.Select(x => x.Split(' ')).ToDictionary(x => x[0].Trim(), x => x[1].Trim()); - - if (parsedArgs.ContainsKey(_registerAccount)) { - _logger.LogInformation("Registring accoount"); - - if(!parsedArgs.ContainsKey(_server)) - throw new ArgumentNullException("Server is required"); - - if(!parsedArgs.ContainsKey(_mail)) - throw new ArgumentNullException("Mail is required"); - - var mail = parsedArgs[_mail]; - - if (parsedArgs[_server] == "staging") - await _letsEncryptService.ConfigureClient("https://acme-staging-v02.api.letsencrypt.org/"); - else if(parsedArgs[_server] == "production") - await _letsEncryptService.ConfigureClient("https://acme-v02.api.letsencrypt.org/"); - else - throw new ArgumentException("Invalid server"); - - - - - - return; - } - - - - try { - _logger.LogInformation("Let's Encrypt client. Started..."); - - foreach (var env in _appSettings.Environments?.Where(x => x.Active) ?? new List()) { - - _logger.LogInformation($"Let's Encrypt C# .Net Core Client, environment: {env.Name}"); - - //loop all customers - foreach (Customer customer in _appSettings.Customers?.Where(x => x.Active) ?? new List()) { - - _logger.LogInformation($"Managing customer: {customer.Id} - {customer.Name} {customer.LastName}"); - - //define cache folder - string cachePath = Path.Combine(_appPath, customer.Id, env.Name, "cache"); - if (!Directory.Exists(cachePath)) { - Directory.CreateDirectory(cachePath); - } - - //check acme directory - var acmePath = Path.Combine(_appPath, customer.Id, env.Name, "acme"); - if (!Directory.Exists(acmePath)) { - Directory.CreateDirectory(acmePath); - } - - //loop each customer website - foreach (Site site in customer.Sites?.Where(s => s.Active) ?? new List()) { - _logger.LogInformation($"Managing site: {site.Name}"); - - - //create folder for ssl - string sslPath = Path.Combine(_appPath, customer.Id, env.Name, "ssl", site.Name); - if (!Directory.Exists(sslPath)) { - Directory.CreateDirectory(sslPath); - } - - var cacheFile = Path.Combine(cachePath, $"{site.Name}.lets-encrypt.cache.json"); - - - - #region LetsEncrypt client configuration and local registration cache initialization - _logger.LogInformation("1. Client Initialization..."); - - await _letsEncryptService.ConfigureClient(env.Url); - - var registrationCache = (File.Exists(cacheFile) - ? File.ReadAllText(cacheFile) - : null) - .ToObject(); - - var initResult = await _letsEncryptService.Init(customer.Contacts, registrationCache); - if (!initResult.IsSuccess) { - continue; - } - #endregion - - #region LetsEncrypt terms of service - _logger.LogInformation($"Terms of service: {_letsEncryptService.GetTermsOfServiceUri()}"); - #endregion - - // get cached certificate and check if it's valid - // if valid check if cert and key exists otherwise recreate - // else continue with new certificate request - var certRes = new CachedCertificateResult(); - if (registrationCache != null && registrationCache.TryGetCachedCertificate(site.Name, out certRes)) { - - File.WriteAllText(Path.Combine(sslPath, $"{site.Name}.crt"), certRes.Certificate); - - if (certRes.PrivateKey != null) - File.WriteAllText(Path.Combine(sslPath, $"{site.Name}.key"), certRes.PrivateKey.ExportRSAPrivateKeyPem()); - - _logger.LogInformation("Certificate and Key exists and valid. Restored from cache."); - } - else { - - - //create new orders - #region LetsEncrypt new order - _logger.LogInformation("2. Client New Order..."); - - var (orders, newOrderResult) = await _letsEncryptService.NewOrder(site.Hosts, site.Challenge); - if (!newOrderResult.IsSuccess || orders == null) { - continue; - } - #endregion - - if (orders.Count > 0) { - switch (site.Challenge) { - case "http-01": { - //ensure to enable static file discovery on server in .well-known/acme-challenge - //and listen on 80 port - - foreach (FileInfo file in new DirectoryInfo(acmePath).GetFiles()) - file.Delete(); - - foreach (var result in orders) { - Console.WriteLine($"Key: {result.Key}, Value: {result.Value}"); - string[] splitToken = result.Value.Split('.'); - - File.WriteAllText(Path.Combine(acmePath, splitToken[0]), result.Value); - } - - foreach (FileInfo file in new DirectoryInfo(acmePath).GetFiles()) { - if (env?.SSH?.Active ?? false) { - UploadFiles(_logger, env.SSH, env.ACME.Linux.Path, file.Name, File.ReadAllBytes(file.FullName), env.ACME.Linux.Owner, env.ACME.Linux.ChangeMode); - } - else { - throw new NotImplementedException(); - } - } - - break; - } - - case "dns-01": { - //Manage DNS server MX record, depends from provider - throw new NotImplementedException(); - } - - default: { - throw new NotImplementedException(); - } - } - - - #region LetsEncrypt complete challenges - _logger.LogInformation("3. Client Complete Challange..."); - var completeChallengesResult = await _letsEncryptService.CompleteChallenges(); - if (!completeChallengesResult.IsSuccess) { - continue; - } - _logger.LogInformation("Challanges comleted."); - #endregion - - await Task.Delay(1000); - - #region Download new certificate - _logger.LogInformation("4. Download certificate..."); - var (certData, getCertResult) = await _letsEncryptService.GetCertificate(site.Name); - if (!getCertResult.IsSuccess || certData == null) { - continue; - } - - // not used in this scenario - // var (cert, key) = certData.Value; - #endregion - - #region Persist cache - registrationCache = _letsEncryptService.GetRegistrationCache(); - File.WriteAllText(cacheFile, registrationCache.ToJson()); - #endregion - } - - #region Save cert and key to filesystem - certRes = new CachedCertificateResult(); - if (registrationCache.TryGetCachedCertificate(site.Name, out certRes)) { - - File.WriteAllText(Path.Combine(sslPath, $"{site.Name}.crt"), certRes.Certificate); - - if (certRes.PrivateKey != null) - File.WriteAllText(Path.Combine(sslPath, $"{site.Name}.key"), certRes.PrivateKey.ExportRSAPrivateKeyPem()); - - _logger.LogInformation("Certificate saved."); - - foreach (FileInfo file in new DirectoryInfo(sslPath).GetFiles()) { - - if (env?.SSH?.Active ?? false) { - UploadFiles(_logger, env.SSH, $"{env.SSL.Linux.Path}/{site.Name}", file.Name, File.ReadAllBytes(file.FullName), env.SSL.Linux.Owner, env.SSL.Linux.ChangeMode); - } - else { - throw new NotImplementedException(); - } - } - - } - else { - _logger.LogError("Unable to get new cached certificate."); - } - #endregion - - } - } - } - } - - _logger.LogInformation($"Let's Encrypt client. Execution complete."); - } - catch (Exception ex) { - _logger.LogError(ex, $"Let's Encrypt client. Unhandled exception."); - } - - - } - - - - - private void UploadFiles( - ILogger logger, - SSHClientSettings sshSettings, - string workDir, - string fileName, - byte[] bytes, - string owner, - string changeMode - ) { - using var sshService = new SSHService(logger, sshSettings.Host, sshSettings.Port, sshSettings.Username, sshSettings.Password); - sshService.Connect(); - - sshService.RunSudoCommand(sshSettings.Password, $"mkdir {workDir}"); - - sshService.RunSudoCommand(sshSettings.Password, $"chown {owner} {workDir} -R"); - sshService.RunSudoCommand(sshSettings.Password, $"chmod 777 {workDir} -R"); - - sshService.Upload($"{workDir}", fileName, bytes); - - sshService.RunSudoCommand(sshSettings.Password, $"chown {owner} {workDir} -R"); - sshService.RunSudoCommand(sshSettings.Password, $"chmod {changeMode} {workDir} -R"); - - //sshService.RunSudoCommand(sshSettings.Password, $"systemctl restart nginx"); - } -} diff --git a/src/LetsEncryptConsole/Configuration.cs b/src/LetsEncryptConsole/Configuration.cs deleted file mode 100644 index 58d0cb1..0000000 --- a/src/LetsEncryptConsole/Configuration.cs +++ /dev/null @@ -1,71 +0,0 @@ - -namespace MaksIT.LetsEncryptConsole; - -public class Configuration { - public LetsEncryptEnvironment[]? Environments { get; set; } - public Customer[]? Customers { get; set; } -} - -public class OsWindows { - public string? Path { get; set; } -} - -public class OsLinux { - public string? Path { get; set; } - - public string? Owner { get; set; } - - public string? ChangeMode { get; set; } - -} - -public class OsDependant { - public OsWindows? Windows { get; set; } - public OsLinux? Linux { get; set; } -} - -public class SSHClientSettings { - public bool Active { get; set; } - - public string? Host { get; set; } - - public int Port { get; set; } - - public string? Username { get; set; } - - public string? Password { get; set; } -} - - - - public class LetsEncryptEnvironment { - public bool Active { get; set; } - public string? Name { get; set; } - public string? Url { get; set; } - - public OsDependant? ACME { get; set; } - public OsDependant? SSL { get; set; } - - public SSHClientSettings? SSH { get; set; } - } - - public class Customer { - private string? _id; - public string Id { - get => _id ?? string.Empty; - set => _id = value; - } - - public bool Active { get; set; } - public string[]? Contacts { get; set; } - public string? Name { get; set; } - public string? LastName { get; set; } - public Site[]? Sites { get; set; } - } - - public class Site { - public bool Active { get; set; } - public string? Name { get; set; } - public string[]? Hosts { get; set; } - public string? Challenge { get; set; } - } diff --git a/src/LetsEncryptConsole/LetsEncryptConsole.csproj b/src/LetsEncryptConsole/LetsEncryptConsole.csproj deleted file mode 100644 index 8ce4a60..0000000 --- a/src/LetsEncryptConsole/LetsEncryptConsole.csproj +++ /dev/null @@ -1,44 +0,0 @@ - - - - Exe - net7.0 - enable - enable - MaksIT.$(MSBuildProjectName.Replace(" ", "_")) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - diff --git a/src/LetsEncryptConsole/Program.cs b/src/LetsEncryptConsole/Program.cs deleted file mode 100644 index 7edba4d..0000000 --- a/src/LetsEncryptConsole/Program.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - -using Serilog; - -using MaksIT.LetsEncryptConsole.Services; -using MaksIT.LetsEncrypt.Extensions; - -namespace MaksIT.LetsEncryptConsole; - -class Program { - private static readonly IConfiguration _configuration = InitConfig(); - - static void Main(string[] args) { - // create service collection - var services = new ServiceCollection(); - ConfigureServices(services); - - // create service provider - var serviceProvider = services.BuildServiceProvider(); - - // entry to run app -#pragma warning disable CS8602 // Dereference of a possibly null reference. - var app = serviceProvider.GetService(); - app.Run(args).Wait(); -#pragma warning restore CS8602 // Dereference of a possibly null reference. - } - - public static void ConfigureServices(IServiceCollection services) { - - var configurationSection = _configuration.GetSection("Configuration"); - services.Configure(configurationSection); - var appSettings = configurationSection.Get(); - - #region Configure logging - services.AddLogging(configure => { - configure.AddSerilog(new LoggerConfiguration() - .ReadFrom.Configuration(_configuration) - .CreateLogger()); - }); - #endregion - - #region Services - services.RegisterLetsEncrypt(); - services.AddSingleton(); - #endregion - - // add app - services.AddSingleton(); - } - - private static IConfiguration InitConfig() { - var aspNetCoreEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); - - var configuration = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddEnvironmentVariables(); - - if (!string.IsNullOrWhiteSpace(aspNetCoreEnvironment) - && new FileInfo(Path.Combine(Directory.GetCurrentDirectory(), $"appsettings.{aspNetCoreEnvironment}.json")).Exists - ) - configuration.AddJsonFile($"appsettings.{aspNetCoreEnvironment}.json", true); - else - configuration.AddJsonFile($"appsettings.json", true, true); - - return configuration.Build(); - } -} - diff --git a/src/LetsEncryptConsole/README.md b/src/LetsEncryptConsole/README.md deleted file mode 100644 index 6e5bd17..0000000 --- a/src/LetsEncryptConsole/README.md +++ /dev/null @@ -1,140 +0,0 @@ -#ACMEv2 Client library - -https://tools.ietf.org/html/draft-ietf-acme-acme-18 - -The following diagram illustrates the relations between resources on -an ACME server. For the most part, these relations are expressed by -URLs provided as strings in the resources' JSON representations. -Lines with labels in quotes indicate HTTP link relations. - - directory - | - +--> new-nonce - | - +----------+----------+-----+-----+------------+ - | | | | | - | | | | | - V V V V V - newAccount newAuthz newOrder revokeCert keyChange - | | | - | | | - V | V - account | order -----> cert - | | - | | - | V - +------> authz - | ^ - | | "up" - V | - challenge - - - - +-------------------+--------------------------------+--------------+ - | Action | Request | Response | - +-------------------+--------------------------------+--------------+ - | Get directory | GET directory | 200 | - | | | | - | Get nonce | HEAD newNonce | 200 | - | | | | - | Create account | POST newAccount | 201 -> | - | | | account | - | | | | - | Submit order | POST newOrder | 201 -> order | - | | | | - | Fetch challenges | POST-as-GET order's | 200 | - | | authorization urls | | - | | | | - | Respond to | POST authorization challenge | 200 | - | challenges | urls | | - | | | | - | Poll for status | POST-as-GET order | 200 | - | | | | - | Finalize order | POST order's finalize url | 200 | - | | | | - | Poll for status | POST-as-GET order | 200 | - | | | | - | Download | POST-as-GET order's | 200 | - | certificate | certificate url | | - +-------------------+--------------------------------+--------------+ - - - - - - - pending - | - | Receive - | response - V - processing <-+ - | | | Server retry or - | | | client retry request - | +----+ - | - | - Successful | Failed - validation | validation - +---------+---------+ - | | - V V - valid invalid - - - - - https://community.letsencrypt.org/t/acme-client-finalized-order-stuck-on-ready-state/165196 - - The following table illustrates a typical sequence of requests - required to establish a new account with the server, prove control of - an identifier, issue a certificate, and fetch an updated certificate - some time after issuance. The "->" is a mnemonic for a Location - header field pointing to a created resource. - - +-------------------+--------------------------------+--------------+ - | Action | Request | Response | - +-------------------+--------------------------------+--------------+ - | Get directory | GET directory | 200 | - | | | | - | Get nonce | HEAD newNonce | 200 | - | | | | - | Create account | POST newAccount | 201 -> | - | | | account | - | | | | - | Submit order | POST newOrder | 201 -> order | - | | | | - | Fetch challenges | POST-as-GET order's | 200 | - | | authorization urls | | - | | | | - | Respond to | POST authorization challenge | 200 | - | challenges | urls | | - | | | | - | Poll for status | POST-as-GET order | 200 | - | | | | - | Finalize order | POST order's finalize url | 200 | - | | | | - | Poll for status | POST-as-GET order | 200 | - | | | | - | Download | POST-as-GET order's | 200 | - | certificate | certificate url | | - +-------------------+--------------------------------+--------------+ - - - - - - - - - - -|Level|Usage| -|-----|-----| -|Verbose|Verbose is the noisiest level, rarely (if ever) enabled for a production app.| -|Debug|Debug is used for internal system events that are not necessarily observable from the outside, but useful when determining how something happened.| -|Information|Information events describe things happening in the system that correspond to its responsibilities and functions. Generally these are the observable actions the system can perform.| -|Warning|When service is degraded, endangered, or may be behaving outside of its expected parameters, Warning level events are used.| -|Error|When functionality is unavailable or expectations broken, an Error event is used.| -|Fatal|The most critical level, Fatal events demand immediate attention.| \ No newline at end of file diff --git a/src/LetsEncryptConsole/Services/TerminalService.cs b/src/LetsEncryptConsole/Services/TerminalService.cs deleted file mode 100644 index 7607531..0000000 --- a/src/LetsEncryptConsole/Services/TerminalService.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Diagnostics; - -namespace MaksIT.LetsEncryptConsole.Services; - -public interface ITerminalService { - void Exec(string cmd); -} - -public class TerminalService : ITerminalService { - - public void Exec(string cmd) { - var escapedArgs = cmd.Replace("\"", "\\\""); - - var pc = new Process { - StartInfo = new ProcessStartInfo { - RedirectStandardOutput = true, - UseShellExecute = false, - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - FileName = "/bin/bash", - Arguments = $"-c \"{escapedArgs}\"" - } - }; - - pc.Start(); - pc.WaitForExit(); - } -} diff --git a/src/LetsEncryptConsole/appsettings.json b/src/LetsEncryptConsole/appsettings.json deleted file mode 100644 index 1370813..0000000 --- a/src/LetsEncryptConsole/appsettings.json +++ /dev/null @@ -1,150 +0,0 @@ -{ - "Serilog": { - "Using": [ "Serilog.Settings.Configuration", "Serilog.Expressions", "Serilog.Sinks.Console" ], - "MinimumLevel": "Information", - "Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ], - "WriteTo": [ - { - "Name": "Console", - "Args": { - "restrictedToMinimumLevel": "Information", - //"formatter": "Serilog.Formatting.Compact.RenderedCompactJsonFormatter, Serilog.Formatting.Compact" - - "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console", - "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {NewLine}{Exception}" - } - } - ] - }, - "Configuration": { - "Environments": [ - { - "Active": false, - "Name": "StagingV2", - "Url": "https://acme-staging-v02.api.letsencrypt.org/directory", - - "Cache": "staging_cache", - "ACME": { - "Linux": { - "Path": "/var/www/html/acme-challenge", - "Ower": "nginx:nginx", - "ChangeMode": "775" - }, - "Windows": { - "Path": "C:\\inetpub\\www\\acme-challenge" - } - }, - "SSL": { - "Linux": { - "Path": "/var/www/ssl/staging", - "Owner": "nginx:nginx", - "ChangeMode": "775" - }, - "Windows": { - "Path": "C:\\inetpub\\www\\ssl\\staging" - } - }, - "SSH": { - "Active": true, - "Host": "192.168.2.10", - "Port": 22, - "Username": "", - "Password": "" - } - }, - { - "Active": true, - "Name": "ProductionV2", - "Url": "https://acme-v02.api.letsencrypt.org/directory", - - "Cache": "production_cache", - "ACME": { - "Linux": { - "Path": "/var/www/html/acme-challenge", - "Owner": "nginx:nginx", - "ChangeMode": "775" - }, - "Windows": { - "Path": "C:\\inetpub\\www\\acme-challenge" - } - }, - "SSL": { - "Linux": { - "Path": "/var/www/ssl", - "Owner": "nginx:nginx", - "ChangeMode": "775" - }, - "Windows": { - "Path": "C:\\inetpub\\www\\ssl" - } - }, - "SSH": { - "Active": true, - "Host": "192.168.2.10", - "Port": 22, - "Username": "", - "Password": "" - } - } - ], - - "Customers": [ - { - "Id": "9b4c8584-dc83-4388-b45f-2942e34dca9d", - "Active": true, - "Contacts": [ "maksym.sadovnychyy@gmail.com" ], - "Name": "Maksym", - "LastName": "Sadovnychyy", - - "Sites": [ - { - "Active": true, - "Name": "maks-it.com", - "Hosts": [ - "maks-it.com", - "www.maks-it.com", - - "git.maks-it.com", - "www.git.maks-it.com", - - "hcr.maks-it.com", - "www.hcr.maks-it.com", - - "vlt.maks-it.com", - "www.vlt.maks-it.com", - - "obj.maks-it.com", - "www.obj.maks-it.com", - - "s3.maks-it.com", - "www.s3.maks-it.com" - ], - "Challenge": "http-01" - } - ] - }, - { - "Id": "46337ef5-d69b-4332-b6ef-67959dfb3c2c", - "Active": false, - "Contacts": [ - "maksym.sadovnychyy@gmail.com", - "anastasiia.pavlovskaia@gmail.com" - ], - "Name": "Anastasiia", - "LastName": "Pavlovskaia", - - "Sites": [ - { - "Active": true, - "Name": "nastyarey.com", - "Hosts": [ - "nastyarey.com", - "www.nastyarey.com" - ], - "Challenge": "http-01" - } - ] - } - ] - } -} diff --git a/src/LetsEncrypt.Tests/AcmeProblemKindTests.cs b/src/MaksIT.CertsUI.Engine.Tests/AcmeProblemKindTests.cs similarity index 100% rename from src/LetsEncrypt.Tests/AcmeProblemKindTests.cs rename to src/MaksIT.CertsUI.Engine.Tests/AcmeProblemKindTests.cs diff --git a/src/LetsEncrypt.Tests/AcmeRetryAfterParserTests.cs b/src/MaksIT.CertsUI.Engine.Tests/AcmeRetryAfterParserTests.cs similarity index 100% rename from src/LetsEncrypt.Tests/AcmeRetryAfterParserTests.cs rename to src/MaksIT.CertsUI.Engine.Tests/AcmeRetryAfterParserTests.cs diff --git a/src/LetsEncrypt.Tests/ContentTypeTests.cs b/src/MaksIT.CertsUI.Engine.Tests/ContentTypeTests.cs similarity index 100% rename from src/LetsEncrypt.Tests/ContentTypeTests.cs rename to src/MaksIT.CertsUI.Engine.Tests/ContentTypeTests.cs diff --git a/src/LetsEncrypt.Tests/LetsEncrypt.Tests.csproj b/src/MaksIT.CertsUI.Engine.Tests/MaksIT.CertsUI.Engine.Tests.csproj similarity index 100% rename from src/LetsEncrypt.Tests/LetsEncrypt.Tests.csproj rename to src/MaksIT.CertsUI.Engine.Tests/MaksIT.CertsUI.Engine.Tests.csproj diff --git a/src/LetsEncrypt.Tests/RegistrationCacheAcmeCooldownSerializationTests.cs b/src/MaksIT.CertsUI.Engine.Tests/RegistrationCacheAcmeCooldownSerializationTests.cs similarity index 100% rename from src/LetsEncrypt.Tests/RegistrationCacheAcmeCooldownSerializationTests.cs rename to src/MaksIT.CertsUI.Engine.Tests/RegistrationCacheAcmeCooldownSerializationTests.cs diff --git a/src/LetsEncrypt/.vscode/launch.json b/src/MaksIT.CertsUI.Engine/.vscode/launch.json similarity index 100% rename from src/LetsEncrypt/.vscode/launch.json rename to src/MaksIT.CertsUI.Engine/.vscode/launch.json diff --git a/src/LetsEncrypt/.vscode/tasks.json b/src/MaksIT.CertsUI.Engine/.vscode/tasks.json similarity index 100% rename from src/LetsEncrypt/.vscode/tasks.json rename to src/MaksIT.CertsUI.Engine/.vscode/tasks.json diff --git a/src/LetsEncrypt/AcmeProblemKind.cs b/src/MaksIT.CertsUI.Engine/AcmeProblemKind.cs similarity index 100% rename from src/LetsEncrypt/AcmeProblemKind.cs rename to src/MaksIT.CertsUI.Engine/AcmeProblemKind.cs diff --git a/src/LetsEncrypt/AcmeRetryAfterParser.cs b/src/MaksIT.CertsUI.Engine/AcmeRetryAfterParser.cs similarity index 100% rename from src/LetsEncrypt/AcmeRetryAfterParser.cs rename to src/MaksIT.CertsUI.Engine/AcmeRetryAfterParser.cs diff --git a/src/LetsEncrypt/Entities/ChalengeType.cs b/src/MaksIT.CertsUI.Engine/Entities/ChalengeType.cs similarity index 100% rename from src/LetsEncrypt/Entities/ChalengeType.cs rename to src/MaksIT.CertsUI.Engine/Entities/ChalengeType.cs diff --git a/src/LetsEncrypt/Entities/ContentType.cs b/src/MaksIT.CertsUI.Engine/Entities/ContentType.cs similarity index 100% rename from src/LetsEncrypt/Entities/ContentType.cs rename to src/MaksIT.CertsUI.Engine/Entities/ContentType.cs diff --git a/src/LetsEncrypt/Entities/Jws/ACMEJwsHeader.cs b/src/MaksIT.CertsUI.Engine/Entities/Jws/ACMEJwsHeader.cs similarity index 100% rename from src/LetsEncrypt/Entities/Jws/ACMEJwsHeader.cs rename to src/MaksIT.CertsUI.Engine/Entities/Jws/ACMEJwsHeader.cs diff --git a/src/LetsEncrypt/Entities/LetsEncrypt/CachedHostname.cs b/src/MaksIT.CertsUI.Engine/Entities/LetsEncrypt/CachedHostname.cs similarity index 100% rename from src/LetsEncrypt/Entities/LetsEncrypt/CachedHostname.cs rename to src/MaksIT.CertsUI.Engine/Entities/LetsEncrypt/CachedHostname.cs diff --git a/src/LetsEncrypt/Entities/LetsEncrypt/CertificateCache.cs b/src/MaksIT.CertsUI.Engine/Entities/LetsEncrypt/CertificateCache.cs similarity index 100% rename from src/LetsEncrypt/Entities/LetsEncrypt/CertificateCache.cs rename to src/MaksIT.CertsUI.Engine/Entities/LetsEncrypt/CertificateCache.cs diff --git a/src/LetsEncrypt/Entities/LetsEncrypt/RegistrationCache.cs b/src/MaksIT.CertsUI.Engine/Entities/LetsEncrypt/RegistrationCache.cs similarity index 100% rename from src/LetsEncrypt/Entities/LetsEncrypt/RegistrationCache.cs rename to src/MaksIT.CertsUI.Engine/Entities/LetsEncrypt/RegistrationCache.cs diff --git a/src/LetsEncrypt/Entities/LetsEncrypt/RevokeReason.cs b/src/MaksIT.CertsUI.Engine/Entities/LetsEncrypt/RevokeReason.cs similarity index 100% rename from src/LetsEncrypt/Entities/LetsEncrypt/RevokeReason.cs rename to src/MaksIT.CertsUI.Engine/Entities/LetsEncrypt/RevokeReason.cs diff --git a/src/LetsEncrypt/Entities/LetsEncrypt/State.cs b/src/MaksIT.CertsUI.Engine/Entities/LetsEncrypt/State.cs similarity index 100% rename from src/LetsEncrypt/Entities/LetsEncrypt/State.cs rename to src/MaksIT.CertsUI.Engine/Entities/LetsEncrypt/State.cs diff --git a/src/LetsEncrypt/Entities/OrderStatus.cs b/src/MaksIT.CertsUI.Engine/Entities/OrderStatus.cs similarity index 100% rename from src/LetsEncrypt/Entities/OrderStatus.cs rename to src/MaksIT.CertsUI.Engine/Entities/OrderStatus.cs diff --git a/src/LetsEncrypt/Exceptions/LetsEncrytException.cs b/src/MaksIT.CertsUI.Engine/Exceptions/LetsEncrytException.cs similarity index 100% rename from src/LetsEncrypt/Exceptions/LetsEncrytException.cs rename to src/MaksIT.CertsUI.Engine/Exceptions/LetsEncrytException.cs diff --git a/src/LetsEncrypt/Extensions/ServiceCollectionExtensions.cs b/src/MaksIT.CertsUI.Engine/Extensions/ServiceCollectionExtensions.cs similarity index 100% rename from src/LetsEncrypt/Extensions/ServiceCollectionExtensions.cs rename to src/MaksIT.CertsUI.Engine/Extensions/ServiceCollectionExtensions.cs diff --git a/src/LetsEncrypt/LetsEncryptConfiguration.cs b/src/MaksIT.CertsUI.Engine/LetsEncryptConfiguration.cs similarity index 100% rename from src/LetsEncrypt/LetsEncryptConfiguration.cs rename to src/MaksIT.CertsUI.Engine/LetsEncryptConfiguration.cs diff --git a/src/LetsEncrypt/LetsEncrypt.csproj b/src/MaksIT.CertsUI.Engine/MaksIT.CertsUI.Engine.csproj similarity index 100% rename from src/LetsEncrypt/LetsEncrypt.csproj rename to src/MaksIT.CertsUI.Engine/MaksIT.CertsUI.Engine.csproj diff --git a/src/LetsEncrypt/Models/Interfaces/RequestModelWithLocationBase.cs b/src/MaksIT.CertsUI.Engine/Models/Interfaces/RequestModelWithLocationBase.cs similarity index 100% rename from src/LetsEncrypt/Models/Interfaces/RequestModelWithLocationBase.cs rename to src/MaksIT.CertsUI.Engine/Models/Interfaces/RequestModelWithLocationBase.cs diff --git a/src/LetsEncrypt/Models/Requests/FinalizeRequest.cs b/src/MaksIT.CertsUI.Engine/Models/Requests/FinalizeRequest.cs similarity index 100% rename from src/LetsEncrypt/Models/Requests/FinalizeRequest.cs rename to src/MaksIT.CertsUI.Engine/Models/Requests/FinalizeRequest.cs diff --git a/src/LetsEncrypt/Models/Responses/Account.cs b/src/MaksIT.CertsUI.Engine/Models/Responses/Account.cs similarity index 100% rename from src/LetsEncrypt/Models/Responses/Account.cs rename to src/MaksIT.CertsUI.Engine/Models/Responses/Account.cs diff --git a/src/LetsEncrypt/Models/Responses/AcmeDirectory.cs b/src/MaksIT.CertsUI.Engine/Models/Responses/AcmeDirectory.cs similarity index 100% rename from src/LetsEncrypt/Models/Responses/AcmeDirectory.cs rename to src/MaksIT.CertsUI.Engine/Models/Responses/AcmeDirectory.cs diff --git a/src/LetsEncrypt/Models/Responses/AuthorizationChallengeChallenge.cs b/src/MaksIT.CertsUI.Engine/Models/Responses/AuthorizationChallengeChallenge.cs similarity index 100% rename from src/LetsEncrypt/Models/Responses/AuthorizationChallengeChallenge.cs rename to src/MaksIT.CertsUI.Engine/Models/Responses/AuthorizationChallengeChallenge.cs diff --git a/src/LetsEncrypt/Models/Responses/AuthorizationChallengeError.cs b/src/MaksIT.CertsUI.Engine/Models/Responses/AuthorizationChallengeError.cs similarity index 100% rename from src/LetsEncrypt/Models/Responses/AuthorizationChallengeError.cs rename to src/MaksIT.CertsUI.Engine/Models/Responses/AuthorizationChallengeError.cs diff --git a/src/LetsEncrypt/Models/Responses/AuthorizationChallengeResponse.cs b/src/MaksIT.CertsUI.Engine/Models/Responses/AuthorizationChallengeResponse.cs similarity index 100% rename from src/LetsEncrypt/Models/Responses/AuthorizationChallengeResponse.cs rename to src/MaksIT.CertsUI.Engine/Models/Responses/AuthorizationChallengeResponse.cs diff --git a/src/LetsEncrypt/Models/Responses/AuthorizationChallengeValidationRecord.cs b/src/MaksIT.CertsUI.Engine/Models/Responses/AuthorizationChallengeValidationRecord.cs similarity index 100% rename from src/LetsEncrypt/Models/Responses/AuthorizationChallengeValidationRecord.cs rename to src/MaksIT.CertsUI.Engine/Models/Responses/AuthorizationChallengeValidationRecord.cs diff --git a/src/LetsEncrypt/Models/Responses/Order.cs b/src/MaksIT.CertsUI.Engine/Models/Responses/Order.cs similarity index 100% rename from src/LetsEncrypt/Models/Responses/Order.cs rename to src/MaksIT.CertsUI.Engine/Models/Responses/Order.cs diff --git a/src/LetsEncrypt/Models/Responses/Problem.cs b/src/MaksIT.CertsUI.Engine/Models/Responses/Problem.cs similarity index 100% rename from src/LetsEncrypt/Models/Responses/Problem.cs rename to src/MaksIT.CertsUI.Engine/Models/Responses/Problem.cs diff --git a/src/LetsEncrypt/Models/Responses/RevokeRequest.cs b/src/MaksIT.CertsUI.Engine/Models/Responses/RevokeRequest.cs similarity index 100% rename from src/LetsEncrypt/Models/Responses/RevokeRequest.cs rename to src/MaksIT.CertsUI.Engine/Models/Responses/RevokeRequest.cs diff --git a/src/LetsEncrypt/Models/Responses/SendResult.cs b/src/MaksIT.CertsUI.Engine/Models/Responses/SendResult.cs similarity index 100% rename from src/LetsEncrypt/Models/Responses/SendResult.cs rename to src/MaksIT.CertsUI.Engine/Models/Responses/SendResult.cs diff --git a/src/LetsEncrypt/Services/AcmeSessionStore.cs b/src/MaksIT.CertsUI.Engine/Services/AcmeSessionStore.cs similarity index 100% rename from src/LetsEncrypt/Services/AcmeSessionStore.cs rename to src/MaksIT.CertsUI.Engine/Services/AcmeSessionStore.cs diff --git a/src/LetsEncrypt/Services/LetsEncryptService.Helpers.cs b/src/MaksIT.CertsUI.Engine/Services/LetsEncryptService.Helpers.cs similarity index 100% rename from src/LetsEncrypt/Services/LetsEncryptService.Helpers.cs rename to src/MaksIT.CertsUI.Engine/Services/LetsEncryptService.Helpers.cs diff --git a/src/LetsEncrypt/Services/LetsEncryptService.cs b/src/MaksIT.CertsUI.Engine/Services/LetsEncryptService.cs similarity index 100% rename from src/LetsEncrypt/Services/LetsEncryptService.cs rename to src/MaksIT.CertsUI.Engine/Services/LetsEncryptService.cs diff --git a/src/LetsEncrypt/launchSettings.json b/src/MaksIT.CertsUI.Engine/launchSettings.json similarity index 100% rename from src/LetsEncrypt/launchSettings.json rename to src/MaksIT.CertsUI.Engine/launchSettings.json