From 48fa8d094e89a4aeba73a6252d4a2913ba93abc0 Mon Sep 17 00:00:00 2001 From: Bastien Hubert Date: Fri, 24 Nov 2023 12:02:39 +0100 Subject: [PATCH 1/3] Add GandiLiveDns Provider to handle new api --- KeyVault.Acmebot/Options/AcmebotOptions.cs | 2 + .../Options/GandiLiveDnsOptions.cs | 7 + .../Providers/GandiLiveDnsProvider.cs | 156 ++++++++++++++++++ KeyVault.Acmebot/Startup.cs | 1 + 4 files changed, 166 insertions(+) create mode 100644 KeyVault.Acmebot/Options/GandiLiveDnsOptions.cs create mode 100644 KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs diff --git a/KeyVault.Acmebot/Options/AcmebotOptions.cs b/KeyVault.Acmebot/Options/AcmebotOptions.cs index bfae8ef1..4355e425 100644 --- a/KeyVault.Acmebot/Options/AcmebotOptions.cs +++ b/KeyVault.Acmebot/Options/AcmebotOptions.cs @@ -43,6 +43,8 @@ public class AcmebotOptions public GandiOptions Gandi { get; set; } + public GandiLiveDnsOptions GandiLiveDns { get; set; } + public GoDaddyOptions GoDaddy { get; set; } public GoogleDnsOptions GoogleDns { get; set; } diff --git a/KeyVault.Acmebot/Options/GandiLiveDnsOptions.cs b/KeyVault.Acmebot/Options/GandiLiveDnsOptions.cs new file mode 100644 index 00000000..0ec37a65 --- /dev/null +++ b/KeyVault.Acmebot/Options/GandiLiveDnsOptions.cs @@ -0,0 +1,7 @@ +namespace KeyVault.Acmebot.Options; + +public class GandiLiveDnsOptions +{ + public string ApiKey { get; set; } + +} diff --git a/KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs b/KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs new file mode 100644 index 00000000..66e515f2 --- /dev/null +++ b/KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; + +using KeyVault.Acmebot.Internal; +using KeyVault.Acmebot.Options; + +using Newtonsoft.Json; + +namespace KeyVault.Acmebot.Providers; + +public class GandiLiveDnsProvider : IDnsProvider +{ + public GandiLiveDnsProvider(GandiLiveDnsOptions options) + { + _client = new GandiClient(options.ApiKey); + } + + private readonly GandiClient _client; + + public string Name => "Gandi LiveDNS"; + + public int PropagationSeconds => 300; + + public async Task> ListZonesAsync() + { + var zones = await _client.ListZonesAsync(); + + return zones.Select(x => new DnsZone(this) { Id = x.Fqdn, Name = x.FqdnUnicode }).ToArray(); + } + + public Task CreateTxtRecordAsync(DnsZone zone, string relativeRecordName, IEnumerable values) + { + return _client.AddRecordAsync(zone.Name, relativeRecordName, values); + } + + public Task DeleteTxtRecordAsync(DnsZone zone, string relativeRecordName) + { + return _client.DeleteRecordAsync(zone.Name, relativeRecordName); + } + + private class GandiClient + { + public GandiClient(string apiKey) + { + ArgumentNullException.ThrowIfNull(apiKey); + + _httpClient = new HttpClient + { + BaseAddress = new Uri("https://api.gandi.net/v5/") + }; + + _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "Bearer " + apiKey); + } + + private readonly HttpClient _httpClient; + + public async Task> ListZonesAsync() + { + var response = await _httpClient.GetAsync("domain/domains"); + + response.EnsureSuccessStatusCode(); + var domains = await response.Content.ReadAsAsync(); + + return domains.Where(x => x.Nameserver.Current == "livedns").ToArray(); + } + + public async Task DeleteRecordAsync(string zoneName, string relativeRecordName) + { + var response = await _httpClient.DeleteAsync($"livedns/domains/{zoneName}/records/{relativeRecordName}/TXT"); + + if (response.StatusCode != HttpStatusCode.NotFound) + { + response.EnsureSuccessStatusCode(); + } + } + + public async Task AddRecordAsync(string zoneName, string relativeRecordName, IEnumerable values) + { + var response = await _httpClient.PostAsync($"livedns/domains/{zoneName}/records/{relativeRecordName}/TXT", new + { + rrset_values = values.ToArray(), + rrset_ttl = 300 //300 is the minimal value + }); + + response.EnsureSuccessStatusCode(); + } + } + public class Domain + { + [JsonProperty("fqdn")] + public string Fqdn { get; set; } + + [JsonProperty("tld")] + public string Tld { get; set; } + + [JsonProperty("status")] + public List Status { get; set; } + + [JsonProperty("dates")] + public Dates Dates { get; set; } + + [JsonProperty("nameserver")] + public Nameserver Nameserver { get; set; } + + [JsonProperty("autorenew")] + public bool Autorenew { get; set; } + + [JsonProperty("domain_owner")] + public string DomainOwner { get; set; } + + [JsonProperty("orga_owner")] + public string OrgaOwner { get; set; } + + [JsonProperty("owner")] + public string Owner { get; set; } + + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("tags")] + public List Tags { get; set; } + + [JsonProperty("href")] + public string Href { get; set; } + + [JsonProperty("fqdn_unicode")] + public string FqdnUnicode { get; set; } + } + + public class Dates + { + [JsonProperty("created_at")] + public DateTime CreatedAt { get; set; } + + [JsonProperty("registry_created_at")] + public DateTime RegistryCreatedAt { get; set; } + + [JsonProperty("registry_ends_at")] + public DateTime RegistryEndsAt { get; set; } + + [JsonProperty("updated_at")] + public DateTime UpdatedAt { get; set; } + } + + public class Nameserver + { + [JsonProperty("current")] + public string Current { get; set; } + } +} diff --git a/KeyVault.Acmebot/Startup.cs b/KeyVault.Acmebot/Startup.cs index f531ce90..73b78425 100644 --- a/KeyVault.Acmebot/Startup.cs +++ b/KeyVault.Acmebot/Startup.cs @@ -120,6 +120,7 @@ public override void Configure(IFunctionsHostBuilder builder) dnsProviders.TryAdd(options.CustomDns, o => new CustomDnsProvider(o)); dnsProviders.TryAdd(options.DnsMadeEasy, o => new DnsMadeEasyProvider(o)); dnsProviders.TryAdd(options.Gandi, o => new GandiProvider(o)); + dnsProviders.TryAdd(options.GandiLiveDns, o => new GandiLiveDnsProvider(o)); dnsProviders.TryAdd(options.GoDaddy, o => new GoDaddyProvider(o)); dnsProviders.TryAdd(options.GoogleDns, o => new GoogleDnsProvider(o)); dnsProviders.TryAdd(options.Route53, o => new Route53Provider(o)); From c16e44d58871a029721b5c8e6c53fa11e85f77f7 Mon Sep 17 00:00:00 2001 From: Bastien Hubert Date: Sat, 25 Nov 2023 15:43:30 +0100 Subject: [PATCH 2/3] fix encoding --- KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs b/KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs index 66e515f2..bfcb169b 100644 --- a/KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs +++ b/KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Net; From 0c5f462fac24602e8c9873f17573e6bfc759c6bb Mon Sep 17 00:00:00 2001 From: Bastien Hubert Date: Thu, 30 Nov 2023 09:41:48 +0100 Subject: [PATCH 3/3] Rename Client --- KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs b/KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs index bfcb169b..922ad8bc 100644 --- a/KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs +++ b/KeyVault.Acmebot/Providers/GandiLiveDnsProvider.cs @@ -17,10 +17,10 @@ public class GandiLiveDnsProvider : IDnsProvider { public GandiLiveDnsProvider(GandiLiveDnsOptions options) { - _client = new GandiClient(options.ApiKey); + _client = new GandiLiveDnsClient(options.ApiKey); } - private readonly GandiClient _client; + private readonly GandiLiveDnsClient _client; public string Name => "Gandi LiveDNS"; @@ -43,9 +43,9 @@ public Task DeleteTxtRecordAsync(DnsZone zone, string relativeRecordName) return _client.DeleteRecordAsync(zone.Name, relativeRecordName); } - private class GandiClient + private class GandiLiveDnsClient { - public GandiClient(string apiKey) + public GandiLiveDnsClient(string apiKey) { ArgumentNullException.ThrowIfNull(apiKey);