Skip to content

Commit

Permalink
Adding Custom DNS Provider model (#285)
Browse files Browse the repository at this point in the history
* Adding Custom DNS Provider model

* Changed custom dns provider api spec

* Streamlined HttpClient send methods

* Fixed formatting

* Update create record verb

* Adding API Key auth

* Make customizable API auth header name
  • Loading branch information
shibayan authored Sep 10, 2021
1 parent 83b26ea commit 944cc2c
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 29 deletions.
29 changes: 29 additions & 0 deletions KeyVault.Acmebot/Internal/HttpClientExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

using Newtonsoft.Json;

namespace KeyVault.Acmebot.Internal
{
internal static class HttpClientExtensions
{
public static Task<HttpResponseMessage> PostAsync<T>(this HttpClient client, string requestUri, T value) => client.PostAsync(requestUri, SerializeToJson(value));

public static Task<HttpResponseMessage> PutAsync<T>(this HttpClient client, string requestUri, T value) => client.PutAsync(requestUri, SerializeToJson(value));

public static Task<HttpResponseMessage> PatchAsync<T>(this HttpClient client, string requestUri, T value) => client.PatchAsync(requestUri, SerializeToJson(value));

public static Task<HttpResponseMessage> DeleteAsync<T>(this HttpClient client, string requestUri, T value)
{
var request = new HttpRequestMessage(HttpMethod.Delete, requestUri)
{
Content = SerializeToJson(value)
};

return client.SendAsync(request);
}

private static HttpContent SerializeToJson<T>(T value) => new StringContent(JsonConvert.SerializeObject(value), Encoding.UTF8, "application/json");
}
}
2 changes: 2 additions & 0 deletions KeyVault.Acmebot/Options/AcmebotOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public class AcmebotOptions

public CloudflareOptions Cloudflare { get; set; }

public CustomDnsOptions CustomDns { get; set; }

public DnsMadeEasyOptions DnsMadeEasy { get; set; }

public GoDaddyOptions GoDaddy { get; set; }
Expand Down
13 changes: 13 additions & 0 deletions KeyVault.Acmebot/Options/CustomDnsOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace KeyVault.Acmebot.Options
{
public class CustomDnsOptions
{
public int PropagationSeconds { get; set; } = 180;

public string Endpoint { get; set; }

public string ApiKey { get; set; }

public string ApiKeyHeaderName { get; set; } = "X-Api-Key";
}
}
5 changes: 3 additions & 2 deletions KeyVault.Acmebot/Providers/CloudflareProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Net.Http.Headers;
using System.Threading.Tasks;

using KeyVault.Acmebot.Internal;
using KeyVault.Acmebot.Options;

using Newtonsoft.Json;
Expand Down Expand Up @@ -73,7 +74,7 @@ public CloudflareDnsClient(string apiToken)

public async Task<IReadOnlyList<ZoneResult>> ListAllZonesAsync()
{
int page = 1;
var page = 1;
var zones = new List<ZoneResult>();

ApiResult<ZoneResult> result;
Expand Down Expand Up @@ -102,7 +103,7 @@ public async Task<IReadOnlyList<DnsRecordResult>> GetDnsRecordsAsync(string zone

public async Task CreateDnsRecordAsync(string zone, string name, string content)
{
var response = await _httpClient.PostAsJsonAsync($"/client/v4/zones/{zone}/dns_records", new { type = "TXT", name, content, ttl = 60 });
var response = await _httpClient.PostAsync($"/client/v4/zones/{zone}/dns_records", new { type = "TXT", name, content, ttl = 60 });

response.EnsureSuccessStatusCode();
}
Expand Down
60 changes: 60 additions & 0 deletions KeyVault.Acmebot/Providers/CustomDnsProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

using KeyVault.Acmebot.Internal;
using KeyVault.Acmebot.Options;

namespace KeyVault.Acmebot.Providers
{
public class CustomDnsProvider : IDnsProvider
{
public CustomDnsProvider(CustomDnsOptions options)
{
_httpClient = new HttpClient
{
BaseAddress = new Uri(options.Endpoint)
};

_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation(options.ApiKeyHeaderName, options.ApiKey);

PropagationSeconds = options.PropagationSeconds;
}

private readonly HttpClient _httpClient;

public int PropagationSeconds { get; }

public async Task<IReadOnlyList<DnsZone>> ListZonesAsync()
{
var response = await _httpClient.GetAsync("zones");

response.EnsureSuccessStatusCode();

var zones = await response.Content.ReadAsAsync<DnsZone[]>();

return zones;
}

public async Task CreateTxtRecordAsync(DnsZone zone, string relativeRecordName, IEnumerable<string> values)
{
var recordName = $"{relativeRecordName}.{zone.Name}";

var response = await _httpClient.PutAsync($"zones/{zone.Id}/records/{recordName}", new { type = "TXT", ttl = 60, values });

response.EnsureSuccessStatusCode();
}

public async Task DeleteTxtRecordAsync(DnsZone zone, string relativeRecordName)
{
var recordName = $"{relativeRecordName}.{zone.Name}";

var response = await _httpClient.DeleteAsync($"zones/{zone.Id}/records/{recordName}");

response.EnsureSuccessStatusCode();
}
}
}
8 changes: 3 additions & 5 deletions KeyVault.Acmebot/Providers/DnsMadeEasyProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Threading;
using System.Threading.Tasks;

using KeyVault.Acmebot.Internal;
using KeyVault.Acmebot.Options;

using Newtonsoft.Json;
Expand Down Expand Up @@ -97,17 +98,14 @@ public async Task<IReadOnlyList<DnsEntry>> ListRecordsAsync(string zoneId)

public async Task DeleteRecordAsync(string zoneId, DnsEntry entry)
{
var response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Delete, $"dns/managed/{zoneId}/records/{entry.Id}"));
var response = await _httpClient.DeleteAsync($"dns/managed/{zoneId}/records/{entry.Id}");

response.EnsureSuccessStatusCode();
}

public async Task AddRecordAsync(string zoneId, DnsEntry entry)
{
var response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Post, $"dns/managed/{zoneId}/records")
{
Content = new StringContent(JsonConvert.SerializeObject(entry), Encoding.UTF8, "application/json")
});
var response = await _httpClient.PostAsync($"dns/managed/{zoneId}/records", entry);

response.EnsureSuccessStatusCode();
}
Expand Down
22 changes: 9 additions & 13 deletions KeyVault.Acmebot/Providers/GoDaddyProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

using KeyVault.Acmebot.Internal;
using KeyVault.Acmebot.Options;

using Newtonsoft.Json;
Expand Down Expand Up @@ -33,19 +33,19 @@ public async Task<IReadOnlyList<DnsZone>> ListZonesAsync()
public async Task CreateTxtRecordAsync(DnsZone zone, string relativeRecordName, IEnumerable<string> values)
{
var entries = new List<DnsEntry>();

foreach (var value in values)
{
entries.Add(new DnsEntry
{
Name = relativeRecordName,
Type = "TXT",
TTL = 600,
TTL = 60,
Data = value
});
}

await _client.AddRecordAsync(zone.Id, entries);

}

public async Task DeleteTxtRecordAsync(DnsZone zone, string relativeRecordName)
Expand Down Expand Up @@ -74,15 +74,13 @@ public GoDaddyClient(string apiKey, string apiSecret)
throw new ArgumentNullException(nameof(apiSecret));
}


_httpClient = new HttpClient()
_httpClient = new HttpClient
{
BaseAddress = new Uri("https://api.godaddy.com")
};

_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("sso-key", $"{apiKey}:{apiSecret}");

}

private readonly HttpClient _httpClient;
Expand All @@ -93,34 +91,32 @@ public async Task<IReadOnlyList<ZoneDomain>> ListZonesAsync()

response.EnsureSuccessStatusCode();

var domains = await response.Content.ReadAsAsync<List<ZoneDomain>>();
var domains = await response.Content.ReadAsAsync<ZoneDomain[]>();

return domains;
}

public async Task<IReadOnlyList<DnsEntry>> ListRecordsAsync(string zoneId)
{

var response = await _httpClient.GetAsync($"v1/domains/{zoneId}/records");

response.EnsureSuccessStatusCode();

var entries = await response.Content.ReadAsAsync<List<DnsEntry>>();
var entries = await response.Content.ReadAsAsync<DnsEntry[]>();

return entries;
}

public async Task DeleteRecordAsync(string zoneId, DnsEntry entry)
{
var response = await _httpClient.DeleteAsync($"v1/domains/{zoneId}/records/{entry.Type}/{entry.Name}");

response.EnsureSuccessStatusCode();
}

public async Task AddRecordAsync(string zoneId, List<DnsEntry> entries)
public async Task AddRecordAsync(string zoneId, IReadOnlyList<DnsEntry> entries)
{
var content = new StringContent(JsonConvert.SerializeObject(entries, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), Encoding.UTF8, "application/json");

var response = await _httpClient.PatchAsync($"v1/domains/{zoneId}/records", content);
var response = await _httpClient.PatchAsync($"v1/domains/{zoneId}/records", entries);

response.EnsureSuccessStatusCode();
}
Expand Down
10 changes: 2 additions & 8 deletions KeyVault.Acmebot/Providers/TransIpProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,7 @@ public async Task DeleteRecordAsync(string zoneName, DnsEntry entry)
DnsEntry = entry
};

var response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Delete, $"domains/{zoneName}/dns")
{
Content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json")
});
var response = await _httpClient.DeleteAsync($"domains/{zoneName}/dns", request);

response.EnsureSuccessStatusCode();
}
Expand All @@ -144,10 +141,7 @@ public async Task AddRecordAsync(string zoneName, DnsEntry entry)
DnsEntry = entry
};

var response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Post, $"domains/{zoneName}/dns")
{
Content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json")
});
var response = await _httpClient.PostAsync($"domains/{zoneName}/dns", request);

response.EnsureSuccessStatusCode();
}
Expand Down
7 changes: 6 additions & 1 deletion KeyVault.Acmebot/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ public override void Configure(IFunctionsHostBuilder builder)
return new CloudflareProvider(options.Cloudflare);
}

if (options.CustomDns != null)
{
return new CustomDnsProvider(options.CustomDns);
}

if (options.DnsMadeEasy != null)
{
return new DnsMadeEasyProvider(options.DnsMadeEasy);
Expand Down Expand Up @@ -120,12 +125,12 @@ public override void Configure(IFunctionsHostBuilder builder)
return new TransIpProvider(options, options.TransIp, environment);
}

// Backward compatibility
if (options.AzureDns != null)
{
return new AzureDnsProvider(options.AzureDns, environment);
}

// Backward compatibility
if (options.SubscriptionId != null)
{
return new AzureDnsProvider(new AzureDnsOptions { SubscriptionId = options.SubscriptionId }, environment);
Expand Down

0 comments on commit 944cc2c

Please sign in to comment.