diff --git a/src/Certify.Core/Management/CertifyManager/CertifyManager.ManagementHub.cs b/src/Certify.Core/Management/CertifyManager/CertifyManager.ManagementHub.cs index 889ff7174..faa7e22b4 100644 --- a/src/Certify.Core/Management/CertifyManager/CertifyManager.ManagementHub.cs +++ b/src/Certify.Core/Management/CertifyManager/CertifyManager.ManagementHub.cs @@ -263,16 +263,47 @@ private async Task _managementServerClient_OnGetCommandRe val = await PerformDeploymentTask(null, managedCertificateIdArg.Value, taskIdArg.Value, isPreviewOnly: false, skipDeferredTasks: false, forceTaskExecution: false); } + else if (arg.CommandType == ManagementHubCommands.GetTargetServiceTypes) + { + val = await GetTargetServiceTypes(); + } + else if (arg.CommandType == ManagementHubCommands.GetTargetServiceItems) + { + var args = JsonSerializer.Deserialize[]>(arg.Value); + var serviceTypeArg = args.FirstOrDefault(a => a.Key == "serviceType"); + + var serverType = MapStandardServerType(serviceTypeArg.Value); + + val = await GetPrimaryWebSites(serverType, ignoreStoppedSites: true); + } + else if (arg.CommandType == ManagementHubCommands.GetTargetServiceItemIdentifiers) + { + var args = JsonSerializer.Deserialize[]>(arg.Value); + var serviceTypeArg = args.FirstOrDefault(a => a.Key == "serviceType"); + var itemArg = args.FirstOrDefault(a => a.Key == "itemId"); + + var serverType = MapStandardServerType(serviceTypeArg.Value); + + val = await GetDomainOptionsFromSite(serverType, itemArg.Value); + } else if (arg.CommandType == ManagementHubCommands.Reconnect) { await _managementServerClient.Disconnect(); } - var result = new InstanceCommandResult { CommandId = arg.CommandId, Value = JsonSerializer.Serialize(val) }; - - result.ObjectValue = val; + return new InstanceCommandResult { CommandId = arg.CommandId, Value = JsonSerializer.Serialize(val), ObjectValue = val }; + } - return result; + private StandardServerTypes MapStandardServerType(string type) + { + if (StandardServerTypes.TryParse(type, out StandardServerTypes standardServerType)) + { + return standardServerType; + } + else + { + return StandardServerTypes.Other; + } } private void ReportManagedItemUpdateToMgmtHub(ManagedCertificate item) diff --git a/src/Certify.Core/Management/CertifyManager/CertifyManager.ServerType.cs b/src/Certify.Core/Management/CertifyManager/CertifyManager.ServerType.cs index 76d770d05..1719b80b8 100644 --- a/src/Certify.Core/Management/CertifyManager/CertifyManager.ServerType.cs +++ b/src/Certify.Core/Management/CertifyManager/CertifyManager.ServerType.cs @@ -9,6 +9,22 @@ namespace Certify.Management { public partial class CertifyManager { + private async Task> GetTargetServiceTypes() + { + var list = new List(); + + // TODO: make dynamic from service + if (await IsServerTypeAvailable(StandardServerTypes.IIS)) + { + list.Add(StandardServerTypes.IIS.ToString()); + }; + + if (await IsServerTypeAvailable(StandardServerTypes.Nginx)) + { + list.Add(StandardServerTypes.Nginx.ToString()); + }; + return list; + } private ITargetWebServer GetTargetServerProvider(StandardServerTypes serverType) { diff --git a/src/Certify.Core/Management/Servers/ServerProviderIIS.cs b/src/Certify.Core/Management/Servers/ServerProviderIIS.cs index b7c45a993..bcb78fc80 100644 --- a/src/Certify.Core/Management/Servers/ServerProviderIIS.cs +++ b/src/Certify.Core/Management/Servers/ServerProviderIIS.cs @@ -54,6 +54,11 @@ public IBindingDeploymentTarget GetDeploymentTarget() public Task IsAvailable() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return Task.FromResult(false); + } + if (!_isIISAvailable) { try diff --git a/src/Certify.Models/Hub/ManagedCertificateSummary.cs b/src/Certify.Models/Hub/ManagedCertificateSummary.cs index 1b6804447..9c5b5b3ea 100644 --- a/src/Certify.Models/Hub/ManagedCertificateSummary.cs +++ b/src/Certify.Models/Hub/ManagedCertificateSummary.cs @@ -11,6 +11,9 @@ public class ManagedCertificateSummary { public string? InstanceId { get; set; } = string.Empty; public string? InstanceTitle { get; set; } = string.Empty; + + public string? OS { get; set; } = string.Empty; + public string? ClientDetails { get; set; } = string.Empty; /// /// Id for this managed item /// diff --git a/src/Certify.Models/Hub/ManagementHubMessages.cs b/src/Certify.Models/Hub/ManagementHubMessages.cs index c5aa01ab3..14d3e6149 100644 --- a/src/Certify.Models/Hub/ManagementHubMessages.cs +++ b/src/Certify.Models/Hub/ManagementHubMessages.cs @@ -43,6 +43,10 @@ public class ManagementHubCommands public const string GetDeploymentProviders = "GetDeploymentProviders"; public const string ExecuteDeploymentTask = "ExecuteDeploymentTask"; + public const string GetTargetServiceTypes = "GetTargetServiceTypes"; + public const string GetTargetServiceItems = "GetTargetServiceItems"; + public const string GetTargetServiceItemIdentifiers = "GetTargetServiceItemIdentifiers"; + public const string Reconnect = "Reconnect"; /// diff --git a/src/Certify.Server/Certify.Server.Api.Public.Client/Certify.API.Public.cs b/src/Certify.Server/Certify.Server.Api.Public.Client/Certify.API.Public.cs index de0c5abd1..2b402d629 100644 --- a/src/Certify.Server/Certify.Server.Api.Public.Client/Certify.API.Public.cs +++ b/src/Certify.Server/Certify.Server.Api.Public.Client/Certify.API.Public.cs @@ -1,6 +1,6 @@ //---------------------- // -// Generated using the NSwag toolchain v14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// Generated using the NSwag toolchain v14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) // //---------------------- @@ -30,7 +30,7 @@ namespace Certify.API.Public { using System = global::System; - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Client { #pragma warning disable 8618 @@ -4475,25 +4475,25 @@ public virtual async System.Threading.Tasks.Task PerformExp } /// - /// Get list of known service items (e.g. websites etc) we may want to then check for domains etc to add to cert. May return many items (e.g. thousands of sites) + /// Get Service Types present on instance (IIS, nginx etc) [Generated by Certify.SourceGenerators] /// /// OK /// A server side error occurred. - public virtual System.Threading.Tasks.Task> GetTargetServiceItemsAsync(string serverType) + public virtual System.Threading.Tasks.Task> GetTargetServiceTypesAsync(string instanceId) { - return GetTargetServiceItemsAsync(serverType, System.Threading.CancellationToken.None); + return GetTargetServiceTypesAsync(instanceId, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Get list of known service items (e.g. websites etc) we may want to then check for domains etc to add to cert. May return many items (e.g. thousands of sites) + /// Get Service Types present on instance (IIS, nginx etc) [Generated by Certify.SourceGenerators] /// /// OK /// A server side error occurred. - public virtual async System.Threading.Tasks.Task> GetTargetServiceItemsAsync(string serverType, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task> GetTargetServiceTypesAsync(string instanceId, System.Threading.CancellationToken cancellationToken) { - if (serverType == null) - throw new System.ArgumentNullException("serverType"); + if (instanceId == null) + throw new System.ArgumentNullException("instanceId"); var client_ = _httpClient; var disposeClient_ = false; @@ -4506,10 +4506,10 @@ public virtual async System.Threading.Tasks.Task PerformExp var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "internal/v1/target/{serverType}/items" + // Operation Path: "internal/v1/target/{instanceId}/types" urlBuilder_.Append("internal/v1/target/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(serverType, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/items"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(instanceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/types"); PrepareRequest(client_, request_, urlBuilder_); @@ -4536,7 +4536,7 @@ public virtual async System.Threading.Tasks.Task PerformExp var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -4564,28 +4564,28 @@ public virtual async System.Threading.Tasks.Task PerformExp } /// - /// Return details of single target server item (e.g. 1 site) + /// Get Service items (sites) present on instance (IIS, nginx etc). [Generated by Certify.SourceGenerators] /// /// OK /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetTargetServiceItemAsync(string serverType, string itemId) + public virtual System.Threading.Tasks.Task> GetTargetServiceItemsAsync(string instanceId, string serviceType) { - return GetTargetServiceItemAsync(serverType, itemId, System.Threading.CancellationToken.None); + return GetTargetServiceItemsAsync(instanceId, serviceType, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Return details of single target server item (e.g. 1 site) + /// Get Service items (sites) present on instance (IIS, nginx etc). [Generated by Certify.SourceGenerators] /// /// OK /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetTargetServiceItemAsync(string serverType, string itemId, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task> GetTargetServiceItemsAsync(string instanceId, string serviceType, System.Threading.CancellationToken cancellationToken) { - if (serverType == null) - throw new System.ArgumentNullException("serverType"); + if (instanceId == null) + throw new System.ArgumentNullException("instanceId"); - if (itemId == null) - throw new System.ArgumentNullException("itemId"); + if (serviceType == null) + throw new System.ArgumentNullException("serviceType"); var client_ = _httpClient; var disposeClient_ = false; @@ -4598,11 +4598,12 @@ public virtual async System.Threading.Tasks.Task GetTargetServiceItemA var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "internal/v1/target/{serverType}/item/{itemId}" + // Operation Path: "internal/v1/target/{instanceId}/{serviceType}/items" urlBuilder_.Append("internal/v1/target/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(serverType, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/item/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(itemId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(instanceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(serviceType, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/items"); PrepareRequest(client_, request_, urlBuilder_); @@ -4629,7 +4630,7 @@ public virtual async System.Threading.Tasks.Task GetTargetServiceItemA var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -4657,25 +4658,28 @@ public virtual async System.Threading.Tasks.Task GetTargetServiceItemA } /// - /// Get list of known service items (e.g. websites etc) we may want to then check for domains etc to add to cert + /// Get Service item identifiers (domains on a website etc) present on instance (IIS, nginx etc) [Generated by Certify.SourceGenerators] /// /// OK /// A server side error occurred. - public virtual System.Threading.Tasks.Task> GetTargetServiceItemIdentifiersAsync(string serverType, string itemId) + public virtual System.Threading.Tasks.Task> GetTargetServiceItemIdentifiersAsync(string instanceId, string serviceType, string itemId) { - return GetTargetServiceItemIdentifiersAsync(serverType, itemId, System.Threading.CancellationToken.None); + return GetTargetServiceItemIdentifiersAsync(instanceId, serviceType, itemId, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Get list of known service items (e.g. websites etc) we may want to then check for domains etc to add to cert + /// Get Service item identifiers (domains on a website etc) present on instance (IIS, nginx etc) [Generated by Certify.SourceGenerators] /// /// OK /// A server side error occurred. - public virtual async System.Threading.Tasks.Task> GetTargetServiceItemIdentifiersAsync(string serverType, string itemId, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task> GetTargetServiceItemIdentifiersAsync(string instanceId, string serviceType, string itemId, System.Threading.CancellationToken cancellationToken) { - if (serverType == null) - throw new System.ArgumentNullException("serverType"); + if (instanceId == null) + throw new System.ArgumentNullException("instanceId"); + + if (serviceType == null) + throw new System.ArgumentNullException("serviceType"); if (itemId == null) throw new System.ArgumentNullException("itemId"); @@ -4691,9 +4695,11 @@ public virtual async System.Threading.Tasks.Task GetTargetServiceItemA var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "internal/v1/target/{serverType}/item/{itemId}/identifiers" + // Operation Path: "internal/v1/target/{instanceId}/{serviceType}/item/{itemId}/identifiers" urlBuilder_.Append("internal/v1/target/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(serverType, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(instanceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(serviceType, System.Globalization.CultureInfo.InvariantCulture))); urlBuilder_.Append("/item/"); urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(itemId, System.Globalization.CultureInfo.InvariantCulture))); urlBuilder_.Append("/identifiers"); @@ -4750,90 +4756,6 @@ public virtual async System.Threading.Tasks.Task GetTargetServiceItemA } } - /// - /// Get list of target services this server supports (e.g. IIS etc) - /// - /// OK - /// A server side error occurred. - public virtual System.Threading.Tasks.Task> GetTargetServiceTypesAsync() - { - return GetTargetServiceTypesAsync(System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get list of target services this server supports (e.g. IIS etc) - /// - /// OK - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task> GetTargetServiceTypesAsync(System.Threading.CancellationToken cancellationToken) - { - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "internal/v1/target/services" - urlBuilder_.Append("internal/v1/target/services"); - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - /// /// get current challenge info for a given type/key /// @@ -5041,7 +4963,7 @@ private string ConvertToString(object value, System.Globalization.CultureInfo cu - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class FileResponse : System.IDisposable { private System.IDisposable _client; @@ -5078,7 +5000,7 @@ public void Dispose() } - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ApiException : System.Exception { public int StatusCode { get; private set; } @@ -5101,7 +5023,7 @@ public override string ToString() } } - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ApiException : ApiException { public TResult Result { get; private set; } diff --git a/src/Certify.Server/Certify.Server.Api.Public.Client/nswag.json b/src/Certify.Server/Certify.Server.Api.Public.Client/nswag.json index 12e2953f1..9c857d408 100644 --- a/src/Certify.Server/Certify.Server.Api.Public.Client/nswag.json +++ b/src/Certify.Server/Certify.Server.Api.Public.Client/nswag.json @@ -1,5 +1,5 @@ { - "runtime": "Net80", + "runtime": "Net90", "defaultVariables": null, "documentGenerator": { "fromDocument": { diff --git a/src/Certify.Server/Certify.Server.Api.Public/Controllers/internal/HubController.cs b/src/Certify.Server/Certify.Server.Api.Public/Controllers/internal/HubController.cs index b969a09e3..a3cdefc3c 100644 --- a/src/Certify.Server/Certify.Server.Api.Public/Controllers/internal/HubController.cs +++ b/src/Certify.Server/Certify.Server.Api.Public/Controllers/internal/HubController.cs @@ -64,20 +64,28 @@ public async Task GetHubManagedItems(string? instanceId, string? list.AddRange( remote.Items .Where(i => string.IsNullOrWhiteSpace(keyword) || (!string.IsNullOrWhiteSpace(keyword) && i.Name?.Contains(keyword) == true)) - .Select(i => new ManagedCertificateSummary + .Select(i => { - InstanceId = remote.InstanceId, - InstanceTitle = instances.FirstOrDefault(i => i.InstanceId == remote.InstanceId)?.Title, - Id = i.Id ?? "", - Title = $"{i.Name}" ?? "", - PrimaryIdentifier = i.GetCertificateIdentifiers().FirstOrDefault(p => p.Value == i.RequestConfig.PrimaryDomain) ?? i.GetCertificateIdentifiers().FirstOrDefault(), - Identifiers = i.GetCertificateIdentifiers(), - DateRenewed = i.DateRenewed, - DateExpiry = i.DateExpiry, - Comments = i.Comments ?? "", - Status = i.LastRenewalStatus?.ToString() ?? "", - HasCertificate = !string.IsNullOrEmpty(i.CertificatePath) - }) + var instance = instances.FirstOrDefault(i => i.InstanceId == remote.InstanceId); + + return new ManagedCertificateSummary + { + InstanceId = remote.InstanceId, + InstanceTitle = instance?.Title, + Id = i.Id ?? "", + Title = $"{i.Name}" ?? "", + OS = instance?.OS, + ClientDetails = instance?.ClientName, + PrimaryIdentifier = i.GetCertificateIdentifiers().FirstOrDefault(p => p.Value == i.RequestConfig.PrimaryDomain) ?? i.GetCertificateIdentifiers().FirstOrDefault(), + Identifiers = i.GetCertificateIdentifiers(), + DateRenewed = i.DateRenewed, + DateExpiry = i.DateExpiry, + Comments = i.Comments ?? "", + Status = i.LastRenewalStatus?.ToString() ?? "", + HasCertificate = !string.IsNullOrEmpty(i.CertificatePath) + }; + } + ) ); } } diff --git a/src/Certify.Server/Certify.Server.Api.Public/Controllers/internal/TargetController.cs b/src/Certify.Server/Certify.Server.Api.Public/Controllers/internal/TargetController.cs index 3f1d8148e..edfc943b8 100644 --- a/src/Certify.Server/Certify.Server.Api.Public/Controllers/internal/TargetController.cs +++ b/src/Certify.Server/Certify.Server.Api.Public/Controllers/internal/TargetController.cs @@ -1,5 +1,6 @@ using Certify.Client; using Certify.Models; +using Certify.Server.Api.Public.Services; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -18,42 +19,18 @@ public partial class TargetController : ApiControllerBase private readonly ICertifyInternalApiClient _client; + private readonly ManagementAPI _mgmtAPI; + /// /// Constructor /// /// /// - public TargetController(ILogger logger, ICertifyInternalApiClient client) + public TargetController(ILogger logger, ICertifyInternalApiClient client, ManagementAPI mgmtAPI) { _logger = logger; _client = client; - } - - /// - /// Get list of known service items (e.g. websites etc) we may want to then check for domains etc to add to cert. May return many items (e.g. thousands of sites) - /// - /// - [HttpGet] - [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] - [Route("{serverType}/items")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List))] - - public async Task GetTargetServiceItems(string serverType) - { - var knownServerType = GetServerTypeFromString(serverType); - if (knownServerType == null) - { - return new NotFoundResult(); - } - - var targetList = new List(); - - if (await _client.IsServerAvailable((StandardServerTypes)knownServerType)) - { - targetList.AddRange(await _client.GetServerSiteList((StandardServerTypes)knownServerType)); - } - - return new OkObjectResult(targetList); + _mgmtAPI = mgmtAPI; } private static StandardServerTypes? GetServerTypeFromString(string value) @@ -67,90 +44,5 @@ public async Task GetTargetServiceItems(string serverType) return null; } } - - /// - /// Return details of single target server item (e.g. 1 site) - /// - /// - /// - /// - [HttpGet] - [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] - [Route("{serverType}/item/{itemId}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(SiteInfo))] - - public async Task GetTargetServiceItem(string serverType, string itemId) - { - if (string.IsNullOrEmpty(itemId)) - { - return new BadRequestResult(); - } - - var knownServerType = GetServerTypeFromString(serverType); - if (knownServerType == null) - { - return new NotFoundResult(); - } - - var results = await _client.GetServerSiteList((StandardServerTypes)knownServerType, itemId); - - if (results.Count == 0) - { - return new NotFoundResult(); - } - else - { - return new OkObjectResult(results.First()); - } - } - - /// - /// Get list of known service items (e.g. websites etc) we may want to then check for domains etc to add to cert - /// - /// - [HttpGet] - [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] - [Route("{serverType}/item/{itemId}/identifiers")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List))] - - public async Task GetTargetServiceItemIdentifiers(string serverType, string itemId) - { - var targetList = new List(); - - var knownServerType = GetServerTypeFromString(serverType); - if (knownServerType == null) - { - return new NotFoundResult(); - } - - targetList.AddRange(await _client.GetServerSiteDomains((StandardServerTypes)knownServerType, itemId)); - - return new OkObjectResult(targetList); - - } - /// - /// Get list of target services this server supports (e.g. IIS etc) - /// - /// - [HttpGet] - [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] - [Route("services")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string[]))] - public async Task GetTargetServiceTypes() - { - var list = new List(); - - // TODO: make dynamic from service - if (await _client.IsServerAvailable(StandardServerTypes.IIS)) - { - list.Add(StandardServerTypes.IIS.ToString()); - }; - - if (await _client.IsServerAvailable(StandardServerTypes.Nginx)) - { - list.Add(StandardServerTypes.Nginx.ToString()); - }; - return new OkObjectResult(list); - } } } diff --git a/src/Certify.SourceGenerators/ApiMethods.cs b/src/Certify.SourceGenerators/ApiMethods.cs index bfe920bd9..6fac3c8cc 100644 --- a/src/Certify.SourceGenerators/ApiMethods.cs +++ b/src/Certify.SourceGenerators/ApiMethods.cs @@ -309,6 +309,48 @@ public static List GetApiDefinitions() { "instanceId", "string" } } }, + new GeneratedAPI { + OperationName = "GetTargetServiceTypes", + OperationMethod = HttpGet, + Comment = "Get Service Types present on instance (IIS, nginx etc)", + UseManagementAPI = true, + ManagementHubCommandType = Models.Hub.ManagementHubCommands.GetTargetServiceTypes, + PublicAPIController = "Target", + PublicAPIRoute = "{instanceId}/types", + ReturnType = "ICollection", + Params =new Dictionary{ + { "instanceId", "string" } + } + }, + new GeneratedAPI { + OperationName = "GetTargetServiceItems", + OperationMethod = HttpGet, + Comment = "Get Service items (sites) present on instance (IIS, nginx etc).", + UseManagementAPI = true, + ManagementHubCommandType = Models.Hub.ManagementHubCommands.GetTargetServiceItems, + PublicAPIController = "Target", + PublicAPIRoute = "{instanceId}/{serviceType}/items", + ReturnType = "ICollection", + Params =new Dictionary{ + { "instanceId", "string" }, + { "serviceType", "string" } + } + }, + new GeneratedAPI { + OperationName = "GetTargetServiceItemIdentifiers", + OperationMethod = HttpGet, + Comment = "Get Service item identifiers (domains on a website etc) present on instance (IIS, nginx etc)", + UseManagementAPI = true, + ManagementHubCommandType = Models.Hub.ManagementHubCommands.GetTargetServiceItemIdentifiers, + PublicAPIController = "Target", + PublicAPIRoute = "{instanceId}/{serviceType}/item/{itemId}/identifiers", + ReturnType = "ICollection", + Params =new Dictionary{ + { "instanceId", "string" }, + { "serviceType", "string" }, + { "itemId", "string" } + } + }, new GeneratedAPI { OperationName = "GetChallengeProviders", OperationMethod = HttpGet, diff --git a/src/Certify.SourceGenerators/Certify.SourceGenerators.csproj b/src/Certify.SourceGenerators/Certify.SourceGenerators.csproj index 6c8720d2d..c8eaa676e 100644 --- a/src/Certify.SourceGenerators/Certify.SourceGenerators.csproj +++ b/src/Certify.SourceGenerators/Certify.SourceGenerators.csproj @@ -17,4 +17,7 @@ + + + diff --git a/src/Certify.SourceGenerators/PublicAPISourceGenerator.cs b/src/Certify.SourceGenerators/PublicAPISourceGenerator.cs index f330c2308..59f2ea499 100644 --- a/src/Certify.SourceGenerators/PublicAPISourceGenerator.cs +++ b/src/Certify.SourceGenerators/PublicAPISourceGenerator.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Linq; using System.Text; +using System.Threading.Tasks; using Certify.SourceGenerators; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; @@ -17,6 +18,7 @@ public class GeneratedAPI public string PublicAPIRoute { get; set; } = string.Empty; public bool UseManagementAPI { get; set; } = false; + public string ManagementHubCommandType { get; set; } = string.Empty; public string ServiceAPIRoute { get; set; } = string.Empty; public string ReturnType { get; set; } = string.Empty; public Dictionary Params { get; set; } = new Dictionary(); @@ -42,9 +44,9 @@ public void Execute(GeneratorExecutionContext context) var apiParamCall = paramSet.Any() ? string.Join(", ", paramSet.Select(p => $"{p.Key}")) : ""; var apiParamCallWithoutAuthContext = config.Params.Any() ? string.Join(", ", config.Params.Select(p => $"{p.Key}")) : ""; - if (context.Compilation.AssemblyName.EndsWith("Api.Public") && config.PublicAPIController!=null) + if (context.Compilation.AssemblyName.EndsWith("Api.Public") && config.PublicAPIController != null) { - ImplementPublicAPI(context, config, apiParamDeclWithoutAuthContext, apiParamCall); + ImplementPublicAPI(context, config, apiParamDeclWithoutAuthContext, apiParamDecl, apiParamCall); } if (context.Compilation.AssemblyName.EndsWith("Certify.UI.Blazor")) @@ -63,39 +65,40 @@ public void Execute(GeneratorExecutionContext context) private static void ImplementAppModel(GeneratorExecutionContext context, GeneratedAPI config, string apiParamDeclWithoutAuthContext, string apiParamCallWithoutAuthContext) { context.AddSource($"AppModel.{config.OperationName}.g.cs", SourceText.From($@" -using System.Collections.Generic; -using System.Threading.Tasks; -using Certify.Models; -using Certify.Models.Providers; -using Certify.Models.Hub; - - namespace Certify.UI.Client.Core - {{ - public partial class AppModel - {{ - public async Task<{config.ReturnType}> {config.OperationName}({apiParamDeclWithoutAuthContext}) - {{ - return await _api.{config.OperationName}Async({apiParamCallWithoutAuthContext}); - }} - }} - }}", Encoding.UTF8)); + using System.Collections.Generic; + using System.Threading.Tasks; + using Certify.Models; + using Certify.Models.Providers; + using Certify.Models.Hub; + + namespace Certify.UI.Client.Core + {{ + public partial class AppModel + {{ + public async Task<{config.ReturnType}> {config.OperationName}({apiParamDeclWithoutAuthContext}) + {{ + return await _api.{config.OperationName}Async({apiParamCallWithoutAuthContext}); + }} + }} + }} + ", Encoding.UTF8)); } - private static void ImplementPublicAPI(GeneratorExecutionContext context, GeneratedAPI config, string apiParamDeclWithoutAuthContext, string apiParamCall) + private static void ImplementPublicAPI(GeneratorExecutionContext context, GeneratedAPI config, string apiParamDeclWithoutAuthContext, string apiParamDecl, string apiParamCall) { context.AddSource($"{config.PublicAPIController}Controller.{config.OperationName}.g.cs", SourceText.From($@" -using Certify.Client; -using Certify.Server.Api.Public.Controllers; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Authorization; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; -using Certify.Models; -using Certify.Models.Hub; + using Certify.Client; + using Certify.Server.Api.Public.Controllers; + using Microsoft.AspNetCore.Authentication.JwtBearer; + using Microsoft.AspNetCore.Authorization; + using System.Collections.Generic; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Http; + using Microsoft.AspNetCore.Mvc; + using Microsoft.Extensions.Logging; + using Certify.Models; + using Certify.Models.Hub; namespace Certify.Server.Api.Public.Controllers @@ -116,25 +119,61 @@ public partial class {config.PublicAPIController}Controller return new OkObjectResult(result); }} }} - }}", Encoding.UTF8)); + }} + ", Encoding.UTF8)); + + // Management API service + + if (!string.IsNullOrEmpty(config.ManagementHubCommandType)) + { + var src = $@" + + using Certify.Client; + using Certify.Models.Hub; + using Certify.Models; + using Certify.Models.Config; + using Certify.Models.Providers; + using Certify.Models.Reporting; + using Microsoft.AspNetCore.SignalR; + namespace Certify.Server.Api.Public.Services + {{ + public partial class ManagementAPI + {{ + /// + /// {config.Comment} [Generated by Certify.SourceGenerators] + /// + /// + internal async Task<{config.ReturnType}> {config.OperationName}({apiParamDecl}) + {{ + var args = new KeyValuePair[] {{ + {string.Join(",", config.Params.Select(s => $"new (\"{s.Key}\", {s.Key})").ToArray())} + }}; + + return await PerformInstanceCommandTaskWithResult<{config.ReturnType}>(instanceId, args, ""{config.ManagementHubCommandType}"") ?? []; + }} + }} + }} + "; + context.AddSource($"ManagementAPI.{config.OperationName}.g.cs", SourceText.From(src, Encoding.UTF8)); + } } private static void ImplementInternalAPIClient(GeneratorExecutionContext context, GeneratedAPI config, string apiParamDecl, string apiParamCall) { var template = @" -using Certify.Models; -using Certify.Models.Config.Migration; -using Certify.Models.Providers; -using Certify.Models.Hub; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Certify.Client -{ - MethodTemplate -} -"; + using Certify.Models; + using Certify.Models.Config.Migration; + using Certify.Models.Providers; + using Certify.Models.Hub; + using System.Collections.Generic; + using System.Threading.Tasks; + + namespace Certify.Client + { + MethodTemplate + } + "; if (config.OperationMethod == "HttpGet") { @@ -192,7 +231,6 @@ public partial interface ICertifyInternalApiClient }} - public partial class CertifyApiClient {{ /// @@ -204,7 +242,6 @@ public partial class CertifyApiClient var result = await PostAsync($""{postAPIRoute}"", {postApiCall}); return JsonToObject<{config.ReturnType}>(await result.Content.ReadAsStringAsync()); }} - }} "), Encoding.UTF8)); } @@ -220,10 +257,8 @@ public partial interface ICertifyInternalApiClient /// /// Task<{config.ReturnType}> {config.OperationName}({apiParamDecl}); - }} - public partial class CertifyApiClient {{ /// @@ -232,14 +267,10 @@ public partial class CertifyApiClient /// public async Task<{config.ReturnType}> {config.OperationName}({apiParamDecl}) {{ - var route = $""{config.ServiceAPIRoute}""; - var result = await DeleteAsync(route, authContext); return JsonToObject<{config.ReturnType}>(await result.Content.ReadAsStringAsync()); - }} - }} "), Encoding.UTF8)); }