mirror of
https://github.com/MAKS-IT-COM/maksit-certs-ui.git
synced 2025-12-31 04:00:03 +01:00
(refactor): cert revokation and renew complete
This commit is contained in:
parent
1e068877e0
commit
619348607e
@ -25,7 +25,7 @@ const GetApiRoute = (route: ApiRoutes, ...args: string[]): string => {
|
|||||||
args.forEach((arg) => {
|
args.forEach((arg) => {
|
||||||
result = result.replace(/{.*?}/, arg)
|
result = result.replace(/{.*?}/, arg)
|
||||||
})
|
})
|
||||||
return `http://localhost:5000/${result}`
|
return `http://localhost:8080/${result}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export { GetApiRoute, ApiRoutes }
|
export { GetApiRoute, ApiRoutes }
|
||||||
|
|||||||
@ -21,7 +21,9 @@ Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-co
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Agent", "Agent\Agent.csproj", "{871BDED3-C6AE-437D-9B45-3AA3F184D002}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Agent", "Agent\Agent.csproj", "{871BDED3-C6AE-437D-9B45-3AA3F184D002}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Models", "Models\Models.csproj", "{6814169B-D4D0-40B2-9FA9-89997DD44C30}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Models", "Models\Models.csproj", "{6814169B-D4D0-40B2-9FA9-89997DD44C30}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReverseProxy", "ReverseProxy\ReverseProxy.csproj", "{BE051147-7AB7-4358-9C24-5CB40FAFF4FC}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -65,6 +67,10 @@ Global
|
|||||||
{6814169B-D4D0-40B2-9FA9-89997DD44C30}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{6814169B-D4D0-40B2-9FA9-89997DD44C30}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{6814169B-D4D0-40B2-9FA9-89997DD44C30}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{6814169B-D4D0-40B2-9FA9-89997DD44C30}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{6814169B-D4D0-40B2-9FA9-89997DD44C30}.Release|Any CPU.Build.0 = Release|Any CPU
|
{6814169B-D4D0-40B2-9FA9-89997DD44C30}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BE051147-7AB7-4358-9C24-5CB40FAFF4FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BE051147-7AB7-4358-9C24-5CB40FAFF4FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BE051147-7AB7-4358-9C24-5CB40FAFF4FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BE051147-7AB7-4358-9C24-5CB40FAFF4FC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@ -22,9 +22,6 @@ using MaksIT.LetsEncrypt.Models.Interfaces;
|
|||||||
using MaksIT.LetsEncrypt.Models.Requests;
|
using MaksIT.LetsEncrypt.Models.Requests;
|
||||||
using MaksIT.LetsEncrypt.Entities.Jws;
|
using MaksIT.LetsEncrypt.Entities.Jws;
|
||||||
using MaksIT.LetsEncrypt.Entities.LetsEncrypt;
|
using MaksIT.LetsEncrypt.Entities.LetsEncrypt;
|
||||||
using System.Net.Mime;
|
|
||||||
using System;
|
|
||||||
using System.Security.Principal;
|
|
||||||
|
|
||||||
namespace MaksIT.LetsEncrypt.Services;
|
namespace MaksIT.LetsEncrypt.Services;
|
||||||
|
|
||||||
@ -141,8 +138,10 @@ public class LetsEncryptService : ILetsEncryptService {
|
|||||||
|
|
||||||
await HandleNonceAsync(sessionId, state.Directory.NewAccount, state);
|
await HandleNonceAsync(sessionId, state.Directory.NewAccount, state);
|
||||||
|
|
||||||
var jwsHeader = CreateJwsHeader(state.Directory.NewAccount, state.Nonce);
|
var json = EncodeMessage(false, letsEncryptOrder, state, new JwsHeader {
|
||||||
var json = EncodeMessage(false, letsEncryptOrder, state, jwsHeader);
|
Url = state.Directory.NewAccount,
|
||||||
|
Nonce = state.Nonce
|
||||||
|
});
|
||||||
PrepareRequestContent(request, json, HttpMethod.Post);
|
PrepareRequestContent(request, json, HttpMethod.Post);
|
||||||
|
|
||||||
var response = await _httpClient.SendAsync(request);
|
var response = await _httpClient.SendAsync(request);
|
||||||
@ -232,9 +231,11 @@ public class LetsEncryptService : ILetsEncryptService {
|
|||||||
|
|
||||||
var request = new HttpRequestMessage(HttpMethod.Post, state.Directory.NewOrder);
|
var request = new HttpRequestMessage(HttpMethod.Post, state.Directory.NewOrder);
|
||||||
await HandleNonceAsync(sessionId, state.Directory.NewOrder, state);
|
await HandleNonceAsync(sessionId, state.Directory.NewOrder, state);
|
||||||
|
|
||||||
var jwsHeader = CreateJwsHeader(state.Directory.NewOrder, state.Nonce);
|
var json = EncodeMessage(false, letsEncryptOrder, state, new JwsHeader {
|
||||||
var json = EncodeMessage(false, letsEncryptOrder, state, jwsHeader);
|
Url = state.Directory.NewOrder,
|
||||||
|
Nonce = state.Nonce
|
||||||
|
});
|
||||||
PrepareRequestContent(request, json, HttpMethod.Post);
|
PrepareRequestContent(request, json, HttpMethod.Post);
|
||||||
|
|
||||||
var response = await _httpClient.SendAsync(request);
|
var response = await _httpClient.SendAsync(request);
|
||||||
@ -261,9 +262,10 @@ public class LetsEncryptService : ILetsEncryptService {
|
|||||||
request = new HttpRequestMessage(HttpMethod.Post, item);
|
request = new HttpRequestMessage(HttpMethod.Post, item);
|
||||||
await HandleNonceAsync(sessionId, item, state);
|
await HandleNonceAsync(sessionId, item, state);
|
||||||
|
|
||||||
|
json = EncodeMessage(true, null, state, new JwsHeader {
|
||||||
jwsHeader = CreateJwsHeader(item, state.Nonce);
|
Url = item,
|
||||||
json = EncodeMessage(true, null, state, jwsHeader);
|
Nonce = state.Nonce
|
||||||
|
});
|
||||||
PrepareRequestContent(request, json, HttpMethod.Post);
|
PrepareRequestContent(request, json, HttpMethod.Post);
|
||||||
|
|
||||||
|
|
||||||
@ -349,8 +351,10 @@ public class LetsEncryptService : ILetsEncryptService {
|
|||||||
var request = new HttpRequestMessage(HttpMethod.Post, challenge.Url);
|
var request = new HttpRequestMessage(HttpMethod.Post, challenge.Url);
|
||||||
await HandleNonceAsync(sessionId, challenge.Url, state);
|
await HandleNonceAsync(sessionId, challenge.Url, state);
|
||||||
|
|
||||||
var jwsHeader = CreateJwsHeader(challenge.Url, state.Nonce);
|
var json = EncodeMessage(false, "{}", state, new JwsHeader {
|
||||||
var json = EncodeMessage(false, "{}", state, jwsHeader);
|
Url = challenge.Url,
|
||||||
|
Nonce = state.Nonce
|
||||||
|
});
|
||||||
PrepareRequestContent(request, json, HttpMethod.Post);
|
PrepareRequestContent(request, json, HttpMethod.Post);
|
||||||
|
|
||||||
var response = await _httpClient.SendAsync(request);
|
var response = await _httpClient.SendAsync(request);
|
||||||
@ -406,9 +410,11 @@ public class LetsEncryptService : ILetsEncryptService {
|
|||||||
|
|
||||||
var request = new HttpRequestMessage(HttpMethod.Post, state.Directory.NewOrder);
|
var request = new HttpRequestMessage(HttpMethod.Post, state.Directory.NewOrder);
|
||||||
await HandleNonceAsync(sessionId, state.Directory.NewOrder, state);
|
await HandleNonceAsync(sessionId, state.Directory.NewOrder, state);
|
||||||
|
|
||||||
var jwsHeader = CreateJwsHeader(state.Directory.NewOrder, state.Nonce);
|
var json = EncodeMessage(false, letsEncryptOrder, state, new JwsHeader {
|
||||||
var json = EncodeMessage(false, letsEncryptOrder, state, jwsHeader);
|
Url = state.Directory.NewOrder,
|
||||||
|
Nonce = state.Nonce
|
||||||
|
});
|
||||||
PrepareRequestContent(request, json, HttpMethod.Post);
|
PrepareRequestContent(request, json, HttpMethod.Post);
|
||||||
|
|
||||||
var response = await _httpClient.SendAsync(request);
|
var response = await _httpClient.SendAsync(request);
|
||||||
@ -470,13 +476,12 @@ public class LetsEncryptService : ILetsEncryptService {
|
|||||||
var request = new HttpRequestMessage(HttpMethod.Post, state.CurrentOrder.Finalize);
|
var request = new HttpRequestMessage(HttpMethod.Post, state.CurrentOrder.Finalize);
|
||||||
await HandleNonceAsync(sessionId, state.CurrentOrder.Finalize, state);
|
await HandleNonceAsync(sessionId, state.CurrentOrder.Finalize, state);
|
||||||
|
|
||||||
|
var json = EncodeMessage(false, letsEncryptOrder, state, new JwsHeader {
|
||||||
var jwsHeader = CreateJwsHeader(state.CurrentOrder.Finalize, state.Nonce);
|
Url = state.CurrentOrder.Finalize,
|
||||||
var json = EncodeMessage(false, letsEncryptOrder, state, jwsHeader);
|
Nonce = state.Nonce
|
||||||
|
});
|
||||||
PrepareRequestContent(request, json, HttpMethod.Post);
|
PrepareRequestContent(request, json, HttpMethod.Post);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var response = await _httpClient.SendAsync(request);
|
var response = await _httpClient.SendAsync(request);
|
||||||
UpdateStateNonceIfNeededAsync(response, state, HttpMethod.Post);
|
UpdateStateNonceIfNeededAsync(response, state, HttpMethod.Post);
|
||||||
|
|
||||||
@ -492,13 +497,12 @@ public class LetsEncryptService : ILetsEncryptService {
|
|||||||
request = new HttpRequestMessage(HttpMethod.Post, state.CurrentOrder.Location);
|
request = new HttpRequestMessage(HttpMethod.Post, state.CurrentOrder.Location);
|
||||||
await HandleNonceAsync(sessionId, state.CurrentOrder.Location, state);
|
await HandleNonceAsync(sessionId, state.CurrentOrder.Location, state);
|
||||||
|
|
||||||
|
json = EncodeMessage(true, null, state, new JwsHeader {
|
||||||
jwsHeader = CreateJwsHeader(state.CurrentOrder.Location, state.Nonce);
|
Url = state.CurrentOrder.Location,
|
||||||
json = EncodeMessage(true, null, state, jwsHeader);
|
Nonce = state.Nonce
|
||||||
|
});
|
||||||
PrepareRequestContent(request, json, HttpMethod.Post);
|
PrepareRequestContent(request, json, HttpMethod.Post);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
response = await _httpClient.SendAsync(request);
|
response = await _httpClient.SendAsync(request);
|
||||||
UpdateStateNonceIfNeededAsync(response, state, HttpMethod.Post);
|
UpdateStateNonceIfNeededAsync(response, state, HttpMethod.Post);
|
||||||
|
|
||||||
@ -524,13 +528,12 @@ public class LetsEncryptService : ILetsEncryptService {
|
|||||||
var finalRequest = new HttpRequestMessage(HttpMethod.Post, certificateUrl);
|
var finalRequest = new HttpRequestMessage(HttpMethod.Post, certificateUrl);
|
||||||
await HandleNonceAsync(sessionId, certificateUrl, state);
|
await HandleNonceAsync(sessionId, certificateUrl, state);
|
||||||
|
|
||||||
|
var finalJson = EncodeMessage(true, null, state, new JwsHeader {
|
||||||
var finalJwsHeader = CreateJwsHeader(certificateUrl, state.Nonce);
|
Url = certificateUrl,
|
||||||
var finalJson = EncodeMessage(true, null, state, finalJwsHeader);
|
Nonce = state.Nonce
|
||||||
|
});
|
||||||
PrepareRequestContent(finalRequest, finalJson, HttpMethod.Post);
|
PrepareRequestContent(finalRequest, finalJson, HttpMethod.Post);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var finalResponse = await _httpClient.SendAsync(finalRequest);
|
var finalResponse = await _httpClient.SendAsync(finalRequest);
|
||||||
UpdateStateNonceIfNeededAsync(finalResponse, state, HttpMethod.Post);
|
UpdateStateNonceIfNeededAsync(finalResponse, state, HttpMethod.Post);
|
||||||
|
|
||||||
@ -583,43 +586,42 @@ public class LetsEncryptService : ILetsEncryptService {
|
|||||||
return IDomainResult.Failed("Certificate not found");
|
return IDomainResult.Failed("Certificate not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
string Base64UrlEncode(byte[] input) {
|
|
||||||
return Convert.ToBase64String(input)
|
|
||||||
.TrimEnd('=')
|
|
||||||
.Replace('+', '-')
|
|
||||||
.Replace('/', '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Load the certificate from PEM format and convert it to DER format
|
// Load the certificate from PEM format and convert it to DER format
|
||||||
var certificate = new X509Certificate2(Encoding.UTF8.GetBytes(certificateCache.Cert));
|
var certificate = new X509Certificate2(Encoding.UTF8.GetBytes(certificateCache.Cert));
|
||||||
var derEncodedCert = certificate.Export(X509ContentType.Cert);
|
var derEncodedCert = certificate.Export(X509ContentType.Cert);
|
||||||
var base64UrlEncodedCert = Base64UrlEncode(derEncodedCert);
|
var base64UrlEncodedCert = state.JwsService.Base64UrlEncoded(derEncodedCert);
|
||||||
|
|
||||||
// Convert the certificate to DER format and Base64 encode it
|
|
||||||
var base64Cert = Convert.ToBase64String(certificate.Export(X509ContentType.Cert));
|
|
||||||
|
|
||||||
var revokeRequest = new RevokeRequest {
|
var revokeRequest = new RevokeRequest {
|
||||||
Certificate = certificateCache.Cert,
|
Certificate = base64UrlEncodedCert,
|
||||||
Reason = (int)reason
|
Reason = (int)reason
|
||||||
};
|
};
|
||||||
|
|
||||||
var request = new HttpRequestMessage(HttpMethod.Post, state.Directory.RevokeCert);
|
var request = new HttpRequestMessage(HttpMethod.Post, state.Directory.RevokeCert);
|
||||||
await HandleNonceAsync(sessionId, state.Directory.RevokeCert, state);
|
await HandleNonceAsync(sessionId, state.Directory.RevokeCert, state);
|
||||||
|
|
||||||
var jwsHeader = CreateJwsHeader(state.Directory.RevokeCert, state.Nonce);
|
var jwsHeader = new JwsHeader {
|
||||||
var json = EncodeMessage(false, revokeRequest, state, jwsHeader);
|
Url = state.Directory.RevokeCert,
|
||||||
PrepareRequestContent(request, json, HttpMethod.Post);
|
Nonce = state.Nonce
|
||||||
|
};
|
||||||
|
|
||||||
|
var json = state.JwsService.Encode(revokeRequest, jwsHeader).ToJson();
|
||||||
|
|
||||||
|
request.Content = new StringContent(json);
|
||||||
|
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/jose+json");
|
||||||
|
|
||||||
var response = await _httpClient.SendAsync(request);
|
var response = await _httpClient.SendAsync(request);
|
||||||
UpdateStateNonceIfNeededAsync(response, state, HttpMethod.Post);
|
UpdateStateNonceIfNeededAsync(response, state, HttpMethod.Post);
|
||||||
|
|
||||||
var responseText = await response.Content.ReadAsStringAsync();
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
HandleProblemResponseAsync(response, responseText);
|
if (response.Content.Headers.ContentType?.MediaType == "application/problem+json") {
|
||||||
|
var erroObj = responseText.ToObject<Problem>();
|
||||||
|
}
|
||||||
|
|
||||||
var revokeResult = ProcessResponseContent<object>(response, responseText);
|
if (!response.IsSuccessStatusCode)
|
||||||
|
IDomainResult.CriticalDependencyError(responseText);
|
||||||
|
|
||||||
|
|
||||||
// Remove the certificate from the cache after successful revocation
|
// Remove the certificate from the cache after successful revocation
|
||||||
state.Cache.CachedCerts.Remove(subject);
|
state.Cache.CachedCerts.Remove(subject);
|
||||||
|
|
||||||
@ -630,7 +632,7 @@ public class LetsEncryptService : ILetsEncryptService {
|
|||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
var message = "Let's Encrypt client unhandled exception";
|
var message = "Let's Encrypt client unhandled exception";
|
||||||
_logger.LogError(ex, message);
|
_logger.LogError(ex, message);
|
||||||
return IDomainResult.CriticalDependencyError(message);
|
return IDomainResult.CriticalDependencyError($"{message}: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -668,13 +670,6 @@ public class LetsEncryptService : ILetsEncryptService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JwsHeader CreateJwsHeader(Uri uri, string? nonce) {
|
|
||||||
return new JwsHeader {
|
|
||||||
Url = uri,
|
|
||||||
Nonce = nonce
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private string EncodeMessage(bool isPostAsGet, object? requestModel, State state, JwsHeader jwsHeader) {
|
private string EncodeMessage(bool isPostAsGet, object? requestModel, State state, JwsHeader jwsHeader) {
|
||||||
return isPostAsGet
|
return isPostAsGet
|
||||||
? state.JwsService.Encode(jwsHeader).ToJson()
|
? state.JwsService.Encode(jwsHeader).ToJson()
|
||||||
|
|||||||
@ -114,5 +114,17 @@ namespace MaksIT.LetsEncryptServer.Controllers {
|
|||||||
var result = await _certsFlowService.ApplyCertificatesAsync(sessionId, requestData);
|
var result = await _certsFlowService.ApplyCertificatesAsync(sessionId, requestData);
|
||||||
return result.ToActionResult();
|
return result.ToActionResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Revoke certificates
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sessionId"></param>
|
||||||
|
/// <param name="requestData"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("{sessionId}/certificates/revoke")]
|
||||||
|
public async Task<IActionResult> RevokeCertificates(Guid sessionId, [FromBody] RevokeCertificatesRequest requestData) {
|
||||||
|
var result = await _certsFlowService.RevokeCertificatesAsync(sessionId, requestData);
|
||||||
|
return result.ToActionResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||||
USER app
|
USER app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 5000
|
EXPOSE 8080
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
ARG BUILD_CONFIGURATION=Release
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
|
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_HTTP_PORTS": "5000"
|
"ASPNETCORE_HTTP_PORTS": "8080"
|
||||||
},
|
},
|
||||||
"publishAllPorts": true
|
"publishAllPorts": true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,8 +23,8 @@ public interface ICertsInternalService : ICertsCommonService {
|
|||||||
Task<(List<string>?, IDomainResult)> NewOrderAsync(Guid sessionId, string[] hostnames, string challengeType);
|
Task<(List<string>?, IDomainResult)> NewOrderAsync(Guid sessionId, string[] hostnames, string challengeType);
|
||||||
Task<IDomainResult> GetOrderAsync(Guid sessionId, string[] hostnames);
|
Task<IDomainResult> GetOrderAsync(Guid sessionId, string[] hostnames);
|
||||||
Task<IDomainResult> GetCertificatesAsync(Guid sessionId, string[] hostnames);
|
Task<IDomainResult> GetCertificatesAsync(Guid sessionId, string[] hostnames);
|
||||||
Task<IDomainResult> RevokeCertificatesAsync(Guid sessionId, string[] hostnames);
|
|
||||||
Task<(Dictionary<string, string>?, IDomainResult)> ApplyCertificatesAsync(Guid sessionId, string[] hostnames);
|
Task<(Dictionary<string, string>?, IDomainResult)> ApplyCertificatesAsync(Guid sessionId, string[] hostnames);
|
||||||
|
Task<IDomainResult> RevokeCertificatesAsync(Guid sessionId, string[] hostnames);
|
||||||
Task<(Guid?, IDomainResult)> FullFlow(bool isStaging, Guid? accountId, string description, string[] contacts, string challengeType, string[] hostnames);
|
Task<(Guid?, IDomainResult)> FullFlow(bool isStaging, Guid? accountId, string description, string[] contacts, string challengeType, string[] hostnames);
|
||||||
Task<IDomainResult> FullRevocationFlow(bool isStaging, Guid accountId, string description, string[] contacts, string[] hostnames);
|
Task<IDomainResult> FullRevocationFlow(bool isStaging, Guid accountId, string description, string[] contacts, string[] hostnames);
|
||||||
|
|
||||||
@ -37,6 +37,7 @@ public interface ICertsRestService : ICertsCommonService {
|
|||||||
Task<IDomainResult> GetOrderAsync(Guid sessionId, GetOrderRequest requestData);
|
Task<IDomainResult> GetOrderAsync(Guid sessionId, GetOrderRequest requestData);
|
||||||
Task<IDomainResult> GetCertificatesAsync(Guid sessionId, GetCertificatesRequest requestData);
|
Task<IDomainResult> GetCertificatesAsync(Guid sessionId, GetCertificatesRequest requestData);
|
||||||
Task<(Dictionary<string, string>?, IDomainResult)> ApplyCertificatesAsync(Guid sessionId, GetCertificatesRequest requestData);
|
Task<(Dictionary<string, string>?, IDomainResult)> ApplyCertificatesAsync(Guid sessionId, GetCertificatesRequest requestData);
|
||||||
|
Task<IDomainResult> RevokeCertificatesAsync(Guid sessionId, RevokeCertificatesRequest requestData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ICertsRestChallengeService {
|
public interface ICertsRestChallengeService {
|
||||||
@ -166,33 +167,6 @@ public class CertsFlowService : ICertsFlowService {
|
|||||||
return await _letsEncryptService.GetOrder(sessionId, hostnames);
|
return await _letsEncryptService.GetOrder(sessionId, hostnames);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IDomainResult> RevokeCertificatesAsync(Guid sessionId, string[] hostnames) {
|
|
||||||
foreach (var hostname in hostnames) {
|
|
||||||
var result = await _letsEncryptService.RevokeCertificate(sessionId, hostname, RevokeReason.Unspecified);
|
|
||||||
if (!result.IsSuccess)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Move to separate method
|
|
||||||
// Persist the cache
|
|
||||||
var (cache, getCacheResult) = _letsEncryptService.GetRegistrationCache(sessionId);
|
|
||||||
if (!getCacheResult.IsSuccess || cache == null)
|
|
||||||
return getCacheResult;
|
|
||||||
|
|
||||||
var saveResult = await _cacheService.SaveToCacheAsync(cache.AccountId, cache);
|
|
||||||
if (!saveResult.IsSuccess)
|
|
||||||
return saveResult;
|
|
||||||
|
|
||||||
return IDomainResult.Success();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<(Dictionary<string, string>?, IDomainResult)> ApplyCertificatesAsync(Guid sessionId, string[] hostnames) {
|
public async Task<(Dictionary<string, string>?, IDomainResult)> ApplyCertificatesAsync(Guid sessionId, string[] hostnames) {
|
||||||
|
|
||||||
var (cache, getCacheResult) = _letsEncryptService.GetRegistrationCache(sessionId);
|
var (cache, getCacheResult) = _letsEncryptService.GetRegistrationCache(sessionId);
|
||||||
@ -221,6 +195,26 @@ public class CertsFlowService : ICertsFlowService {
|
|||||||
return IDomainResult.Success(results);
|
return IDomainResult.Success(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IDomainResult> RevokeCertificatesAsync(Guid sessionId, string[] hostnames) {
|
||||||
|
foreach (var hostname in hostnames) {
|
||||||
|
var result = await _letsEncryptService.RevokeCertificate(sessionId, hostname, RevokeReason.Unspecified);
|
||||||
|
if (!result.IsSuccess)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Move to separate method
|
||||||
|
// Persist the cache
|
||||||
|
var (cache, getCacheResult) = _letsEncryptService.GetRegistrationCache(sessionId);
|
||||||
|
if (!getCacheResult.IsSuccess || cache == null)
|
||||||
|
return getCacheResult;
|
||||||
|
|
||||||
|
var saveResult = await _cacheService.SaveToCacheAsync(cache.AccountId, cache);
|
||||||
|
if (!saveResult.IsSuccess)
|
||||||
|
return saveResult;
|
||||||
|
|
||||||
|
return IDomainResult.Success();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<(Guid?, IDomainResult)> FullFlow(bool isStaging, Guid? accountId, string description, string[] contacts, string challengeType, string[]hostnames) {
|
public async Task<(Guid?, IDomainResult)> FullFlow(bool isStaging, Guid? accountId, string description, string[] contacts, string challengeType, string[]hostnames) {
|
||||||
var (sessionId, configureClientResult) = await ConfigureClientAsync(isStaging);
|
var (sessionId, configureClientResult) = await ConfigureClientAsync(isStaging);
|
||||||
if (!configureClientResult.IsSuccess || sessionId == null)
|
if (!configureClientResult.IsSuccess || sessionId == null)
|
||||||
@ -230,14 +224,17 @@ public class CertsFlowService : ICertsFlowService {
|
|||||||
if (!initResult.IsSuccess)
|
if (!initResult.IsSuccess)
|
||||||
return (null, initResult);
|
return (null, initResult);
|
||||||
|
|
||||||
var (_, newOrderResult) = await NewOrderAsync(sessionId.Value, hostnames, challengeType);
|
var (challenges, newOrderResult) = await NewOrderAsync(sessionId.Value, hostnames, challengeType);
|
||||||
if (!newOrderResult.IsSuccess)
|
if (!newOrderResult.IsSuccess)
|
||||||
return (null, newOrderResult);
|
return (null, newOrderResult);
|
||||||
|
|
||||||
var challengeResult = await CompleteChallengesAsync(sessionId.Value);
|
if (challenges?.Count > 0) {
|
||||||
if (!challengeResult.IsSuccess)
|
var challengeResult = await CompleteChallengesAsync(sessionId.Value);
|
||||||
return (null, challengeResult);
|
if (!challengeResult.IsSuccess)
|
||||||
|
return (null, challengeResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var getOrderResult = await GetOrderAsync(sessionId.Value, hostnames);
|
var getOrderResult = await GetOrderAsync(sessionId.Value, hostnames);
|
||||||
if (!getOrderResult.IsSuccess)
|
if (!getOrderResult.IsSuccess)
|
||||||
return (null, getOrderResult);
|
return (null, getOrderResult);
|
||||||
@ -273,6 +270,7 @@ public class CertsFlowService : ICertsFlowService {
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region REST methods
|
#region REST methods
|
||||||
|
|
||||||
public Task<(Guid?, IDomainResult)> ConfigureClientAsync(ConfigureClientRequest requestData) =>
|
public Task<(Guid?, IDomainResult)> ConfigureClientAsync(ConfigureClientRequest requestData) =>
|
||||||
ConfigureClientAsync(requestData.IsStaging);
|
ConfigureClientAsync(requestData.IsStaging);
|
||||||
|
|
||||||
@ -291,6 +289,9 @@ public class CertsFlowService : ICertsFlowService {
|
|||||||
public Task<(Dictionary<string, string>?, IDomainResult)> ApplyCertificatesAsync(Guid sessionId, GetCertificatesRequest requestData) =>
|
public Task<(Dictionary<string, string>?, IDomainResult)> ApplyCertificatesAsync(Guid sessionId, GetCertificatesRequest requestData) =>
|
||||||
ApplyCertificatesAsync(sessionId, requestData.Hostnames);
|
ApplyCertificatesAsync(sessionId, requestData.Hostnames);
|
||||||
|
|
||||||
|
public Task<IDomainResult> RevokeCertificatesAsync(Guid sessionId, RevokeCertificatesRequest requestData) =>
|
||||||
|
RevokeCertificatesAsync(sessionId, requestData.Hostnames);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Acme Challenge REST methods
|
#region Acme Challenge REST methods
|
||||||
|
|||||||
@ -6,18 +6,11 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MaksIT.Models.LetsEncryptServer.CertsFlow.Requests {
|
namespace MaksIT.Models.LetsEncryptServer.CertsFlow.Requests {
|
||||||
public class PostAccountRequest : IValidatableObject {
|
public class RevokeCertificatesRequest : IValidatableObject {
|
||||||
public required string Description { get; set; }
|
|
||||||
public required string[] Contacts { get; set; }
|
|
||||||
public required string [] Hostnames { get; set; }
|
public required string [] Hostnames { get; set; }
|
||||||
|
|
||||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
|
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
|
||||||
if (Description == null || Description.Length == 0)
|
|
||||||
yield return new ValidationResult("Description is required", new[] { nameof(Description) });
|
|
||||||
|
|
||||||
if (Contacts == null || Contacts.Length == 0)
|
|
||||||
yield return new ValidationResult("Contacts is required", new[] { nameof(Contacts) });
|
|
||||||
|
|
||||||
if (Hostnames == null || Hostnames.Length == 0)
|
if (Hostnames == null || Hostnames.Length == 0)
|
||||||
yield return new ValidationResult("Hostnames is required", new[] { nameof(Hostnames) });
|
yield return new ValidationResult("Hostnames is required", new[] { nameof(Hostnames) });
|
||||||
}
|
}
|
||||||
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"info": {
|
"info": {
|
||||||
"_postman_id": "95186b61-1197-4a6e-a90f-d97223528d90",
|
"_postman_id": "95186b61-1197-4a6e-a90f-d97223528d90",
|
||||||
"name": "LetsEncrypt Staging",
|
"name": "LetsEncrypt Client",
|
||||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||||
"_exporter_id": "33635244"
|
"_exporter_id": "33635244"
|
||||||
},
|
},
|
||||||
"item": [
|
"item": [
|
||||||
{
|
{
|
||||||
"name": "Cache",
|
"name": "account",
|
||||||
"item": [
|
"item": [
|
||||||
{
|
{
|
||||||
"name": "get cache contacts",
|
"name": "get cache contacts",
|
||||||
@ -116,24 +116,17 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Certs Manual Flow",
|
"name": "certs",
|
||||||
"item": [
|
"item": [
|
||||||
{
|
{
|
||||||
"name": "letsencrypt staging",
|
"name": "letsencrypt directory",
|
||||||
"request": {
|
"request": {
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"header": [],
|
"header": [],
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "https://acme-staging-v02.api.letsencrypt.org/directory",
|
"raw": "{{letsEncryptDirectory}}",
|
||||||
"protocol": "https",
|
|
||||||
"host": [
|
"host": [
|
||||||
"acme-staging-v02",
|
"{{letsEncryptDirectory}}"
|
||||||
"api",
|
|
||||||
"letsencrypt",
|
|
||||||
"org"
|
|
||||||
],
|
|
||||||
"path": [
|
|
||||||
"directory"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"description": "[https://letsencrypt.status.io/](https://letsencrypt.status.io/)"
|
"description": "[https://letsencrypt.status.io/](https://letsencrypt.status.io/)"
|
||||||
@ -141,7 +134,7 @@
|
|||||||
"response": []
|
"response": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "configure client",
|
"name": "configure-client",
|
||||||
"event": [
|
"event": [
|
||||||
{
|
{
|
||||||
"listen": "test",
|
"listen": "test",
|
||||||
@ -185,8 +178,17 @@
|
|||||||
"value": "application/json"
|
"value": "application/json"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\r\n \"isStaging\": {{isStaging}}\r\n}",
|
||||||
|
"options": {
|
||||||
|
"raw": {
|
||||||
|
"language": "json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/ConfigureClient",
|
"raw": "http://localhost:8080/api/certs/configure-client",
|
||||||
"protocol": "http",
|
"protocol": "http",
|
||||||
"host": [
|
"host": [
|
||||||
"localhost"
|
"localhost"
|
||||||
@ -194,20 +196,20 @@
|
|||||||
"port": "8080",
|
"port": "8080",
|
||||||
"path": [
|
"path": [
|
||||||
"api",
|
"api",
|
||||||
"CertsFlow",
|
"certs",
|
||||||
"ConfigureClient"
|
"configure-client"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"response": []
|
"response": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "terms of service",
|
"name": "terms-of-service",
|
||||||
"request": {
|
"request": {
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"header": [],
|
"header": [],
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/TermsOfService/{{sessionId}}",
|
"raw": "http://localhost:8080/api/certs/{{sessionId}}/terms-of-service",
|
||||||
"protocol": "http",
|
"protocol": "http",
|
||||||
"host": [
|
"host": [
|
||||||
"localhost"
|
"localhost"
|
||||||
@ -215,9 +217,9 @@
|
|||||||
"port": "8080",
|
"port": "8080",
|
||||||
"path": [
|
"path": [
|
||||||
"api",
|
"api",
|
||||||
"CertsFlow",
|
"certs",
|
||||||
"TermsOfService",
|
"{{sessionId}}",
|
||||||
"{{sessionId}}"
|
"terms-of-service"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -300,7 +302,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/Init/{{sessionId}}/{{accountId}}",
|
"raw": "http://localhost:8080/api/certs/{{sessionId}}/init/{{accountId}}",
|
||||||
"protocol": "http",
|
"protocol": "http",
|
||||||
"host": [
|
"host": [
|
||||||
"localhost"
|
"localhost"
|
||||||
@ -308,9 +310,9 @@
|
|||||||
"port": "8080",
|
"port": "8080",
|
||||||
"path": [
|
"path": [
|
||||||
"api",
|
"api",
|
||||||
"CertsFlow",
|
"certs",
|
||||||
"Init",
|
|
||||||
"{{sessionId}}",
|
"{{sessionId}}",
|
||||||
|
"init",
|
||||||
"{{accountId}}"
|
"{{accountId}}"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -318,7 +320,7 @@
|
|||||||
"response": []
|
"response": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "new order",
|
"name": "order",
|
||||||
"event": [
|
"event": [
|
||||||
{
|
{
|
||||||
"listen": "test",
|
"listen": "test",
|
||||||
@ -378,7 +380,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/NewOrder/{{sessionId}}",
|
"raw": "http://localhost:8080/api/certs/{{sessionId}}/order",
|
||||||
"protocol": "http",
|
"protocol": "http",
|
||||||
"host": [
|
"host": [
|
||||||
"localhost"
|
"localhost"
|
||||||
@ -386,9 +388,9 @@
|
|||||||
"port": "8080",
|
"port": "8080",
|
||||||
"path": [
|
"path": [
|
||||||
"api",
|
"api",
|
||||||
"CertsFlow",
|
"certs",
|
||||||
"NewOrder",
|
"{{sessionId}}",
|
||||||
"{{sessionId}}"
|
"order"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -438,7 +440,7 @@
|
|||||||
"response": []
|
"response": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "complete challenges",
|
"name": "complete-challenges",
|
||||||
"request": {
|
"request": {
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"header": [
|
"header": [
|
||||||
@ -461,7 +463,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/CompleteChallenges/{{sessionId}}",
|
"raw": "http://localhost:8080/api/certs/{{sessionId}}/complete-challenges",
|
||||||
"protocol": "http",
|
"protocol": "http",
|
||||||
"host": [
|
"host": [
|
||||||
"localhost"
|
"localhost"
|
||||||
@ -469,16 +471,16 @@
|
|||||||
"port": "8080",
|
"port": "8080",
|
||||||
"path": [
|
"path": [
|
||||||
"api",
|
"api",
|
||||||
"CertsFlow",
|
"certs",
|
||||||
"CompleteChallenges",
|
"{{sessionId}}",
|
||||||
"{{sessionId}}"
|
"complete-challenges"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"response": []
|
"response": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "get order",
|
"name": "order-status",
|
||||||
"request": {
|
"request": {
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"header": [
|
"header": [
|
||||||
@ -501,7 +503,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/GetOrder/{{sessionId}}",
|
"raw": "http://localhost:8080/api/certs/{{sessionId}}/order-status",
|
||||||
"protocol": "http",
|
"protocol": "http",
|
||||||
"host": [
|
"host": [
|
||||||
"localhost"
|
"localhost"
|
||||||
@ -509,16 +511,16 @@
|
|||||||
"port": "8080",
|
"port": "8080",
|
||||||
"path": [
|
"path": [
|
||||||
"api",
|
"api",
|
||||||
"CertsFlow",
|
"certs",
|
||||||
"GetOrder",
|
"{{sessionId}}",
|
||||||
"{{sessionId}}"
|
"order-status"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"response": []
|
"response": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "get certificates",
|
"name": "download",
|
||||||
"request": {
|
"request": {
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"header": [
|
"header": [
|
||||||
@ -541,7 +543,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/GetCertificates/{{sessionId}}",
|
"raw": "http://localhost:8080/api/certs/{{sessionId}}//certificates/download",
|
||||||
"protocol": "http",
|
"protocol": "http",
|
||||||
"host": [
|
"host": [
|
||||||
"localhost"
|
"localhost"
|
||||||
@ -549,16 +551,18 @@
|
|||||||
"port": "8080",
|
"port": "8080",
|
||||||
"path": [
|
"path": [
|
||||||
"api",
|
"api",
|
||||||
"CertsFlow",
|
"certs",
|
||||||
"GetCertificates",
|
"{{sessionId}}",
|
||||||
"{{sessionId}}"
|
"",
|
||||||
|
"certificates",
|
||||||
|
"download"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"response": []
|
"response": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "apply certificates",
|
"name": "apply",
|
||||||
"request": {
|
"request": {
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"header": [
|
"header": [
|
||||||
@ -581,7 +585,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/ApplyCertificates/{{sessionId}}",
|
"raw": "http://localhost:8080/api/certs/{{sessionId}}/certificates/apply",
|
||||||
"protocol": "http",
|
"protocol": "http",
|
||||||
"host": [
|
"host": [
|
||||||
"localhost"
|
"localhost"
|
||||||
@ -589,9 +593,53 @@
|
|||||||
"port": "8080",
|
"port": "8080",
|
||||||
"path": [
|
"path": [
|
||||||
"api",
|
"api",
|
||||||
"CertsFlow",
|
"certs",
|
||||||
"ApplyCertificates",
|
"{{sessionId}}",
|
||||||
"{{sessionId}}"
|
"certificates",
|
||||||
|
"apply"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "revoke",
|
||||||
|
"request": {
|
||||||
|
"method": "POST",
|
||||||
|
"header": [
|
||||||
|
{
|
||||||
|
"key": "Content-Type",
|
||||||
|
"value": "application/json",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "Accept",
|
||||||
|
"value": "application/json",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\r\n \"hostnames\": [\r\n \"staging.maks-it.com\"\r\n ]\r\n}",
|
||||||
|
"options": {
|
||||||
|
"raw": {
|
||||||
|
"language": "json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "http://localhost:8080/api/certs/{{sessionId}}/certificates/revoke",
|
||||||
|
"protocol": "http",
|
||||||
|
"host": [
|
||||||
|
"localhost"
|
||||||
|
],
|
||||||
|
"port": "8080",
|
||||||
|
"path": [
|
||||||
|
"api",
|
||||||
|
"certs",
|
||||||
|
"{{sessionId}}",
|
||||||
|
"certificates",
|
||||||
|
"revoke"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1,601 +0,0 @@
|
|||||||
{
|
|
||||||
"info": {
|
|
||||||
"_postman_id": "728f64b6-893b-43fa-802e-ee836d1dc372",
|
|
||||||
"name": "LetsEncrypt Production",
|
|
||||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
|
||||||
"_exporter_id": "33635244"
|
|
||||||
},
|
|
||||||
"item": [
|
|
||||||
{
|
|
||||||
"name": "Cache",
|
|
||||||
"item": [
|
|
||||||
{
|
|
||||||
"name": "get cache contacts",
|
|
||||||
"request": {
|
|
||||||
"method": "GET",
|
|
||||||
"header": [
|
|
||||||
{
|
|
||||||
"key": "Content-Type",
|
|
||||||
"value": "application/json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Accept",
|
|
||||||
"value": "application/json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"url": {
|
|
||||||
"raw": "http://localhost:8080/api/Cache/GetContacts/{{accountId}}",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"localhost"
|
|
||||||
],
|
|
||||||
"port": "8080",
|
|
||||||
"path": [
|
|
||||||
"api",
|
|
||||||
"Cache",
|
|
||||||
"GetContacts",
|
|
||||||
"{{accountId}}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "set cache contacts",
|
|
||||||
"request": {
|
|
||||||
"method": "POST",
|
|
||||||
"header": [
|
|
||||||
{
|
|
||||||
"key": "Content-Type",
|
|
||||||
"value": "application/json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Accept",
|
|
||||||
"value": "application/json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"body": {
|
|
||||||
"mode": "raw",
|
|
||||||
"raw": "{\r\n \"contacts\": [\r\n \"maksym.sadovnychyy@gmail.com\"\r\n ]\r\n}",
|
|
||||||
"options": {
|
|
||||||
"raw": {
|
|
||||||
"language": "json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"raw": "http://localhost:8080/api/Cache/SetContacts/{{accountId}}",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"localhost"
|
|
||||||
],
|
|
||||||
"port": "8080",
|
|
||||||
"path": [
|
|
||||||
"api",
|
|
||||||
"Cache",
|
|
||||||
"SetContacts",
|
|
||||||
"{{accountId}}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "host with upcoming ssl expire",
|
|
||||||
"request": {
|
|
||||||
"method": "GET",
|
|
||||||
"header": [
|
|
||||||
{
|
|
||||||
"key": "Content-Type",
|
|
||||||
"value": "application/json",
|
|
||||||
"disabled": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Accept",
|
|
||||||
"value": "application/json",
|
|
||||||
"disabled": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"url": {
|
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/HostsWithUpcomingSslExpiry/{{sessionId}}",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"localhost"
|
|
||||||
],
|
|
||||||
"port": "8080",
|
|
||||||
"path": [
|
|
||||||
"api",
|
|
||||||
"CertsFlow",
|
|
||||||
"HostsWithUpcomingSslExpiry",
|
|
||||||
"{{sessionId}}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Certs Manual Flow",
|
|
||||||
"item": [
|
|
||||||
{
|
|
||||||
"name": "letsencrypt production",
|
|
||||||
"request": {
|
|
||||||
"method": "GET",
|
|
||||||
"header": [],
|
|
||||||
"url": {
|
|
||||||
"raw": "https://acme-v02.api.letsencrypt.org/directory",
|
|
||||||
"protocol": "https",
|
|
||||||
"host": [
|
|
||||||
"acme-v02",
|
|
||||||
"api",
|
|
||||||
"letsencrypt",
|
|
||||||
"org"
|
|
||||||
],
|
|
||||||
"path": [
|
|
||||||
"directory"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "configure client",
|
|
||||||
"event": [
|
|
||||||
{
|
|
||||||
"listen": "test",
|
|
||||||
"script": {
|
|
||||||
"exec": [
|
|
||||||
"// Ensure the response status code is 200 (OK)\r",
|
|
||||||
"if (pm.response.code === 200) {\r",
|
|
||||||
" // Get the plain text response\r",
|
|
||||||
" let responseBody = pm.response.text();\r",
|
|
||||||
" \r",
|
|
||||||
" // Remove the surrounding quotes if present\r",
|
|
||||||
" responseBody = responseBody.replace(/^\"|\"$/g, '');\r",
|
|
||||||
" \r",
|
|
||||||
" // Check if the response body is a valid GUID\r",
|
|
||||||
" if (/^[0-9a-fA-F-]{36}$/.test(responseBody)) {\r",
|
|
||||||
" // Set the environment variable sessionId with the response\r",
|
|
||||||
" pm.environment.set(\"sessionId\", responseBody);\r",
|
|
||||||
" console.log(`sessionId set to: ${responseBody}`);\r",
|
|
||||||
" } else {\r",
|
|
||||||
" console.log(\"Response body is not a valid GUID\");\r",
|
|
||||||
" }\r",
|
|
||||||
"} else {\r",
|
|
||||||
" console.log(`Request failed with status code: ${pm.response.code}`);\r",
|
|
||||||
"}\r",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"type": "text/javascript",
|
|
||||||
"packages": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"request": {
|
|
||||||
"method": "POST",
|
|
||||||
"header": [
|
|
||||||
{
|
|
||||||
"key": "Content-Type",
|
|
||||||
"value": "application/json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Accept",
|
|
||||||
"value": "application/json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"url": {
|
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/ConfigureClient",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"localhost"
|
|
||||||
],
|
|
||||||
"port": "8080",
|
|
||||||
"path": [
|
|
||||||
"api",
|
|
||||||
"CertsFlow",
|
|
||||||
"ConfigureClient"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "terms of service",
|
|
||||||
"request": {
|
|
||||||
"method": "GET",
|
|
||||||
"header": [],
|
|
||||||
"url": {
|
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/TermsOfService/{{sessionId}}",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"localhost"
|
|
||||||
],
|
|
||||||
"port": "8080",
|
|
||||||
"path": [
|
|
||||||
"api",
|
|
||||||
"CertsFlow",
|
|
||||||
"TermsOfService",
|
|
||||||
"{{sessionId}}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "init",
|
|
||||||
"event": [
|
|
||||||
{
|
|
||||||
"listen": "test",
|
|
||||||
"script": {
|
|
||||||
"exec": [
|
|
||||||
"// Ensure the response status code is 200 (OK)\r",
|
|
||||||
"if (pm.response.code === 200) {\r",
|
|
||||||
" // Get the plain text response\r",
|
|
||||||
" let responseBody = pm.response.text();\r",
|
|
||||||
" \r",
|
|
||||||
" // Remove the surrounding quotes if present\r",
|
|
||||||
" responseBody = responseBody.replace(/^\"|\"$/g, '');\r",
|
|
||||||
" \r",
|
|
||||||
" // Check if the response body is a valid GUID\r",
|
|
||||||
" if (/^[0-9a-fA-F-]{36}$/.test(responseBody)) {\r",
|
|
||||||
" // Set the environment variable accountId with the response\r",
|
|
||||||
" pm.environment.set(\"accountId\", responseBody);\r",
|
|
||||||
" console.log(`accountId set to: ${responseBody}`);\r",
|
|
||||||
" } else {\r",
|
|
||||||
" console.log(\"Response body is not a valid GUID\");\r",
|
|
||||||
" }\r",
|
|
||||||
"} else {\r",
|
|
||||||
" console.log(`Request failed with status code: ${pm.response.code}`);\r",
|
|
||||||
"}\r",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"type": "text/javascript",
|
|
||||||
"packages": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"listen": "prerequest",
|
|
||||||
"script": {
|
|
||||||
"exec": [
|
|
||||||
"// Retrieve sessionId and accountId from environment variables or global variables\r",
|
|
||||||
"var sessionId = pm.environment.get(\"sessionId\") || pm.globals.get(\"sessionId\");\r",
|
|
||||||
"var accountId = pm.environment.get(\"accountId\") || pm.globals.get(\"accountId\");\r",
|
|
||||||
"\r",
|
|
||||||
"// Base URL without the optional accountId parameter\r",
|
|
||||||
"var baseUrl = `http://localhost:8080/CertsFlow/Init/${sessionId}`;\r",
|
|
||||||
"\r",
|
|
||||||
"// Append the accountId if it is provided\r",
|
|
||||||
"if (accountId) {\r",
|
|
||||||
" pm.request.url = `${baseUrl}/${accountId}`;\r",
|
|
||||||
"} else {\r",
|
|
||||||
" pm.request.url = baseUrl;\r",
|
|
||||||
"}"
|
|
||||||
],
|
|
||||||
"type": "text/javascript",
|
|
||||||
"packages": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"request": {
|
|
||||||
"method": "POST",
|
|
||||||
"header": [
|
|
||||||
{
|
|
||||||
"key": "Content-Type",
|
|
||||||
"value": "application/json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Accept",
|
|
||||||
"value": "application/json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"body": {
|
|
||||||
"mode": "raw",
|
|
||||||
"raw": "{\r\n \"contacts\": [\r\n \"maksym.sadovnychyy@gmail.com\"\r\n ]\r\n}",
|
|
||||||
"options": {
|
|
||||||
"raw": {
|
|
||||||
"language": "json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/Init/{{sessionId}}/{{accountId}}",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"localhost"
|
|
||||||
],
|
|
||||||
"port": "8080",
|
|
||||||
"path": [
|
|
||||||
"api",
|
|
||||||
"CertsFlow",
|
|
||||||
"Init",
|
|
||||||
"{{sessionId}}",
|
|
||||||
"{{accountId}}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "new order",
|
|
||||||
"event": [
|
|
||||||
{
|
|
||||||
"listen": "test",
|
|
||||||
"script": {
|
|
||||||
"exec": [
|
|
||||||
"// Ensure the response status code is 200 (OK)\r",
|
|
||||||
"if (pm.response.code === 200) {\r",
|
|
||||||
" // Parse the JSON response\r",
|
|
||||||
" let responseBody;\r",
|
|
||||||
" try {\r",
|
|
||||||
" responseBody = pm.response.json();\r",
|
|
||||||
" } catch (e) {\r",
|
|
||||||
" console.error(\"Failed to parse JSON response:\", e);\r",
|
|
||||||
" return;\r",
|
|
||||||
" }\r",
|
|
||||||
"\r",
|
|
||||||
" // Check if the response is an array and has at least one element\r",
|
|
||||||
" if (Array.isArray(responseBody) && responseBody.length > 0) {\r",
|
|
||||||
" // Get the first element of the array\r",
|
|
||||||
" const firstElement = responseBody[0];\r",
|
|
||||||
" \r",
|
|
||||||
" // Set the environment variable challenge with the first element\r",
|
|
||||||
" pm.environment.set(\"challenge\", firstElement);\r",
|
|
||||||
" console.log(`challenge set to: ${firstElement}`);\r",
|
|
||||||
" } else {\r",
|
|
||||||
" console.log(\"Response body is not an array or is empty\");\r",
|
|
||||||
" }\r",
|
|
||||||
"} else {\r",
|
|
||||||
" console.log(`Request failed with status code: ${pm.response.code}`);\r",
|
|
||||||
"}\r",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"type": "text/javascript",
|
|
||||||
"packages": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"request": {
|
|
||||||
"method": "POST",
|
|
||||||
"header": [
|
|
||||||
{
|
|
||||||
"key": "Content-Type",
|
|
||||||
"value": "application/json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Accept",
|
|
||||||
"value": "application/json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"body": {
|
|
||||||
"mode": "raw",
|
|
||||||
"raw": "{\r\n \"hostnames\": [\r\n \"maks-it.com\",\r\n \"auth.maks-it.com\"\r\n ],\r\n \"challengeType\": \"http-01\"\r\n}",
|
|
||||||
"options": {
|
|
||||||
"raw": {
|
|
||||||
"language": "json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/NewOrder/{{sessionId}}",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"localhost"
|
|
||||||
],
|
|
||||||
"port": "8080",
|
|
||||||
"path": [
|
|
||||||
"api",
|
|
||||||
"CertsFlow",
|
|
||||||
"NewOrder",
|
|
||||||
"{{sessionId}}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "acme-challenge local",
|
|
||||||
"request": {
|
|
||||||
"method": "GET",
|
|
||||||
"header": [],
|
|
||||||
"url": {
|
|
||||||
"raw": "http://localhost:8080/.well-known/acme-challenge/{{challenge}}",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"localhost"
|
|
||||||
],
|
|
||||||
"port": "8080",
|
|
||||||
"path": [
|
|
||||||
".well-known",
|
|
||||||
"acme-challenge",
|
|
||||||
"{{challenge}}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "acme-challenge",
|
|
||||||
"request": {
|
|
||||||
"method": "GET",
|
|
||||||
"header": [],
|
|
||||||
"url": {
|
|
||||||
"raw": "http://maks-it.com/.well-known/acme-challenge/{{challenge}}",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"maks-it",
|
|
||||||
"com"
|
|
||||||
],
|
|
||||||
"path": [
|
|
||||||
".well-known",
|
|
||||||
"acme-challenge",
|
|
||||||
"{{challenge}}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "complete challenges",
|
|
||||||
"request": {
|
|
||||||
"method": "POST",
|
|
||||||
"header": [
|
|
||||||
{
|
|
||||||
"key": "Content-Type",
|
|
||||||
"value": "application/json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Accept",
|
|
||||||
"value": "application/json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"body": {
|
|
||||||
"mode": "raw",
|
|
||||||
"raw": "",
|
|
||||||
"options": {
|
|
||||||
"raw": {
|
|
||||||
"language": "json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/CompleteChallenges/{{sessionId}}",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"localhost"
|
|
||||||
],
|
|
||||||
"port": "8080",
|
|
||||||
"path": [
|
|
||||||
"api",
|
|
||||||
"CertsFlow",
|
|
||||||
"CompleteChallenges",
|
|
||||||
"{{sessionId}}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "get order",
|
|
||||||
"request": {
|
|
||||||
"method": "POST",
|
|
||||||
"header": [
|
|
||||||
{
|
|
||||||
"key": "Content-Type",
|
|
||||||
"value": "application/json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Accept",
|
|
||||||
"value": "application/json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"body": {
|
|
||||||
"mode": "raw",
|
|
||||||
"raw": "{\r\n \"hostnames\": [\r\n \"maks-it.com\",\r\n \"auth.maks-it.com\"\r\n ]\r\n}",
|
|
||||||
"options": {
|
|
||||||
"raw": {
|
|
||||||
"language": "json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/GetOrder/{{sessionId}}",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"localhost"
|
|
||||||
],
|
|
||||||
"port": "8080",
|
|
||||||
"path": [
|
|
||||||
"api",
|
|
||||||
"CertsFlow",
|
|
||||||
"GetOrder",
|
|
||||||
"{{sessionId}}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "get certificates",
|
|
||||||
"request": {
|
|
||||||
"method": "POST",
|
|
||||||
"header": [
|
|
||||||
{
|
|
||||||
"key": "Content-Type",
|
|
||||||
"value": "application/json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Accept",
|
|
||||||
"value": "application/json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"body": {
|
|
||||||
"mode": "raw",
|
|
||||||
"raw": "{\r\n \"hostnames\": [\r\n \"maks-it.com\",\r\n \"auth.maks-it.com\"\r\n ]\r\n}",
|
|
||||||
"options": {
|
|
||||||
"raw": {
|
|
||||||
"language": "json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/GetCertificates/{{sessionId}}",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"localhost"
|
|
||||||
],
|
|
||||||
"port": "8080",
|
|
||||||
"path": [
|
|
||||||
"api",
|
|
||||||
"CertsFlow",
|
|
||||||
"GetCertificates",
|
|
||||||
"{{sessionId}}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "apply certificates",
|
|
||||||
"request": {
|
|
||||||
"method": "POST",
|
|
||||||
"header": [
|
|
||||||
{
|
|
||||||
"key": "Content-Type",
|
|
||||||
"value": "application/json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Accept",
|
|
||||||
"value": "application/json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"body": {
|
|
||||||
"mode": "raw",
|
|
||||||
"raw": "{\r\n \"hostnames\": [\r\n \"maks-it.com\",\r\n \"auth.maks-it.com\"\r\n ]\r\n}",
|
|
||||||
"options": {
|
|
||||||
"raw": {
|
|
||||||
"language": "json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"raw": "http://localhost:8080/api/CertsFlow/ApplyCertificates/{{sessionId}}",
|
|
||||||
"protocol": "http",
|
|
||||||
"host": [
|
|
||||||
"localhost"
|
|
||||||
],
|
|
||||||
"port": "8080",
|
|
||||||
"path": [
|
|
||||||
"api",
|
|
||||||
"CertsFlow",
|
|
||||||
"ApplyCertificates",
|
|
||||||
"{{sessionId}}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
24
src/ReverseProxy/Dockerfile
Normal file
24
src/ReverseProxy/Dockerfile
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||||
|
USER app
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
WORKDIR /src
|
||||||
|
COPY ["ReverseProxy/ReverseProxy.csproj", "ReverseProxy/"]
|
||||||
|
RUN dotnet restore "./ReverseProxy/ReverseProxy.csproj"
|
||||||
|
COPY . .
|
||||||
|
WORKDIR "/src/ReverseProxy"
|
||||||
|
RUN dotnet build "./ReverseProxy.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||||
|
|
||||||
|
FROM build AS publish
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
RUN dotnet publish "./ReverseProxy.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app/publish .
|
||||||
|
ENTRYPOINT ["dotnet", "ReverseProxy.dll"]
|
||||||
22
src/ReverseProxy/Program.cs
Normal file
22
src/ReverseProxy/Program.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
|
||||||
|
//builder.Services.AddDataProtection()
|
||||||
|
// .PersistKeysToFileSystem(new DirectoryInfo(@"/keys"))
|
||||||
|
// .SetApplicationName("YourAppName");
|
||||||
|
|
||||||
|
// Add YARP services
|
||||||
|
builder.Services.AddReverseProxy()
|
||||||
|
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
app.UseRouting();
|
||||||
|
|
||||||
|
// Use YARP reverse proxy
|
||||||
|
app.UseEndpoints(endpoints => {
|
||||||
|
endpoints.MapReverseProxy();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.Run();
|
||||||
40
src/ReverseProxy/Properties/launchSettings.json
Normal file
40
src/ReverseProxy/Properties/launchSettings.json
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "weatherforecast",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"applicationUrl": "http://localhost:5276"
|
||||||
|
},
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "weatherforecast",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Container (Dockerfile)": {
|
||||||
|
"commandName": "Docker",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/weatherforecast",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_HTTP_PORTS": "8080"
|
||||||
|
},
|
||||||
|
"publishAllPorts": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:40278",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/ReverseProxy/ReverseProxy.csproj
Normal file
16
src/ReverseProxy/ReverseProxy.csproj
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Extensions" Version="8.0.7" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
|
||||||
|
<PackageReference Include="Yarp.ReverseProxy" Version="2.1.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
8
src/ReverseProxy/appsettings.Development.json
Normal file
8
src/ReverseProxy/appsettings.Development.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/ReverseProxy/appsettings.json
Normal file
46
src/ReverseProxy/appsettings.json
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"ReverseProxy": {
|
||||||
|
"Routes": {
|
||||||
|
"well-known-acme-challenge-route": {
|
||||||
|
"Match": {
|
||||||
|
"Path": "/.well-known/acme-challenge/{**catch-all}"
|
||||||
|
},
|
||||||
|
"ClusterId": "letsencryptserver"
|
||||||
|
},
|
||||||
|
"swagger-route": {
|
||||||
|
"Match": {
|
||||||
|
"Path": "/swagger/{**catch-all}"
|
||||||
|
},
|
||||||
|
"ClusterId": "letsencryptserver"
|
||||||
|
},
|
||||||
|
"api-route": {
|
||||||
|
"Match": {
|
||||||
|
"Path": "/api/{**catch-all}"
|
||||||
|
},
|
||||||
|
"ClusterId": "letsencryptserver"
|
||||||
|
},
|
||||||
|
"default-route": {
|
||||||
|
"Match": {
|
||||||
|
"Path": "{**catch-all}"
|
||||||
|
},
|
||||||
|
"ClusterId": "letsencryptapp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Clusters": {
|
||||||
|
"letsencryptserver": {
|
||||||
|
"Destinations": {
|
||||||
|
"destination1": {
|
||||||
|
"Address": "http://letsencryptserver:5000/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"letsencryptapp": {
|
||||||
|
"Destinations": {
|
||||||
|
"destination1": {
|
||||||
|
"Address": "http://letsencryptapp:3000/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,12 @@
|
|||||||
version: '3.9'
|
version: '3.9'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# haproxy:
|
reverseProxy:
|
||||||
# ports:
|
ports:
|
||||||
# - "8080:8080"
|
- "8080:8080"
|
||||||
# volumes:
|
depends_on:
|
||||||
# - ./docker-compose/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
|
- letsencryptapp
|
||||||
# depends_on:
|
- letsencryptserver
|
||||||
# - letsencryptapp
|
|
||||||
# - letsencryptserver
|
|
||||||
|
|
||||||
# letsencryptapp:
|
# letsencryptapp:
|
||||||
# ports:
|
# ports:
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
version: '3.9'
|
version: '3.9'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
letsencryptapp:
|
||||||
|
image: ${DOCKER_REGISTRY-}letsencryptapp
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ClientApp/Dockerfile
|
||||||
|
|
||||||
# haproxy:
|
reverseProxy:
|
||||||
# image: haproxy:3.0.0-alpine
|
image: ${DOCKER_REGISTRY-}reverseproxy
|
||||||
|
build:
|
||||||
# letsencryptapp:
|
context: .
|
||||||
# image: ${DOCKER_REGISTRY-}letsencryptapp
|
dockerfile: ReverseProxy/Dockerfile
|
||||||
# build:
|
|
||||||
# context: .
|
|
||||||
# dockerfile: ClientApp/Dockerfile
|
|
||||||
|
|
||||||
letsencryptserver:
|
letsencryptserver:
|
||||||
image: ${DOCKER_REGISTRY-}letsencryptserver
|
image: ${DOCKER_REGISTRY-}letsencryptserver
|
||||||
|
|||||||
@ -1,30 +0,0 @@
|
|||||||
# docker_compose/haproxy/haproxy.cfg
|
|
||||||
|
|
||||||
global
|
|
||||||
log stdout format raw local0
|
|
||||||
maxconn 4096
|
|
||||||
tune.ssl.default-dh-param 2048
|
|
||||||
|
|
||||||
defaults
|
|
||||||
log global
|
|
||||||
mode http
|
|
||||||
option httplog
|
|
||||||
option dontlognull
|
|
||||||
option forwardfor
|
|
||||||
option http-server-close
|
|
||||||
timeout connect 5000ms
|
|
||||||
timeout client 50000ms
|
|
||||||
timeout server 50000ms
|
|
||||||
|
|
||||||
frontend http_front
|
|
||||||
bind *:8080
|
|
||||||
acl is_letsencryptserver path_beg /api /swagger /.well-known/acme-challenge
|
|
||||||
|
|
||||||
use_backend letsencryptserver_backend if is_letsencryptserver
|
|
||||||
default_backend letsencryptapp_backend
|
|
||||||
|
|
||||||
backend letsencryptapp_backend
|
|
||||||
server letsencryptapp letsencryptapp:3000 check
|
|
||||||
|
|
||||||
backend letsencryptserver_backend
|
|
||||||
server letsencryptserver letsencryptserver:5000 check
|
|
||||||
Loading…
Reference in New Issue
Block a user