summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.lib/Clients/Acme/OrderManager.cs2
-rw-r--r--src/main.lib/Clients/AcmeDnsClient.cs13
-rw-r--r--src/main.lib/Clients/DNS/LookupClientProvider.cs12
-rw-r--r--src/main.lib/Clients/IIS/IISClient.cs4
-rw-r--r--src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptionsFactory.cs2
-rw-r--r--src/main.lib/Plugins/StorePlugins/PfxFile/PfxFileOptionsFactory.cs2
-rw-r--r--src/main.lib/Plugins/TargetPlugins/Csr/CsrOptionsFactory.cs2
-rw-r--r--src/main.lib/Plugins/TargetPlugins/IIS/IISOptionsFactory.cs2
-rw-r--r--src/main.lib/Plugins/ValidationPlugins/Dns/Acme/Acme.cs4
-rw-r--r--src/main.lib/Plugins/ValidationPlugins/Dns/DnsValidation.cs67
-rw-r--r--src/main.lib/Plugins/ValidationPlugins/Dns/Manual/Manual.cs14
-rw-r--r--src/main.lib/Plugins/ValidationPlugins/Dns/Script/Script.cs4
-rw-r--r--src/main.lib/RenewalCreator.cs2
-rw-r--r--src/main.lib/Wacs.cs2
-rwxr-xr-xsrc/plugin.validation.dns.azure/Azure.cs52
-rw-r--r--src/plugin.validation.dns.cloudflare/Cloudflare.cs23
-rw-r--r--src/plugin.validation.dns.dreamhost/DreamhostDnsValidation.cs26
-rw-r--r--src/plugin.validation.dns.luadns/luadns.cs23
-rw-r--r--src/plugin.validation.dns.route53/Route53.cs41
19 files changed, 189 insertions, 108 deletions
diff --git a/src/main.lib/Clients/Acme/OrderManager.cs b/src/main.lib/Clients/Acme/OrderManager.cs
index aecb184..51a30c3 100644
--- a/src/main.lib/Clients/Acme/OrderManager.cs
+++ b/src/main.lib/Clients/Acme/OrderManager.cs
@@ -42,7 +42,7 @@ namespace PKISharp.WACS.Clients.Acme
public async Task<OrderDetails?> GetOrCreate(Order order, RunLevel runLevel)
{
var cacheKey = _certificateService.CacheKey(order);
- var existingOrder = FindRecentOrder(cacheKey);
+ var existingOrder = default(OrderDetails); // FindRecentOrder(cacheKey);
if (existingOrder != null)
{
try
diff --git a/src/main.lib/Clients/AcmeDnsClient.cs b/src/main.lib/Clients/AcmeDnsClient.cs
index ff81997..fb6cd0d 100644
--- a/src/main.lib/Clients/AcmeDnsClient.cs
+++ b/src/main.lib/Clients/AcmeDnsClient.cs
@@ -76,7 +76,8 @@ namespace PKISharp.WACS.Clients
_input.Show("Note", "Some DNS control panels add the final dot automatically. Only one is required.");
if (!await _input.Wait("Please press <Enter> after you've created and verified the record"))
{
- throw new Exception("User aborted");
+ _log.Warning("User aborted");
+ return false;
}
if (await VerifyRegistration(domain, newReg.Fulldomain, interactive))
{
@@ -111,7 +112,7 @@ namespace PKISharp.WACS.Clients
}
else if (interactive && _input != null)
{
- if (!await _input.PromptYesNo("Unable to verify acme-dns configuration, press 'Y' or <ENTER> to retry, or 'N' to skip this step.", true))
+ if (!await _input.PromptYesNo("Unable to verify acme-dns configuration, press 'Y' or <Enter> to retry, or 'N' to skip this step.", true))
{
_log.Warning("Verification of acme-dns configuration skipped.");
return true;
@@ -199,18 +200,18 @@ namespace PKISharp.WACS.Clients
}
}
- public async Task Update(string domain, string token)
+ public async Task<bool> Update(string domain, string token)
{
var reg = RegistrationForDomain(domain);
if (reg == null)
{
_log.Error("No registration found for domain {domain}", domain);
- return;
+ return false;
}
if (reg.Fulldomain == null)
{
_log.Error("Registration for domain {domain} appears invalid", domain);
- return;
+ return false;
}
if (!await VerifyCname(domain, reg.Fulldomain, 0))
{
@@ -233,10 +234,12 @@ namespace PKISharp.WACS.Clients
JsonConvert.SerializeObject(request),
Encoding.UTF8,
"application/json"));
+ return true;
}
catch (Exception ex)
{
_log.Error(ex, "Error sending update request to acme-dns server at {baseUri} for domain {domain}", _baseUri, domain);
+ return false;
}
}
diff --git a/src/main.lib/Clients/DNS/LookupClientProvider.cs b/src/main.lib/Clients/DNS/LookupClientProvider.cs
index 933897b..806fff7 100644
--- a/src/main.lib/Clients/DNS/LookupClientProvider.cs
+++ b/src/main.lib/Clients/DNS/LookupClientProvider.cs
@@ -121,14 +121,16 @@ namespace PKISharp.WACS.Clients.DNS
public class DnsLookupResult
{
- public DnsLookupResult(string domain, IEnumerable<LookupClientWrapper> nameServers)
+ public DnsLookupResult(string domain, IEnumerable<LookupClientWrapper> nameServers, DnsLookupResult? cnameFrom = null)
{
Nameservers = nameServers;
Domain = domain;
+ From = cnameFrom;
}
public IEnumerable<LookupClientWrapper> Nameservers { get; set; }
public string Domain { get; set; }
+ public DnsLookupResult? From { get; set; }
}
/// <summary>
@@ -137,7 +139,7 @@ namespace PKISharp.WACS.Clients.DNS
/// <param name="domainName"></param>
/// <param name="round"></param>
/// <returns></returns>
- public async Task<DnsLookupResult> GetAuthority(string domainName, int round = 0, bool followCnames = true)
+ public async Task<DnsLookupResult> GetAuthority(string domainName, int round = 0, bool followCnames = true, DnsLookupResult? from = null)
{
var key = domainName.ToLower().TrimEnd('.');
if (!_authoritativeNs.ContainsKey(key))
@@ -185,7 +187,7 @@ namespace PKISharp.WACS.Clients.DNS
var cname = await client.GetCname(testZone);
if (cname != null)
{
- return await GetAuthority(cname, round);
+ return await GetAuthority(cname, round, true, Produce(key, from));
}
}
@@ -212,7 +214,9 @@ namespace PKISharp.WACS.Clients.DNS
_authoritativeNs.Add(key, _defaultNs);
}
}
- return new DnsLookupResult(key, _authoritativeNs[key].Select(ip => Produce(ip)));
+ return Produce(key, from);
}
+
+ private DnsLookupResult Produce(string key, DnsLookupResult? parent = null) => new DnsLookupResult(key, _authoritativeNs[key].Select(ip => Produce(ip)), parent);
}
} \ No newline at end of file
diff --git a/src/main.lib/Clients/IIS/IISClient.cs b/src/main.lib/Clients/IIS/IISClient.cs
index a0b82ee..6830086 100644
--- a/src/main.lib/Clients/IIS/IISClient.cs
+++ b/src/main.lib/Clients/IIS/IISClient.cs
@@ -201,10 +201,10 @@ namespace PKISharp.WACS.Clients.IIS
public void AddBinding(IISSiteWrapper site, BindingOptions options)
{
var newBinding = site.Site.Bindings.CreateElement("binding");
- newBinding.Protocol = "https";
newBinding.BindingInformation = options.Binding;
newBinding.CertificateStoreName = options.Store;
newBinding.CertificateHash = options.Thumbprint;
+ newBinding.Protocol = "https";
if (options.Flags > 0)
{
newBinding.SetAttributeValue("sslFlags", options.Flags);
@@ -223,10 +223,10 @@ namespace PKISharp.WACS.Clients.IIS
"certificateHash"
};
var replacement = site.Site.Bindings.CreateElement("binding");
- replacement.Protocol = existingBinding.Protocol;
replacement.BindingInformation = existingBinding.BindingInformation;
replacement.CertificateStoreName = options.Store;
replacement.CertificateHash = options.Thumbprint;
+ replacement.Protocol = existingBinding.Protocol;
foreach (var attr in existingBinding.Binding.Attributes)
{
try
diff --git a/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptionsFactory.cs b/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptionsFactory.cs
index 97a7e2d..97aaf95 100644
--- a/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptionsFactory.cs
+++ b/src/main.lib/Plugins/StorePlugins/CentralSsl/CentralSslOptionsFactory.cs
@@ -43,7 +43,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins
}
if (string.IsNullOrEmpty(password))
{
- password = await input.ReadPassword("Password to use for the PFX files, or <ENTER> for none");
+ password = await input.ReadPassword("Password to use for the .pfx files, or <Enter> for none");
}
return Create(path, password, args?.KeepExisting ?? false);
}
diff --git a/src/main.lib/Plugins/StorePlugins/PfxFile/PfxFileOptionsFactory.cs b/src/main.lib/Plugins/StorePlugins/PfxFile/PfxFileOptionsFactory.cs
index 53c3ede..8cc998e 100644
--- a/src/main.lib/Plugins/StorePlugins/PfxFile/PfxFileOptionsFactory.cs
+++ b/src/main.lib/Plugins/StorePlugins/PfxFile/PfxFileOptionsFactory.cs
@@ -43,7 +43,7 @@ namespace PKISharp.WACS.Plugins.StorePlugins
}
if (string.IsNullOrEmpty(password))
{
- password = await input.ReadPassword("Password to use for the .pfx files or <ENTER> for none");
+ password = await input.ReadPassword("Password to use for the .pfx files or <Enter> for none");
}
return Create(path, password);
}
diff --git a/src/main.lib/Plugins/TargetPlugins/Csr/CsrOptionsFactory.cs b/src/main.lib/Plugins/TargetPlugins/Csr/CsrOptionsFactory.cs
index 25b1e43..b631528 100644
--- a/src/main.lib/Plugins/TargetPlugins/Csr/CsrOptionsFactory.cs
+++ b/src/main.lib/Plugins/TargetPlugins/Csr/CsrOptionsFactory.cs
@@ -36,7 +36,7 @@ namespace PKISharp.WACS.Plugins.TargetPlugins
{
pkFile = await _arguments.TryGetArgument(args?.CsrFile,
inputService,
- "Enter the path to the corresponding private key, or <ENTER> to create a certificate without one");
+ "Enter the path to the corresponding private key, or <Enter> to create a certificate without one");
}
while (!(string.IsNullOrWhiteSpace(pkFile) || pkFile.ValidFile(_log)));
diff --git a/src/main.lib/Plugins/TargetPlugins/IIS/IISOptionsFactory.cs b/src/main.lib/Plugins/TargetPlugins/IIS/IISOptionsFactory.cs
index f382169..1ce1d1c 100644
--- a/src/main.lib/Plugins/TargetPlugins/IIS/IISOptionsFactory.cs
+++ b/src/main.lib/Plugins/TargetPlugins/IIS/IISOptionsFactory.cs
@@ -139,7 +139,7 @@ namespace PKISharp.WACS.Plugins.TargetPlugins
description: $"{x.Name} ({x.Hosts.Count()} binding{(x.Hosts.Count() == 1 ? "" : "s")})",
command: x.Id.ToString(),
color: x.Https ? ConsoleColor.DarkGray : (ConsoleColor?)null)));
- var raw = await input.RequestString("Site identifier(s) or <ENTER> to choose all");
+ var raw = await input.RequestString("Site identifier(s) or <Enter> to choose all");
if (!ParseSiteOptions(raw, allSites, options))
{
return null;
diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Acme/Acme.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Acme/Acme.cs
index aa03b6e..ddcff59 100644
--- a/src/main.lib/Plugins/ValidationPlugins/Dns/Acme/Acme.cs
+++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Acme/Acme.cs
@@ -34,10 +34,10 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
/// </summary>
/// <param name="recordName"></param>
/// <param name="token"></param>
- public override async Task CreateRecord(string recordName, string token)
+ public override async Task<bool> CreateRecord(string recordName, string token)
{
var client = new AcmeDnsClient(_dnsClient, _proxy, _log, _settings, _input, new Uri(_options.BaseUri));
- await client.Update(_identifier, token);
+ return await client.Update(_identifier, token);
}
public override Task DeleteRecord(string recordName, string token) => Task.CompletedTask;
diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/DnsValidation.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/DnsValidation.cs
index 98c8b25..87e5273 100644
--- a/src/main.lib/Plugins/ValidationPlugins/Dns/DnsValidation.cs
+++ b/src/main.lib/Plugins/ValidationPlugins/Dns/DnsValidation.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using static PKISharp.WACS.Clients.DNS.LookupClientProvider;
namespace PKISharp.WACS.Plugins.ValidationPlugins
{
@@ -17,7 +18,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins
protected readonly LookupClientProvider _dnsClient;
protected readonly ILogService _log;
protected readonly ISettingsService _settings;
- private string? _recordName;
+ private DnsLookupResult? _authority;
protected DnsValidation(
LookupClientProvider dnsClient,
@@ -32,29 +33,26 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins
public override async Task PrepareChallenge()
{
// Check for substitute domains
- if (_settings.Validation.AllowDnsSubstitution)
+ _authority = await _dnsClient.GetAuthority(
+ Challenge.DnsRecordName,
+ followCnames: _settings.Validation.AllowDnsSubstitution);
+
+ var success = false;
+ while (!success)
{
- try
+ success = await CreateRecord(_authority.Domain, Challenge.DnsRecordValue);
+ if (!success)
{
- // Resolve CNAME in DNS
- var result = await _dnsClient.GetAuthority(Challenge.DnsRecordName);
-
- // Substitute
- if (result.Domain != Challenge.DnsRecordName)
+ if (_authority.From == null)
{
- _log.Information("Detected that {DnsRecordName} is a CNAME that leads to {cname}", Challenge.DnsRecordName, result.Domain);
- _recordName = result.Domain;
+ throw new Exception("Unable to prepare for challenge answer");
+ }
+ else
+ {
+ _authority = _authority.From;
}
}
- catch (Exception ex)
- {
- _log.Debug("Error checking for substitute domains: {ex}", ex.Message);
- }
- }
-
- // Create record
- await CreateRecord(_recordName ?? Challenge.DnsRecordName, Challenge.DnsRecordValue);
- _log.Information("Answer should now be available at {answerUri}", _recordName ?? Challenge.DnsRecordName);
+ }
// Verify that the record was created succesfully and wait for possible
// propagation/caching/TTL issues to resolve themselves naturally
@@ -63,7 +61,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins
var retrySeconds = _settings.Validation.PreValidateDnsRetryInterval;
while (_settings.Validation.PreValidateDns)
{
- if (await PreValidate(retry))
+ if (await PreValidate())
{
break;
}
@@ -84,23 +82,19 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins
}
}
- protected async Task<bool> PreValidate(int attempt)
+ protected async Task<bool> PreValidate()
{
try
{
- var actualDomain = _recordName ?? Challenge.DnsRecordName;
- var authority = await _dnsClient.GetAuthority(actualDomain, attempt, true);
- // This should not be possible because authority was supposed to be
- // checked recursively in the PrepareChallenge phase
- if (authority.Domain != actualDomain)
+ if (_authority == null)
{
- _log.Error("Unexpected authority");
+ throw new InvalidOperationException("_recordName is null");
}
- _log.Debug("Looking for TXT value {DnsRecordValue}...", actualDomain);
- foreach (var client in authority.Nameservers)
+ _log.Debug("Looking for TXT value {DnsRecordValue}...", _authority.Domain);
+ foreach (var client in _authority.Nameservers)
{
_log.Debug("Preliminary validation asking {ip}...", client.IpAddress);
- var answers = await client.GetTxtRecords(Challenge.DnsRecordName);
+ var answers = await client.GetTxtRecords(_authority.Domain);
if (!answers.Any())
{
_log.Warning("Preliminary validation failed: no TXT records found");
@@ -129,9 +123,16 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins
/// </summary>
public override async Task CleanUp()
{
- if (HasChallenge)
+ if (HasChallenge && _authority != null)
{
- await DeleteRecord(_recordName ?? Challenge.DnsRecordName, Challenge.DnsRecordValue);;
+ try
+ {
+ await DeleteRecord(_authority.Domain, Challenge.DnsRecordValue);
+ }
+ catch (Exception ex)
+ {
+ _log.Warning($"Error deleting record: {ex.Message}");
+ }
}
}
@@ -146,7 +147,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins
/// </summary>
/// <param name="recordName">Name of the record</param>
/// <param name="token">Contents of the record</param>
- public abstract Task CreateRecord(string recordName, string token);
+ public abstract Task<bool> CreateRecord(string recordName, string token);
/// <summary>
/// Match DNS zone to use from a list of all zones
diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Manual/Manual.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Manual/Manual.cs
index e112ed1..c584efb 100644
--- a/src/main.lib/Plugins/ValidationPlugins/Dns/Manual/Manual.cs
+++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Manual/Manual.cs
@@ -25,7 +25,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
_identifier = identifier;
}
- public override async Task CreateRecord(string recordName, string token)
+ public override async Task<bool> CreateRecord(string recordName, string token)
{
_input.CreateSpace();
_input.Show("Domain", _identifier);
@@ -33,14 +33,18 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
_input.Show("Type", "TXT");
_input.Show("Content", $"\"{token}\"");
_input.Show("Note", "Some DNS managers add quotes automatically. A single set is needed.");
- await _input.Wait("Please press <Enter> after you've created and verified the record");
+ if (!await _input.Wait("Please press <Enter> after you've created and verified the record"))
+ {
+ _log.Warning("User aborted");
+ return false;
+ }
// Pre-pre-validate, allowing the manual user to correct mistakes
while (true)
{
- if (await PreValidate(0))
+ if (await PreValidate())
{
- break;
+ return true;
}
else
{
@@ -51,7 +55,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
"try ACME validation anyway.", true);
if (!retry)
{
- break;
+ return false;
}
}
}
diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/Script.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/Script.cs
index 6b7b34b..80ece5e 100644
--- a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/Script.cs
+++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/Script.cs
@@ -28,7 +28,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
_scriptClient = client;
}
- public override async Task CreateRecord(string recordName, string token)
+ public override async Task<bool> CreateRecord(string recordName, string token)
{
var script = _options.Script ?? _options.CreateScript;
if (!string.IsNullOrWhiteSpace(script))
@@ -39,10 +39,12 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
args = _options.CreateScriptArguments;
}
await _scriptClient.RunScript(script, ProcessArguments(recordName, token, args, script.EndsWith(".ps1")));
+ return true;
}
else
{
_log.Error("No create script configured");
+ return false;
}
}
diff --git a/src/main.lib/RenewalCreator.cs b/src/main.lib/RenewalCreator.cs
index 823265d..404ee76 100644
--- a/src/main.lib/RenewalCreator.cs
+++ b/src/main.lib/RenewalCreator.cs
@@ -158,7 +158,7 @@ namespace PKISharp.WACS
}
else if (runLevel.HasFlag(RunLevel.Advanced | RunLevel.Interactive))
{
- var alt = await _input.RequestString($"Suggested friendly name '{initialTarget.FriendlyName}', press <ENTER> to accept or type an alternative");
+ var alt = await _input.RequestString($"Suggested friendly name '{initialTarget.FriendlyName}', press <Enter> to accept or type an alternative");
if (!string.IsNullOrEmpty(alt))
{
tempRenewal.FriendlyName = alt;
diff --git a/src/main.lib/Wacs.cs b/src/main.lib/Wacs.cs
index d267b4c..be8faf9 100644
--- a/src/main.lib/Wacs.cs
+++ b/src/main.lib/Wacs.cs
@@ -235,7 +235,7 @@ namespace PKISharp.WACS.Host
{
var total = _renewalStore.Renewals.Count();
var due = _renewalStore.Renewals.Count(x => x.IsDue());
- var error = _renewalStore.Renewals.Count(x => !x.History.Last().Success);
+ var error = _renewalStore.Renewals.Count(x => !x.History.LastOrDefault()?.Success ?? false);
var (allowIIS, allowIISReason) = _userRoleService.AllowIIS;
var options = new List<Choice<Func<Task>>>
{
diff --git a/src/plugin.validation.dns.azure/Azure.cs b/src/plugin.validation.dns.azure/Azure.cs
index cfaf575..2d8c1e0 100755
--- a/src/plugin.validation.dns.azure/Azure.cs
+++ b/src/plugin.validation.dns.azure/Azure.cs
@@ -33,11 +33,14 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
_proxyService = proxyService;
}
- public override async Task CreateRecord(string recordName, string token)
+ public override async Task<bool> CreateRecord(string recordName, string token)
{
var client = await GetClient();
var zone = await GetHostedZone(recordName);
- var subDomain = recordName.Substring(0, recordName.LastIndexOf(zone)).TrimEnd('.');
+ if (zone == null)
+ {
+ return false;
+ }
// Create record set parameters
var recordSetParams = new RecordSet
@@ -49,11 +52,20 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
}
};
- _ = await client.RecordSets.CreateOrUpdateAsync(_options.ResourceGroupName,
- zone,
- subDomain,
- RecordType.TXT,
- recordSetParams);
+ try
+ {
+ _ = await client.RecordSets.CreateOrUpdateAsync(_options.ResourceGroupName,
+ zone,
+ RelativeRecordName(zone, recordName),
+ RecordType.TXT,
+ recordSetParams);
+ }
+ catch (Exception ex)
+ {
+ _log.Error(ex, "Error updating record in Azure");
+ return false;
+ }
+ return true;
}
private async Task<DnsManagementClient> GetClient()
@@ -85,6 +97,12 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
}
return _azureDnsClient;
}
+ private string RelativeRecordName(string zone, string recordName)
+ {
+ var ret = recordName.Substring(0, recordName.LastIndexOf(zone)).TrimEnd('.');
+ return string.IsNullOrEmpty(ret) ? "@" : ret;
+ }
+
private async Task<string> GetHostedZone(string recordName)
{
@@ -107,19 +125,25 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
"Can't find hosted zone for {recordName} in resource group {ResourceGroupName}",
recordName,
_options.ResourceGroupName);
- throw new Exception();
+ return null;
}
public override async Task DeleteRecord(string recordName, string token)
{
var client = await GetClient();
var zone = await GetHostedZone(recordName);
- var subDomain = recordName.Substring(0, recordName.LastIndexOf(zone)).TrimEnd('.');
- await client.RecordSets.DeleteAsync(
- _options.ResourceGroupName,
- zone,
- subDomain,
- RecordType.TXT);
+ try
+ {
+ await client.RecordSets.DeleteAsync(
+ _options.ResourceGroupName,
+ zone,
+ RelativeRecordName(zone, recordName),
+ RecordType.TXT);
+ }
+ catch (Exception ex)
+ {
+ _log.Error(ex, "Error deleting record from Azure");
+ }
}
}
}
diff --git a/src/plugin.validation.dns.cloudflare/Cloudflare.cs b/src/plugin.validation.dns.cloudflare/Cloudflare.cs
index 380629b..e770735 100644
--- a/src/plugin.validation.dns.cloudflare/Cloudflare.cs
+++ b/src/plugin.validation.dns.cloudflare/Cloudflare.cs
@@ -54,22 +54,24 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
return zonesResp.Unpack().First();
}
- public override async Task CreateRecord(string recordName, string token)
+ public override async Task<bool> CreateRecord(string recordName, string token)
{
var ctx = GetContext();
var zone = await GetHostedZone(ctx, recordName).ConfigureAwait(false);
if (zone == null)
{
- throw new InvalidOperationException($"The zone could not be found using the Cloudflare API, thus creating a DNS validation record is impossible. " +
+ _log.Error("The zone could not be found using the Cloudflare API, thus creating a DNS validation record is impossible. " +
$"Please note you need to use an API Token, not the Global API Key. The token needs the permissions Zone.Zone:Read and Zone.DNS:Edit. Regarding " +
$"Zone:Read it is important, that this token has access to all zones in your account (Zone Resources > Include > All zones) because we need to " +
$"list your zones. Read the docs carefully for instructions.");
+ return false;
}
var dns = ctx.Zone(zone).Dns;
_ = await dns.Create(DnsRecordType.TXT, recordName, token)
.CallAsync(_hc)
.ConfigureAwait(false);
+ return true;
}
private async Task DeleteRecord(string recordName, string token, IAuthorizedSyntax context, Zone zone)
@@ -86,12 +88,21 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
var record = records.FirstOrDefault();
if (record == null)
{
- throw new Exception($"The record {recordName} that should be deleted does not exist at Cloudflare.");
+ _log.Warning($"The record {recordName} that should be deleted does not exist at Cloudflare.");
+ return;
+ }
+
+ try
+ {
+ _ = await dns.Delete(record.Id)
+ .CallAsync(_hc)
+ .ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _log.Warning($"Unable to delete record from Cloudflare: {ex.Message}");
}
- _ = await dns.Delete(record.Id)
- .CallAsync(_hc)
- .ConfigureAwait(false);
}
public override async Task DeleteRecord(string recordName, string token)
diff --git a/src/plugin.validation.dns.dreamhost/DreamhostDnsValidation.cs b/src/plugin.validation.dns.dreamhost/DreamhostDnsValidation.cs
index 8c971b5..2e6e5db 100644
--- a/src/plugin.validation.dns.dreamhost/DreamhostDnsValidation.cs
+++ b/src/plugin.validation.dns.dreamhost/DreamhostDnsValidation.cs
@@ -1,6 +1,7 @@
using PKISharp.WACS.Clients.DNS;
using PKISharp.WACS.Plugins.ValidationPlugins.Dreamhost;
using PKISharp.WACS.Services;
+using System;
using System.Threading.Tasks;
namespace PKISharp.WACS.Plugins.ValidationPlugins
@@ -17,8 +18,29 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins
: base(dnsClient, logService, settings)
=> _client = new DnsManagementClient(options.ApiKey.Value, logService);
- public override Task CreateRecord(string recordName, string token) => _client.CreateRecord(recordName, RecordType.TXT, token);
+ public override async Task<bool> CreateRecord(string recordName, string token)
+ {
+ try
+ {
+ await _client.CreateRecord(recordName, RecordType.TXT, token);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
- public override Task DeleteRecord(string recordName, string token) => _client.DeleteRecord(recordName, RecordType.TXT, token);
+ public override async Task DeleteRecord(string recordName, string token)
+ {
+ try
+ {
+ await _client.DeleteRecord(recordName, RecordType.TXT, token);
+ }
+ catch (Exception ex)
+ {
+ _log.Warning($"Unable to delete record from Dreamhost: {ex.Message}");
+ }
+ }
}
}
diff --git a/src/plugin.validation.dns.luadns/luadns.cs b/src/plugin.validation.dns.luadns/luadns.cs
index f7c90d4..4935681 100644
--- a/src/plugin.validation.dns.luadns/luadns.cs
+++ b/src/plugin.validation.dns.luadns/luadns.cs
@@ -64,7 +64,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
_apiKey = options.APIKey.Value;
}
- public override async Task CreateRecord(string recordName, string token)
+ public override async Task<bool> CreateRecord(string recordName, string token)
{
_log.Information("Creating LuaDNS verification record");
@@ -72,8 +72,8 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
var response = await client.GetAsync(new Uri(_LuaDnsApiEndpoint, "zones"));
if (!response.IsSuccessStatusCode)
{
- _log.Information("Failed to get DNS zones list for account. Aborting.");
- return;
+ _log.Error("Failed to get DNS zones list for account. Aborting.");
+ return false;
}
var payload = await response.Content.ReadAsStringAsync();
@@ -81,8 +81,8 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
var targetZone = FindBestMatch(zones.ToDictionary(x => x.Name), recordName);
if (targetZone == null)
{
- _log.Information("No matching zone found in LuaDNS account. Aborting");
- return;
+ _log.Error("No matching zone found in LuaDNS account. Aborting");
+ return false;
}
var newRecord = new RecordData { Name = $"{recordName}.", Type = "TXT", Content = token, TTL = 300 };
@@ -91,24 +91,21 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
response = await client.PostAsync(new Uri(_LuaDnsApiEndpoint, $"zones/{targetZone.Id}/records"), new StringContent(payload, Encoding.UTF8, "application/json"));
if (!response.IsSuccessStatusCode)
{
- _log.Information("Failed to create DNS verification record");
- return;
+ _log.Error("Failed to create DNS verification record");
+ return false;
}
payload = await response.Content.ReadAsStringAsync();
newRecord = JsonSerializer.Deserialize<RecordData>(payload);
-
_recordsMap[recordName] = newRecord;
-
- _log.Information("DNS Record created. Waiting 30 seconds to allow propagation.");
- await Task.Delay(30000);
+ return true;
}
public override async Task DeleteRecord(string recordName, string token)
{
if (!_recordsMap.ContainsKey(recordName))
{
- _log.Information($"No record with name {recordName} was created");
+ _log.Warning($"No record with name {recordName} was created");
return;
}
@@ -118,7 +115,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
var response = await client.DeleteAsync(new Uri(_LuaDnsApiEndpoint, $"zones/{_recordsMap[recordName].ZoneId}/records/{_recordsMap[recordName].Id}"));
if (!response.IsSuccessStatusCode)
{
- _log.Information("Failed to delete DNS verification record");
+ _log.Warning("Failed to delete DNS verification record");
return;
}
diff --git a/src/plugin.validation.dns.route53/Route53.cs b/src/plugin.validation.dns.route53/Route53.cs
index 2db2129..a2d490c 100644
--- a/src/plugin.validation.dns.route53/Route53.cs
+++ b/src/plugin.validation.dns.route53/Route53.cs
@@ -48,19 +48,32 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
};
}
- public override async Task CreateRecord(string recordName, string token)
+ public override async Task<bool> CreateRecord(string recordName, string token)
{
- var hostedZoneId = await GetHostedZoneId(recordName);
- _log.Information("Creating TXT record {recordName} with value {token}", recordName, token);
- var response = await _route53Client.ChangeResourceRecordSetsAsync(
- new ChangeResourceRecordSetsRequest(
- hostedZoneId,
- new ChangeBatch(new List<Change> {
+ try
+ {
+ var hostedZoneId = await GetHostedZoneId(recordName);
+ if (hostedZoneId == null)
+ {
+ return false;
+ }
+ _log.Information("Creating TXT record {recordName} with value {token}", recordName, token);
+ var response = await _route53Client.ChangeResourceRecordSetsAsync(
+ new ChangeResourceRecordSetsRequest(
+ hostedZoneId,
+ new ChangeBatch(new List<Change> {
new Change(
ChangeAction.UPSERT,
CreateResourceRecordSet(recordName, token))
- })));
- await WaitChangesPropagation(response.ChangeInfo);
+ })));
+ await WaitChangesPropagation(response.ChangeInfo);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _log.Warning($"Error creating TXT record: {ex.Message}");
+ return false;
+ }
}
public override async Task DeleteRecord(string recordName, string token)
@@ -70,9 +83,9 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
_ = await _route53Client.ChangeResourceRecordSetsAsync(
new ChangeResourceRecordSetsRequest(hostedZoneId,
new ChangeBatch(new List<Change> {
- new Change(
- ChangeAction.DELETE,
- CreateResourceRecordSet(recordName, token))
+ new Change(
+ ChangeAction.DELETE,
+ CreateResourceRecordSet(recordName, token))
})));
}
@@ -97,7 +110,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
return hostedZone.Id;
}
_log.Error($"Can't find hosted zone for domain {recordName}");
- throw new Exception();
+ return null;
}
private async Task WaitChangesPropagation(ChangeInfo changeInfo)
@@ -113,7 +126,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
while ((await _route53Client.GetChangeAsync(changeRequest)).ChangeInfo.Status == ChangeStatus.PENDING)
{
- await Task.Delay(5000);
+ await Task.Delay(2000);
}
}
}