diff --git a/KeyVault.Acmebot/Functions/SharedActivity.cs b/KeyVault.Acmebot/Functions/SharedActivity.cs index ea957608..ef57c46e 100644 --- a/KeyVault.Acmebot/Functions/SharedActivity.cs +++ b/KeyVault.Acmebot/Functions/SharedActivity.cs @@ -103,7 +103,7 @@ public async Task> GetZones([ActivityTrigger] object input { var zones = await _dnsProviders.ListAllZonesAsync(); - return zones.Select(x => x.Name).ToArray(); + return zones.OrderBy(x => x.DnsProvider.Name).Select(x => x.Name).ToArray(); } catch { @@ -252,11 +252,11 @@ public async Task Dns01Precondition([ActivityTrigger] IReadOnlyList dnsN // Challenge の詳細から DNS 向けにレコード名を作成 var acmeDnsRecordName = dnsRecordName.Replace($".{zone.Name}", "", StringComparison.OrdinalIgnoreCase); - await zone.Provider.DeleteTxtRecordAsync(zone, acmeDnsRecordName); - await zone.Provider.CreateTxtRecordAsync(zone, acmeDnsRecordName, lookup.Select(x => x.DnsRecordValue)); + await zone.DnsProvider.DeleteTxtRecordAsync(zone, acmeDnsRecordName); + await zone.DnsProvider.CreateTxtRecordAsync(zone, acmeDnsRecordName, lookup.Select(x => x.DnsRecordValue)); // 一番時間のかかる DNS Provider に合わせる - propagationSeconds = Math.Max(propagationSeconds, zone.Provider.PropagationSeconds); + propagationSeconds = Math.Max(propagationSeconds, zone.DnsProvider.PropagationSeconds); } return (challengeResults, propagationSeconds); @@ -446,7 +446,7 @@ public async Task CleanupDnsChallenge([ActivityTrigger] IReadOnlyListv4 - + @@ -12,7 +12,7 @@ - + diff --git a/KeyVault.Acmebot/Providers/AzureDnsProvider.cs b/KeyVault.Acmebot/Providers/AzureDnsProvider.cs index 4f662110..8f9c99b3 100644 --- a/KeyVault.Acmebot/Providers/AzureDnsProvider.cs +++ b/KeyVault.Acmebot/Providers/AzureDnsProvider.cs @@ -22,6 +22,8 @@ public AzureDnsProvider(AzureDnsOptions options, AzureEnvironment environment, T private readonly ArmClient _armClient; + public string Name => "Azure DNS"; + public int PropagationSeconds => 10; public async Task> ListZonesAsync() diff --git a/KeyVault.Acmebot/Providers/AzurePrivateDnsProvider.cs b/KeyVault.Acmebot/Providers/AzurePrivateDnsProvider.cs index b7bfeed9..201ea2e2 100644 --- a/KeyVault.Acmebot/Providers/AzurePrivateDnsProvider.cs +++ b/KeyVault.Acmebot/Providers/AzurePrivateDnsProvider.cs @@ -22,6 +22,8 @@ public AzurePrivateDnsProvider(AzurePrivateDnsOptions options, AzureEnvironment private readonly ArmClient _armClient; + public string Name => "Azure Private DNS"; + public int PropagationSeconds => 10; public async Task> ListZonesAsync() diff --git a/KeyVault.Acmebot/Providers/CloudflareProvider.cs b/KeyVault.Acmebot/Providers/CloudflareProvider.cs index 5bdc8a81..c809d623 100644 --- a/KeyVault.Acmebot/Providers/CloudflareProvider.cs +++ b/KeyVault.Acmebot/Providers/CloudflareProvider.cs @@ -21,6 +21,8 @@ public CloudflareProvider(CloudflareOptions options) private readonly CloudflareDnsClient _cloudflareDnsClient; + public string Name => "Cloudflare"; + public int PropagationSeconds => 10; public async Task> ListZonesAsync() @@ -61,7 +63,7 @@ public CloudflareDnsClient(string apiToken) { _httpClient = new HttpClient { - BaseAddress = new Uri("https://api.cloudflare.com") + BaseAddress = new Uri("https://api.cloudflare.com/client/v4/") }; _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); @@ -90,7 +92,7 @@ public async Task> ListAllZonesAsync() public async Task> GetDnsRecordsAsync(string zone, string name) { - var response = await _httpClient.GetAsync($"/client/v4/zones/{zone}/dns_records?type=TXT&name={name}&per_page=100"); + var response = await _httpClient.GetAsync($"zones/{zone}/dns_records?type=TXT&name={name}&per_page=100"); response.EnsureSuccessStatusCode(); @@ -101,21 +103,21 @@ public async Task> GetDnsRecordsAsync(string zone public async Task CreateDnsRecordAsync(string zone, string name, string content) { - var response = await _httpClient.PostAsync($"/client/v4/zones/{zone}/dns_records", new { type = "TXT", name, content, ttl = 60 }); + var response = await _httpClient.PostAsync($"zones/{zone}/dns_records", new { type = "TXT", name, content, ttl = 60 }); response.EnsureSuccessStatusCode(); } public async Task DeleteDnsRecordAsync(string zone, string id) { - var response = await _httpClient.DeleteAsync($"/client/v4/zones/{zone}/dns_records/{id}"); + var response = await _httpClient.DeleteAsync($"zones/{zone}/dns_records/{id}"); response.EnsureSuccessStatusCode(); } private async Task> ListZonesAsync(int page) { - var response = await _httpClient.GetAsync($"/client/v4/zones?page={page}&per_page=50&status=active"); + var response = await _httpClient.GetAsync($"zones?page={page}&per_page=50&status=active"); response.EnsureSuccessStatusCode(); diff --git a/KeyVault.Acmebot/Providers/CustomDnsProvider.cs b/KeyVault.Acmebot/Providers/CustomDnsProvider.cs index f41dfe77..ada57434 100644 --- a/KeyVault.Acmebot/Providers/CustomDnsProvider.cs +++ b/KeyVault.Acmebot/Providers/CustomDnsProvider.cs @@ -29,6 +29,8 @@ public CustomDnsProvider(CustomDnsOptions options) private readonly HttpClient _httpClient; + public string Name => "Custom DNS"; + public int PropagationSeconds { get; } public async Task> ListZonesAsync() @@ -60,7 +62,7 @@ public async Task DeleteTxtRecordAsync(DnsZone zone, string relativeRecordName) response.EnsureSuccessStatusCode(); } - public class Zone + private class Zone { [JsonProperty("id")] public string Id { get; set; } diff --git a/KeyVault.Acmebot/Providers/DnsMadeEasyProvider.cs b/KeyVault.Acmebot/Providers/DnsMadeEasyProvider.cs index 4dbb1c56..0780a918 100644 --- a/KeyVault.Acmebot/Providers/DnsMadeEasyProvider.cs +++ b/KeyVault.Acmebot/Providers/DnsMadeEasyProvider.cs @@ -25,6 +25,8 @@ public DnsMadeEasyProvider(DnsMadeEasyOptions options) private readonly DnsMadeEasyClient _client; + public string Name => "DNS Made Easy"; + public int PropagationSeconds => 10; public async Task> ListZonesAsync() @@ -52,7 +54,7 @@ public async Task DeleteTxtRecordAsync(DnsZone zone, string relativeRecordName) { var records = await _client.ListRecordsAsync(zone.Id); - var recordsToDelete = records.Where(r => r.Name == relativeRecordName && r.Type == "TXT"); + var recordsToDelete = records.Where(x => x.Name == relativeRecordName && x.Type == "TXT"); foreach (var record in recordsToDelete) { @@ -66,7 +68,7 @@ public DnsMadeEasyClient(string apiKey, string secretKey) { _httpClient = new HttpClient(new ApiKeyHandler(apiKey, secretKey, new HttpClientHandler())) { - BaseAddress = new Uri("https://api.dnsmadeeasy.com/V2.0/") + BaseAddress = new Uri("https://api.dnsmadeeasy.com/V2.0/dns/") }; _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); @@ -76,7 +78,7 @@ public DnsMadeEasyClient(string apiKey, string secretKey) public async Task> ListZonesAsync() { - var response = await _httpClient.GetAsync("dns/managed"); + var response = await _httpClient.GetAsync("managed"); response.EnsureSuccessStatusCode(); @@ -87,7 +89,7 @@ public async Task> ListZonesAsync() public async Task> ListRecordsAsync(string zoneId) { - var response = await _httpClient.GetAsync($"dns/managed/{zoneId}/records"); + var response = await _httpClient.GetAsync($"managed/{zoneId}/records"); response.EnsureSuccessStatusCode(); @@ -98,14 +100,14 @@ public async Task> ListRecordsAsync(string zoneId) public async Task DeleteRecordAsync(string zoneId, DnsEntry entry) { - var response = await _httpClient.DeleteAsync($"dns/managed/{zoneId}/records/{entry.Id}"); + var response = await _httpClient.DeleteAsync($"managed/{zoneId}/records/{entry.Id}"); response.EnsureSuccessStatusCode(); } public async Task AddRecordAsync(string zoneId, DnsEntry entry) { - var response = await _httpClient.PostAsync($"dns/managed/{zoneId}/records", entry); + var response = await _httpClient.PostAsync($"managed/{zoneId}/records", entry); response.EnsureSuccessStatusCode(); } @@ -120,20 +122,9 @@ private sealed class ApiKeyHandler : DelegatingHandler public ApiKeyHandler(string apiKey, string secretKey, HttpMessageHandler innerHandler) : base(innerHandler) { - if (apiKey is null) - { - throw new ArgumentNullException(nameof(apiKey)); - } - - if (secretKey is null) - { - throw new ArgumentNullException(nameof(secretKey)); - } - - if (innerHandler is null) - { - throw new ArgumentNullException(nameof(innerHandler)); - } + ArgumentNullException.ThrowIfNull(apiKey); + ArgumentNullException.ThrowIfNull(secretKey); + ArgumentNullException.ThrowIfNull(innerHandler); if (string.IsNullOrWhiteSpace(apiKey)) { diff --git a/KeyVault.Acmebot/Providers/DnsZone.cs b/KeyVault.Acmebot/Providers/DnsZone.cs index dfccf6bf..ba40e4fe 100644 --- a/KeyVault.Acmebot/Providers/DnsZone.cs +++ b/KeyVault.Acmebot/Providers/DnsZone.cs @@ -8,7 +8,7 @@ public class DnsZone : IEquatable { public DnsZone(IDnsProvider dnsProvider) { - Provider = dnsProvider; + DnsProvider = dnsProvider; } private static readonly IdnMapping s_idnMapping = new(); @@ -25,7 +25,7 @@ public string Name public IReadOnlyList NameServers { get; init; } - public IDnsProvider Provider { get; } + public IDnsProvider DnsProvider { get; } public bool Equals(DnsZone other) { @@ -37,10 +37,7 @@ public bool Equals(DnsZone other) return Id == other.Id; } - public override bool Equals(object obj) - { - return Equals(obj as DnsZone); - } + public override bool Equals(object obj) => Equals(obj as DnsZone); public override int GetHashCode() => Id?.GetHashCode() ?? 0; } diff --git a/KeyVault.Acmebot/Providers/GandiProvider.cs b/KeyVault.Acmebot/Providers/GandiProvider.cs index ad3b7af3..484d2430 100644 --- a/KeyVault.Acmebot/Providers/GandiProvider.cs +++ b/KeyVault.Acmebot/Providers/GandiProvider.cs @@ -22,6 +22,8 @@ public GandiProvider(GandiOptions options) private readonly GandiClient _client; + public string Name => "Gandi LiveDNS"; + public int PropagationSeconds => 300; public async Task> ListZonesAsync() @@ -48,10 +50,7 @@ private class GandiClient { public GandiClient(string apiKey) { - if (apiKey is null) - { - throw new ArgumentNullException(nameof(apiKey)); - } + ArgumentNullException.ThrowIfNull(apiKey); _httpClient = new HttpClient { diff --git a/KeyVault.Acmebot/Providers/GoDaddyProvider.cs b/KeyVault.Acmebot/Providers/GoDaddyProvider.cs index 273a5f1d..a57f7849 100644 --- a/KeyVault.Acmebot/Providers/GoDaddyProvider.cs +++ b/KeyVault.Acmebot/Providers/GoDaddyProvider.cs @@ -22,6 +22,8 @@ public GoDaddyProvider(GoDaddyOptions options) private readonly GoDaddyClient _client; + public string Name => "GoDaddy"; + public int PropagationSeconds => 600; public async Task> ListZonesAsync() @@ -33,18 +35,7 @@ public async Task> ListZonesAsync() public Task CreateTxtRecordAsync(DnsZone zone, string relativeRecordName, IEnumerable values) { - var entries = new List(); - - foreach (var value in values) - { - entries.Add(new DnsEntry - { - Name = relativeRecordName, - Type = "TXT", - TTL = 600, - Data = value - }); - } + var entries = values.Select(x => new DnsEntry { Name = relativeRecordName, Type = "TXT", TTL = 600, Data = x }).ToArray(); return _client.AddRecordAsync(zone.Name, entries); } @@ -58,19 +49,12 @@ private class GoDaddyClient { public GoDaddyClient(string apiKey, string apiSecret) { - if (apiKey is null) - { - throw new ArgumentNullException(nameof(apiKey)); - } - - if (apiSecret is null) - { - throw new ArgumentNullException(nameof(apiSecret)); - } + ArgumentNullException.ThrowIfNull(apiKey); + ArgumentNullException.ThrowIfNull(apiSecret); _httpClient = new HttpClient { - BaseAddress = new Uri("https://api.godaddy.com") + BaseAddress = new Uri("https://api.godaddy.com/v1/") }; _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); @@ -88,7 +72,7 @@ public async Task> ListZonesAsync() while (true) { - var response = await _httpClient.GetAsync($"v1/domains?statuses=ACTIVE&includes=nameServers&limit={limit}{marker}"); + var response = await _httpClient.GetAsync($"domains?statuses=ACTIVE&includes=nameServers&limit={limit}{marker}"); response.EnsureSuccessStatusCode(); @@ -109,7 +93,7 @@ public async Task> ListZonesAsync() public async Task DeleteRecordAsync(string domain, string type, string name) { - var response = await _httpClient.DeleteAsync($"v1/domains/{domain}/records/{type}/{name}"); + var response = await _httpClient.DeleteAsync($"domains/{domain}/records/{type}/{name}"); if (response.StatusCode != HttpStatusCode.NotFound) { @@ -119,13 +103,13 @@ public async Task DeleteRecordAsync(string domain, string type, string name) public async Task AddRecordAsync(string domain, IReadOnlyList entries) { - var response = await _httpClient.PatchAsync($"v1/domains/{domain}/records", entries); + var response = await _httpClient.PatchAsync($"domains/{domain}/records", entries); response.EnsureSuccessStatusCode(); } } - public class ZoneDomain + private class ZoneDomain { [JsonProperty("domain")] public string Domain { get; set; } @@ -137,7 +121,7 @@ public class ZoneDomain public string[] NameServers { get; set; } } - public class DnsEntry + private class DnsEntry { [JsonProperty("data")] public string Data { get; set; } diff --git a/KeyVault.Acmebot/Providers/GoogleDnsProvider.cs b/KeyVault.Acmebot/Providers/GoogleDnsProvider.cs index dc2b52e5..5c9e2477 100644 --- a/KeyVault.Acmebot/Providers/GoogleDnsProvider.cs +++ b/KeyVault.Acmebot/Providers/GoogleDnsProvider.cs @@ -29,6 +29,8 @@ public GoogleDnsProvider(GoogleDnsOptions options) private readonly DnsService _dnsService; private readonly JsonCredentialParameters _credsParameters; + public string Name => "Google Cloud DNS"; + public int PropagationSeconds => 60; public async Task> ListZonesAsync() diff --git a/KeyVault.Acmebot/Providers/IDnsProvider.cs b/KeyVault.Acmebot/Providers/IDnsProvider.cs index 3c9ae540..f5a9cd78 100644 --- a/KeyVault.Acmebot/Providers/IDnsProvider.cs +++ b/KeyVault.Acmebot/Providers/IDnsProvider.cs @@ -5,6 +5,7 @@ namespace KeyVault.Acmebot.Providers; public interface IDnsProvider { + string Name { get; } int PropagationSeconds { get; } Task> ListZonesAsync(); Task CreateTxtRecordAsync(DnsZone zone, string relativeRecordName, IEnumerable values); diff --git a/KeyVault.Acmebot/Providers/Route53Provider.cs b/KeyVault.Acmebot/Providers/Route53Provider.cs index 10b31091..cbf25839 100644 --- a/KeyVault.Acmebot/Providers/Route53Provider.cs +++ b/KeyVault.Acmebot/Providers/Route53Provider.cs @@ -22,6 +22,8 @@ public Route53Provider(Route53Options options) private readonly AmazonRoute53Client _amazonRoute53Client; + public string Name => "Amazon Route 53"; + public int PropagationSeconds => 10; public async Task> ListZonesAsync() diff --git a/KeyVault.Acmebot/Providers/TransIpProvider.cs b/KeyVault.Acmebot/Providers/TransIpProvider.cs index bddf88aa..da4dc768 100644 --- a/KeyVault.Acmebot/Providers/TransIpProvider.cs +++ b/KeyVault.Acmebot/Providers/TransIpProvider.cs @@ -31,6 +31,8 @@ public TransIpProvider(AcmebotOptions acmeOptions, TransIpOptions options, Token private readonly TransIpClient _transIpClient; + public string Name => "TransIP DNS"; + public int PropagationSeconds => 360; public async Task> ListZonesAsync()