diff options
author | Skulblaka <skulblaka@mailbox.org> | 2020-07-23 19:34:28 +0200 |
---|---|---|
committer | Skulblaka <skulblaka@mailbox.org> | 2020-07-23 19:34:28 +0200 |
commit | b99c001d04271092a3df12184dfb88851d2e83f6 (patch) | |
tree | 2e076b704bf09c257da5d05214f89d5557737288 | |
parent | 2738777a456ade0dd8d367d87be9037694759986 (diff) | |
download | letsencrypt-win-simple-b99c001d04271092a3df12184dfb88851d2e83f6.zip letsencrypt-win-simple-b99c001d04271092a3df12184dfb88851d2e83f6.tar.gz letsencrypt-win-simple-b99c001d04271092a3df12184dfb88851d2e83f6.tar.bz2 |
Implement DigitalOcean DNS validation
7 files changed, 173 insertions, 0 deletions
diff --git a/src/plugin.validation.dns.digitalocean/DigitalOcean.cs b/src/plugin.validation.dns.digitalocean/DigitalOcean.cs new file mode 100644 index 0000000..f25ff9d --- /dev/null +++ b/src/plugin.validation.dns.digitalocean/DigitalOcean.cs @@ -0,0 +1,68 @@ +using System; +using System.Threading.Tasks; +using DigitalOcean.API; +using DigitalOcean.API.Models.Requests; +using PKISharp.WACS.Clients.DNS; +using PKISharp.WACS.Services; + +namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns +{ + internal class DigitalOcean : DnsValidation<DigitalOcean> + { + private readonly IDigitalOceanClient _doClient; + private long? _recordId; + + public DigitalOcean(DigitalOceanOptions options, LookupClientProvider dnsClient, ILogService log, ISettingsService settings) : base(dnsClient, log, settings) + { + _doClient = new DigitalOceanClient(options.ApiToken.Value); + } + + public override async Task DeleteRecord(DnsValidationRecord record) + { + try + { + var (_, zone) = SplitDomain(record.Authority.Domain); + if (_recordId == null) + { + _log.Warning("Not deleting DNS records on DigitalOcean because of missing record id."); + return; + } + + await _doClient.DomainRecords.Delete(zone, _recordId.Value); + _log.Information("Successfully deleted DNS record on DigitalOcean."); + } + catch (Exception ex) + { + _log.Error(ex, "Failed to delete DNS record on DigitalOcean."); + } + } + + public override async Task<bool> CreateRecord(DnsValidationRecord record) + { + try + { + var (name, zone) = SplitDomain(record.Authority.Domain); + var createdRecord = await _doClient.DomainRecords.Create(zone, new DomainRecord + { + Type = "TXT", + Name = name, + Data = record.Value, + Ttl = 300 + }); + _recordId = createdRecord.Id; + return true; + } + catch (Exception ex) + { + _log.Error(ex, "Failed to create DNS record on DigitalOcean."); + return false; + } + } + + private (string, string) SplitDomain(string domain) + { + var index = domain.IndexOf('.'); + return (domain.Substring(0, index), domain.Substring(index + 1)); + } + } +} diff --git a/src/plugin.validation.dns.digitalocean/DigitalOceanArguments.cs b/src/plugin.validation.dns.digitalocean/DigitalOceanArguments.cs new file mode 100644 index 0000000..072d0d8 --- /dev/null +++ b/src/plugin.validation.dns.digitalocean/DigitalOceanArguments.cs @@ -0,0 +1,7 @@ +namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns +{ + public class DigitalOceanArguments + { + public string ApiToken { get; set; } + } +}
\ No newline at end of file diff --git a/src/plugin.validation.dns.digitalocean/DigitalOceanArgumentsProvider.cs b/src/plugin.validation.dns.digitalocean/DigitalOceanArgumentsProvider.cs new file mode 100644 index 0000000..394021c --- /dev/null +++ b/src/plugin.validation.dns.digitalocean/DigitalOceanArgumentsProvider.cs @@ -0,0 +1,18 @@ +using Fclp; +using PKISharp.WACS.Configuration; + +namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns +{ + public class DigitalOceanArgumentsProvider : BaseArgumentsProvider<DigitalOceanArguments> + { + public override string Name => "DigitalOcean"; + public override string Group => "Validation"; + public override string Condition => "--validationmode dns-01 --validation digitalocean"; + public override void Configure(FluentCommandLineParser<DigitalOceanArguments> parser) + { + _ = parser.Setup(o => o.ApiToken) + .As("digitaloceanapitoken") + .WithDescription("The API token to authenticate against the DigitalOcean API"); + } + } +}
\ No newline at end of file diff --git a/src/plugin.validation.dns.digitalocean/DigitalOceanOptions.cs b/src/plugin.validation.dns.digitalocean/DigitalOceanOptions.cs new file mode 100644 index 0000000..19cba1e --- /dev/null +++ b/src/plugin.validation.dns.digitalocean/DigitalOceanOptions.cs @@ -0,0 +1,15 @@ +using PKISharp.WACS.Plugins.Base; +using PKISharp.WACS.Plugins.Base.Options; +using PKISharp.WACS.Services.Serialization; + +namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns +{ + [Plugin("1a87d670-3fa3-4a2a-bb10-491d48feb5db")] + internal class DigitalOceanOptions : ValidationPluginOptions<DigitalOcean> + { + public override string Name => "DigitalOcean"; + public override string Description => "Create verification records on DigitalOcean"; + public override string ChallengeType => Constants.Dns01ChallengeType; + public ProtectedString ApiToken { get; set; } + } +}
\ No newline at end of file diff --git a/src/plugin.validation.dns.digitalocean/DigitalOceanOptionsFactory.cs b/src/plugin.validation.dns.digitalocean/DigitalOceanOptionsFactory.cs new file mode 100644 index 0000000..d52860e --- /dev/null +++ b/src/plugin.validation.dns.digitalocean/DigitalOceanOptionsFactory.cs @@ -0,0 +1,40 @@ +using System.Threading.Tasks; +using ACMESharp.Authorizations; +using PKISharp.WACS.DomainObjects; +using PKISharp.WACS.Plugins.Base.Factories; +using PKISharp.WACS.Services; +using PKISharp.WACS.Services.Serialization; + +namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns +{ + internal class DigitalOceanOptionsFactory : ValidationPluginOptionsFactory<DigitalOcean, DigitalOceanOptions> + { + private readonly IArgumentsService _arguments; + + public DigitalOceanOptionsFactory(IArgumentsService arguments) : base(Dns01ChallengeValidationDetails.Dns01ChallengeType) + { + _arguments = arguments; + } + + public override Task<DigitalOceanOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel) + { + var arguments = _arguments.GetArguments<DigitalOceanArguments>(); + return Task.FromResult(new DigitalOceanOptions + { + ApiToken = new ProtectedString(arguments.ApiToken) + }); + } + + public override Task<DigitalOceanOptions> Default(Target target) + { + var arguments = _arguments.GetArguments<DigitalOceanArguments>(); + return Task.FromResult(new DigitalOceanOptions + { + ApiToken = new ProtectedString( + _arguments.TryGetRequiredArgument(nameof(arguments.ApiToken), arguments.ApiToken)) + }); + } + + public override bool CanValidate(Target target) => true; + } +}
\ No newline at end of file diff --git a/src/plugin.validation.dns.digitalocean/wacs.validation.dns.digitalocean.csproj b/src/plugin.validation.dns.digitalocean/wacs.validation.dns.digitalocean.csproj new file mode 100644 index 0000000..5a4ec0b --- /dev/null +++ b/src/plugin.validation.dns.digitalocean/wacs.validation.dns.digitalocean.csproj @@ -0,0 +1,17 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netcoreapp3.1</TargetFramework> + <RootNamespace>PKISharp.WACS.Plugins.ValidationPlugins.Dns</RootNamespace> + <AssemblyName>PKISharp.WACS.Plugins.ValidationPlugins.DigitalOcean</AssemblyName> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="DigitalOcean.API" Version="5.1.0" /> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\main.lib\wacs.lib.csproj" /> + </ItemGroup> + +</Project> diff --git a/src/wacs.sln b/src/wacs.sln index fe889a8..d30363f 100644 --- a/src/wacs.sln +++ b/src/wacs.sln @@ -38,6 +38,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "wacs.validation.dns.cloudfl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "wacs.validation.dns.luadns", "plugin.validation.dns.luadns\wacs.validation.dns.luadns.csproj", "{424630AC-3029-4188-B78A-A630316A4B99}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wacs.validation.dns.digitalocean", "plugin.validation.dns.digitalocean\wacs.validation.dns.digitalocean.csproj", "{D8BD50E6-0759-476B-A021-0CF1325B4DDB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -105,6 +107,12 @@ Global {424630AC-3029-4188-B78A-A630316A4B99}.Release|Any CPU.Build.0 = Release|Any CPU {424630AC-3029-4188-B78A-A630316A4B99}.ReleasePluggable|Any CPU.ActiveCfg = Release|Any CPU {424630AC-3029-4188-B78A-A630316A4B99}.ReleasePluggable|Any CPU.Build.0 = Release|Any CPU + {D8BD50E6-0759-476B-A021-0CF1325B4DDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D8BD50E6-0759-476B-A021-0CF1325B4DDB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D8BD50E6-0759-476B-A021-0CF1325B4DDB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D8BD50E6-0759-476B-A021-0CF1325B4DDB}.Release|Any CPU.Build.0 = Release|Any CPU + {D8BD50E6-0759-476B-A021-0CF1325B4DDB}.ReleasePluggable|Any CPU.ActiveCfg = Release|Any CPU + {D8BD50E6-0759-476B-A021-0CF1325B4DDB}.ReleasePluggable|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE |