1
0
mirror of https://github.com/go-acme/lego.git synced 2024-12-25 11:02:56 +02:00

Add Brandit.com as DNS provider (#1890)

This commit is contained in:
Christian Grøntved 2023-04-14 09:44:20 +02:00 committed by GitHub
parent 3b70a85cf7
commit 9db046581b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1050 additions and 28 deletions

View File

@ -51,33 +51,34 @@ Detailed documentation is available [here](https://go-acme.github.io/lego/dns).
|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
| [Akamai EdgeDNS](https://go-acme.github.io/lego/dns/edgedns/) | [Alibaba Cloud DNS](https://go-acme.github.io/lego/dns/alidns/) | [all-inkl](https://go-acme.github.io/lego/dns/allinkl/) | [Amazon Lightsail](https://go-acme.github.io/lego/dns/lightsail/) |
| [Amazon Route 53](https://go-acme.github.io/lego/dns/route53/) | [ArvanCloud](https://go-acme.github.io/lego/dns/arvancloud/) | [Aurora DNS](https://go-acme.github.io/lego/dns/auroradns/) | [Autodns](https://go-acme.github.io/lego/dns/autodns/) |
| [Azure](https://go-acme.github.io/lego/dns/azure/) | [Bindman](https://go-acme.github.io/lego/dns/bindman/) | [Bluecat](https://go-acme.github.io/lego/dns/bluecat/) | [Bunny](https://go-acme.github.io/lego/dns/bunny/) |
| [Checkdomain](https://go-acme.github.io/lego/dns/checkdomain/) | [Civo](https://go-acme.github.io/lego/dns/civo/) | [CloudDNS](https://go-acme.github.io/lego/dns/clouddns/) | [Cloudflare](https://go-acme.github.io/lego/dns/cloudflare/) |
| [ClouDNS](https://go-acme.github.io/lego/dns/cloudns/) | [CloudXNS](https://go-acme.github.io/lego/dns/cloudxns/) | [ConoHa](https://go-acme.github.io/lego/dns/conoha/) | [Constellix](https://go-acme.github.io/lego/dns/constellix/) |
| [deSEC.io](https://go-acme.github.io/lego/dns/desec/) | [Designate DNSaaS for Openstack](https://go-acme.github.io/lego/dns/designate/) | [Digital Ocean](https://go-acme.github.io/lego/dns/digitalocean/) | [DNS Made Easy](https://go-acme.github.io/lego/dns/dnsmadeeasy/) |
| [dnsHome.de](https://go-acme.github.io/lego/dns/dnshomede/) | [DNSimple](https://go-acme.github.io/lego/dns/dnsimple/) | [DNSPod (deprecated)](https://go-acme.github.io/lego/dns/dnspod/) | [Domain Offensive (do.de)](https://go-acme.github.io/lego/dns/dode/) |
| [Domeneshop](https://go-acme.github.io/lego/dns/domeneshop/) | [DreamHost](https://go-acme.github.io/lego/dns/dreamhost/) | [Duck DNS](https://go-acme.github.io/lego/dns/duckdns/) | [Dyn](https://go-acme.github.io/lego/dns/dyn/) |
| [Dynu](https://go-acme.github.io/lego/dns/dynu/) | [EasyDNS](https://go-acme.github.io/lego/dns/easydns/) | [Epik](https://go-acme.github.io/lego/dns/epik/) | [Exoscale](https://go-acme.github.io/lego/dns/exoscale/) |
| [External program](https://go-acme.github.io/lego/dns/exec/) | [freemyip.com](https://go-acme.github.io/lego/dns/freemyip/) | [G-Core Labs](https://go-acme.github.io/lego/dns/gcore/) | [Gandi Live DNS (v5)](https://go-acme.github.io/lego/dns/gandiv5/) |
| [Gandi](https://go-acme.github.io/lego/dns/gandi/) | [Glesys](https://go-acme.github.io/lego/dns/glesys/) | [Go Daddy](https://go-acme.github.io/lego/dns/godaddy/) | [Google Cloud](https://go-acme.github.io/lego/dns/gcloud/) |
| [Google Domains](https://go-acme.github.io/lego/dns/googledomains/) | [Hetzner](https://go-acme.github.io/lego/dns/hetzner/) | [Hosting.de](https://go-acme.github.io/lego/dns/hostingde/) | [Hosttech](https://go-acme.github.io/lego/dns/hosttech/) |
| [HTTP request](https://go-acme.github.io/lego/dns/httpreq/) | [Hurricane Electric DNS](https://go-acme.github.io/lego/dns/hurricane/) | [HyperOne](https://go-acme.github.io/lego/dns/hyperone/) | [IBM Cloud (SoftLayer)](https://go-acme.github.io/lego/dns/ibmcloud/) |
| [IIJ DNS Platform Service](https://go-acme.github.io/lego/dns/iijdpf/) | [Infoblox](https://go-acme.github.io/lego/dns/infoblox/) | [Infomaniak](https://go-acme.github.io/lego/dns/infomaniak/) | [Internet Initiative Japan](https://go-acme.github.io/lego/dns/iij/) |
| [Internet.bs](https://go-acme.github.io/lego/dns/internetbs/) | [INWX](https://go-acme.github.io/lego/dns/inwx/) | [Ionos](https://go-acme.github.io/lego/dns/ionos/) | [iwantmyname](https://go-acme.github.io/lego/dns/iwantmyname/) |
| [Joker](https://go-acme.github.io/lego/dns/joker/) | [Joohoi's ACME-DNS](https://go-acme.github.io/lego/dns/acme-dns/) | [Liara](https://go-acme.github.io/lego/dns/liara/) | [Linode (v4)](https://go-acme.github.io/lego/dns/linode/) |
| [Liquid Web](https://go-acme.github.io/lego/dns/liquidweb/) | [Loopia](https://go-acme.github.io/lego/dns/loopia/) | [LuaDNS](https://go-acme.github.io/lego/dns/luadns/) | [Manual](https://go-acme.github.io/lego/dns/manual/) |
| [MyDNS.jp](https://go-acme.github.io/lego/dns/mydnsjp/) | [MythicBeasts](https://go-acme.github.io/lego/dns/mythicbeasts/) | [Name.com](https://go-acme.github.io/lego/dns/namedotcom/) | [Namecheap](https://go-acme.github.io/lego/dns/namecheap/) |
| [Namesilo](https://go-acme.github.io/lego/dns/namesilo/) | [NearlyFreeSpeech.NET](https://go-acme.github.io/lego/dns/nearlyfreespeech/) | [Netcup](https://go-acme.github.io/lego/dns/netcup/) | [Netlify](https://go-acme.github.io/lego/dns/netlify/) |
| [Nicmanager](https://go-acme.github.io/lego/dns/nicmanager/) | [NIFCloud](https://go-acme.github.io/lego/dns/nifcloud/) | [Njalla](https://go-acme.github.io/lego/dns/njalla/) | [Nodion](https://go-acme.github.io/lego/dns/nodion/) |
| [NS1](https://go-acme.github.io/lego/dns/ns1/) | [Open Telekom Cloud](https://go-acme.github.io/lego/dns/otc/) | [Oracle Cloud](https://go-acme.github.io/lego/dns/oraclecloud/) | [OVH](https://go-acme.github.io/lego/dns/ovh/) |
| [plesk.com](https://go-acme.github.io/lego/dns/plesk/) | [Porkbun](https://go-acme.github.io/lego/dns/porkbun/) | [PowerDNS](https://go-acme.github.io/lego/dns/pdns/) | [Rackspace](https://go-acme.github.io/lego/dns/rackspace/) |
| [reg.ru](https://go-acme.github.io/lego/dns/regru/) | [RFC2136](https://go-acme.github.io/lego/dns/rfc2136/) | [RimuHosting](https://go-acme.github.io/lego/dns/rimuhosting/) | [Sakura Cloud](https://go-acme.github.io/lego/dns/sakuracloud/) |
| [Scaleway](https://go-acme.github.io/lego/dns/scaleway/) | [Selectel](https://go-acme.github.io/lego/dns/selectel/) | [Servercow](https://go-acme.github.io/lego/dns/servercow/) | [Simply.com](https://go-acme.github.io/lego/dns/simply/) |
| [Sonic](https://go-acme.github.io/lego/dns/sonic/) | [Stackpath](https://go-acme.github.io/lego/dns/stackpath/) | [Tencent Cloud DNS](https://go-acme.github.io/lego/dns/tencentcloud/) | [TransIP](https://go-acme.github.io/lego/dns/transip/) |
| [UKFast SafeDNS](https://go-acme.github.io/lego/dns/safedns/) | [Ultradns](https://go-acme.github.io/lego/dns/ultradns/) | [Variomedia](https://go-acme.github.io/lego/dns/variomedia/) | [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) |
| [Vercel](https://go-acme.github.io/lego/dns/vercel/) | [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) | [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/) | [VK Cloud](https://go-acme.github.io/lego/dns/vkcloud/) |
| [Vscale](https://go-acme.github.io/lego/dns/vscale/) | [Vultr](https://go-acme.github.io/lego/dns/vultr/) | [Websupport](https://go-acme.github.io/lego/dns/websupport/) | [WEDOS](https://go-acme.github.io/lego/dns/wedos/) |
| [Yandex Cloud](https://go-acme.github.io/lego/dns/yandexcloud/) | [Yandex PDD](https://go-acme.github.io/lego/dns/yandex/) | [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/) | [Zonomi](https://go-acme.github.io/lego/dns/zonomi/) |
| [Azure](https://go-acme.github.io/lego/dns/azure/) | [Bindman](https://go-acme.github.io/lego/dns/bindman/) | [Bluecat](https://go-acme.github.io/lego/dns/bluecat/) | [BRANDIT](https://go-acme.github.io/lego/dns/brandit/) |
| [Bunny](https://go-acme.github.io/lego/dns/bunny/) | [Checkdomain](https://go-acme.github.io/lego/dns/checkdomain/) | [Civo](https://go-acme.github.io/lego/dns/civo/) | [CloudDNS](https://go-acme.github.io/lego/dns/clouddns/) |
| [Cloudflare](https://go-acme.github.io/lego/dns/cloudflare/) | [ClouDNS](https://go-acme.github.io/lego/dns/cloudns/) | [CloudXNS](https://go-acme.github.io/lego/dns/cloudxns/) | [ConoHa](https://go-acme.github.io/lego/dns/conoha/) |
| [Constellix](https://go-acme.github.io/lego/dns/constellix/) | [deSEC.io](https://go-acme.github.io/lego/dns/desec/) | [Designate DNSaaS for Openstack](https://go-acme.github.io/lego/dns/designate/) | [Digital Ocean](https://go-acme.github.io/lego/dns/digitalocean/) |
| [DNS Made Easy](https://go-acme.github.io/lego/dns/dnsmadeeasy/) | [dnsHome.de](https://go-acme.github.io/lego/dns/dnshomede/) | [DNSimple](https://go-acme.github.io/lego/dns/dnsimple/) | [DNSPod (deprecated)](https://go-acme.github.io/lego/dns/dnspod/) |
| [Domain Offensive (do.de)](https://go-acme.github.io/lego/dns/dode/) | [Domeneshop](https://go-acme.github.io/lego/dns/domeneshop/) | [DreamHost](https://go-acme.github.io/lego/dns/dreamhost/) | [Duck DNS](https://go-acme.github.io/lego/dns/duckdns/) |
| [Dyn](https://go-acme.github.io/lego/dns/dyn/) | [Dynu](https://go-acme.github.io/lego/dns/dynu/) | [EasyDNS](https://go-acme.github.io/lego/dns/easydns/) | [Epik](https://go-acme.github.io/lego/dns/epik/) |
| [Exoscale](https://go-acme.github.io/lego/dns/exoscale/) | [External program](https://go-acme.github.io/lego/dns/exec/) | [freemyip.com](https://go-acme.github.io/lego/dns/freemyip/) | [G-Core Labs](https://go-acme.github.io/lego/dns/gcore/) |
| [Gandi Live DNS (v5)](https://go-acme.github.io/lego/dns/gandiv5/) | [Gandi](https://go-acme.github.io/lego/dns/gandi/) | [Glesys](https://go-acme.github.io/lego/dns/glesys/) | [Go Daddy](https://go-acme.github.io/lego/dns/godaddy/) |
| [Google Cloud](https://go-acme.github.io/lego/dns/gcloud/) | [Google Domains](https://go-acme.github.io/lego/dns/googledomains/) | [Hetzner](https://go-acme.github.io/lego/dns/hetzner/) | [Hosting.de](https://go-acme.github.io/lego/dns/hostingde/) |
| [Hosttech](https://go-acme.github.io/lego/dns/hosttech/) | [HTTP request](https://go-acme.github.io/lego/dns/httpreq/) | [Hurricane Electric DNS](https://go-acme.github.io/lego/dns/hurricane/) | [HyperOne](https://go-acme.github.io/lego/dns/hyperone/) |
| [IBM Cloud (SoftLayer)](https://go-acme.github.io/lego/dns/ibmcloud/) | [IIJ DNS Platform Service](https://go-acme.github.io/lego/dns/iijdpf/) | [Infoblox](https://go-acme.github.io/lego/dns/infoblox/) | [Infomaniak](https://go-acme.github.io/lego/dns/infomaniak/) |
| [Internet Initiative Japan](https://go-acme.github.io/lego/dns/iij/) | [Internet.bs](https://go-acme.github.io/lego/dns/internetbs/) | [INWX](https://go-acme.github.io/lego/dns/inwx/) | [Ionos](https://go-acme.github.io/lego/dns/ionos/) |
| [iwantmyname](https://go-acme.github.io/lego/dns/iwantmyname/) | [Joker](https://go-acme.github.io/lego/dns/joker/) | [Joohoi's ACME-DNS](https://go-acme.github.io/lego/dns/acme-dns/) | [Liara](https://go-acme.github.io/lego/dns/liara/) |
| [Linode (v4)](https://go-acme.github.io/lego/dns/linode/) | [Liquid Web](https://go-acme.github.io/lego/dns/liquidweb/) | [Loopia](https://go-acme.github.io/lego/dns/loopia/) | [LuaDNS](https://go-acme.github.io/lego/dns/luadns/) |
| [Manual](https://go-acme.github.io/lego/dns/manual/) | [MyDNS.jp](https://go-acme.github.io/lego/dns/mydnsjp/) | [MythicBeasts](https://go-acme.github.io/lego/dns/mythicbeasts/) | [Name.com](https://go-acme.github.io/lego/dns/namedotcom/) |
| [Namecheap](https://go-acme.github.io/lego/dns/namecheap/) | [Namesilo](https://go-acme.github.io/lego/dns/namesilo/) | [NearlyFreeSpeech.NET](https://go-acme.github.io/lego/dns/nearlyfreespeech/) | [Netcup](https://go-acme.github.io/lego/dns/netcup/) |
| [Netlify](https://go-acme.github.io/lego/dns/netlify/) | [Nicmanager](https://go-acme.github.io/lego/dns/nicmanager/) | [NIFCloud](https://go-acme.github.io/lego/dns/nifcloud/) | [Njalla](https://go-acme.github.io/lego/dns/njalla/) |
| [Nodion](https://go-acme.github.io/lego/dns/nodion/) | [NS1](https://go-acme.github.io/lego/dns/ns1/) | [Open Telekom Cloud](https://go-acme.github.io/lego/dns/otc/) | [Oracle Cloud](https://go-acme.github.io/lego/dns/oraclecloud/) |
| [OVH](https://go-acme.github.io/lego/dns/ovh/) | [plesk.com](https://go-acme.github.io/lego/dns/plesk/) | [Porkbun](https://go-acme.github.io/lego/dns/porkbun/) | [PowerDNS](https://go-acme.github.io/lego/dns/pdns/) |
| [Rackspace](https://go-acme.github.io/lego/dns/rackspace/) | [reg.ru](https://go-acme.github.io/lego/dns/regru/) | [RFC2136](https://go-acme.github.io/lego/dns/rfc2136/) | [RimuHosting](https://go-acme.github.io/lego/dns/rimuhosting/) |
| [Sakura Cloud](https://go-acme.github.io/lego/dns/sakuracloud/) | [Scaleway](https://go-acme.github.io/lego/dns/scaleway/) | [Selectel](https://go-acme.github.io/lego/dns/selectel/) | [Servercow](https://go-acme.github.io/lego/dns/servercow/) |
| [Simply.com](https://go-acme.github.io/lego/dns/simply/) | [Sonic](https://go-acme.github.io/lego/dns/sonic/) | [Stackpath](https://go-acme.github.io/lego/dns/stackpath/) | [Tencent Cloud DNS](https://go-acme.github.io/lego/dns/tencentcloud/) |
| [TransIP](https://go-acme.github.io/lego/dns/transip/) | [UKFast SafeDNS](https://go-acme.github.io/lego/dns/safedns/) | [Ultradns](https://go-acme.github.io/lego/dns/ultradns/) | [Variomedia](https://go-acme.github.io/lego/dns/variomedia/) |
| [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) | [Vercel](https://go-acme.github.io/lego/dns/vercel/) | [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) | [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/) |
| [VK Cloud](https://go-acme.github.io/lego/dns/vkcloud/) | [Vscale](https://go-acme.github.io/lego/dns/vscale/) | [Vultr](https://go-acme.github.io/lego/dns/vultr/) | [Websupport](https://go-acme.github.io/lego/dns/websupport/) |
| [WEDOS](https://go-acme.github.io/lego/dns/wedos/) | [Yandex Cloud](https://go-acme.github.io/lego/dns/yandexcloud/) | [Yandex PDD](https://go-acme.github.io/lego/dns/yandex/) | [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/) |
| [Zonomi](https://go-acme.github.io/lego/dns/zonomi/) | | | |
<!-- END DNS PROVIDERS LIST -->

View File

@ -23,6 +23,7 @@ func allDNSCodes() string {
"azure",
"bindman",
"bluecat",
"brandit",
"bunny",
"checkdomain",
"civo",
@ -332,6 +333,27 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/bluecat`)
case "brandit":
// generated from: providers/dns/brandit/brandit.toml
ew.writeln(`Configuration for BRANDIT.`)
ew.writeln(`Code: 'brandit'`)
ew.writeln(`Since: 'v4.11.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "BRANDIT_API_KEY": The API key`)
ew.writeln(` - "BRANDIT_API_USERNAME": The API username`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "BRANDIT_HTTP_TIMEOUT": API request timeout`)
ew.writeln(` - "BRANDIT_POLLING_INTERVAL": Time between DNS propagation check`)
ew.writeln(` - "BRANDIT_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
ew.writeln(` - "BRANDIT_TTL": The TTL of the TXT record used for the DNS challenge`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/brandit`)
case "bunny":
// generated from: providers/dns/bunny/bunny.toml
ew.writeln(`Configuration for Bunny.`)

View File

@ -0,0 +1,69 @@
---
title: "BRANDIT"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: brandit
dnsprovider:
since: "v4.11.0"
code: "brandit"
url: "https://www.brandit.com/"
---
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/brandit/brandit.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
Configuration for [BRANDIT](https://www.brandit.com/).
<!--more-->
- Code: `brandit`
- Since: v4.11.0
Here is an example bash command using the BRANDIT provider:
```bash
BRANDIT_API_KEY=xxxxxxxxxxxxxxxxxxxxx \
BRANDIT_API_USERNAME=yyyyyyyyyyyyyyyyyyyy \
lego --email myemail@example.com --dns brandit --domains my.example.org run
```
## Credentials
| Environment Variable Name | Description |
|-----------------------|-------------|
| `BRANDIT_API_KEY` | The API key |
| `BRANDIT_API_USERNAME` | The API username |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{< ref "dns#configuration-and-credentials" >}}).
## Additional Configuration
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `BRANDIT_HTTP_TIMEOUT` | API request timeout |
| `BRANDIT_POLLING_INTERVAL` | Time between DNS propagation check |
| `BRANDIT_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
| `BRANDIT_TTL` | The TTL of the TXT record used for the DNS challenge |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{< ref "dns#configuration-and-credentials" >}}).
## More information
- [API documentation](https://portal.brandit.com/apidocv3)
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/brandit/brandit.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

View File

@ -125,7 +125,7 @@ To display the documentation for a specific DNS provider, run:
$ lego dnshelp -c code
Supported DNS providers:
acme-dns, alidns, allinkl, arvancloud, auroradns, autodns, azure, bindman, bluecat, bunny, checkdomain, civo, clouddns, cloudflare, cloudns, cloudxns, conoha, constellix, desec, designate, digitalocean, dnshomede, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, dreamhost, duckdns, dyn, dynu, easydns, edgedns, epik, exec, exoscale, freemyip, gandi, gandiv5, gcloud, gcore, glesys, godaddy, googledomains, hetzner, hostingde, hosttech, httpreq, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, infomaniak, internetbs, inwx, ionos, iwantmyname, joker, liara, lightsail, linode, liquidweb, loopia, luadns, manual, mydnsjp, mythicbeasts, namecheap, namedotcom, namesilo, nearlyfreespeech, netcup, netlify, nicmanager, nifcloud, njalla, nodion, ns1, oraclecloud, otc, ovh, pdns, plesk, porkbun, rackspace, regru, rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, servercow, simply, sonic, stackpath, tencentcloud, transip, ultradns, variomedia, vegadns, vercel, versio, vinyldns, vkcloud, vscale, vultr, websupport, wedos, yandex, yandexcloud, zoneee, zonomi
acme-dns, alidns, allinkl, arvancloud, auroradns, autodns, azure, bindman, bluecat, brandit, bunny, checkdomain, civo, clouddns, cloudflare, cloudns, cloudxns, conoha, constellix, desec, designate, digitalocean, dnshomede, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, dreamhost, duckdns, dyn, dynu, easydns, edgedns, epik, exec, exoscale, freemyip, gandi, gandiv5, gcloud, gcore, glesys, godaddy, googledomains, hetzner, hostingde, hosttech, httpreq, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, infomaniak, internetbs, inwx, ionos, iwantmyname, joker, liara, lightsail, linode, liquidweb, loopia, luadns, manual, mydnsjp, mythicbeasts, namecheap, namedotcom, namesilo, nearlyfreespeech, netcup, netlify, nicmanager, nifcloud, njalla, nodion, ns1, oraclecloud, otc, ovh, pdns, plesk, porkbun, rackspace, regru, rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, servercow, simply, sonic, stackpath, tencentcloud, transip, ultradns, variomedia, vegadns, vercel, versio, vinyldns, vkcloud, vscale, vultr, websupport, wedos, yandex, yandexcloud, zoneee, zonomi
More information: https://go-acme.github.io/lego/dns
"""

View File

@ -0,0 +1,197 @@
package brandit
import (
"errors"
"fmt"
"net/http"
"sync"
"time"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/brandit/internal"
)
const defaultTTL = 600
// Environment variables names.
const (
envNamespace = "BRANDIT_"
EnvAPIKey = envNamespace + "API_KEY"
EnvAPIUsername = envNamespace + "API_USERNAME"
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
DefaultBrandItPropagationTimeout = 600 * time.Second
)
// Config is used to configure the creation of the DNSProvider.
type Config struct {
APIKey string
APIUsername string
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
HTTPClient *http.Client
}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
TTL: env.GetOrDefaultInt(EnvTTL, defaultTTL),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, DefaultBrandItPropagationTimeout),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
HTTPClient: &http.Client{
Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
},
}
}
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
config *Config
client *internal.Client
records map[string]string
recordsMu sync.Mutex
}
// NewDNSProvider returns a DNSProvider instance configured for BrandIT.
// Credentials must be passed in the environment variables: BRANDIT_API_KEY, BRANDIT_API_USERNAME.
func NewDNSProvider() (*DNSProvider, error) {
values, err := env.Get(EnvAPIKey, EnvAPIUsername)
if err != nil {
return nil, fmt.Errorf("brandit: %w", err)
}
config := NewDefaultConfig()
config.APIKey = values[EnvAPIKey]
config.APIUsername = values[EnvAPIUsername]
return NewDNSProviderConfig(config)
}
// NewDNSProviderConfig return a DNSProvider instance configured for BrandIT.
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config == nil {
return nil, errors.New("brandit: the configuration of the DNS provider is nil")
}
client, err := internal.NewClient(config.APIUsername, config.APIKey)
if err != nil {
return nil, fmt.Errorf("brandit: %w", err)
}
if config.HTTPClient != nil {
client.HTTPClient = config.HTTPClient
}
return &DNSProvider{
config: config,
client: client,
records: make(map[string]string),
}, nil
}
// Present creates a TXT record using the specified parameters.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("brandit: %w", err)
}
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
if err != nil {
return fmt.Errorf("brandit: %w", err)
}
record := internal.Record{
Type: "TXT",
Name: subDomain,
Content: info.Value,
TTL: d.config.TTL,
}
// find the account associated with the domain
account, err := d.client.StatusDomain(dns01.UnFqdn(authZone))
if err != nil {
return fmt.Errorf("brandit: status domain: %w", err)
}
// Find the next record id
recordID, err := d.client.ListRecords(account.Response.Registrar[0], dns01.UnFqdn(authZone))
if err != nil {
return fmt.Errorf("brandit: list records: %w", err)
}
result, err := d.client.AddRecord(dns01.UnFqdn(authZone), account.Response.Registrar[0], fmt.Sprint(recordID.Response.Total[0]), record)
if err != nil {
return fmt.Errorf("brandit: add record: %w", err)
}
d.recordsMu.Lock()
d.records[token] = result.Record
d.recordsMu.Unlock()
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("brandit: %w", err)
}
// gets the record's unique ID
d.recordsMu.Lock()
dnsRecord, ok := d.records[token]
d.recordsMu.Unlock()
if !ok {
return fmt.Errorf("brandit: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
// find the account associated with the domain
account, err := d.client.StatusDomain(dns01.UnFqdn(authZone))
if err != nil {
return fmt.Errorf("brandit: status domain: %w", err)
}
records, err := d.client.ListRecords(account.Response.Registrar[0], dns01.UnFqdn(authZone))
if err != nil {
return fmt.Errorf("brandit: list records: %w", err)
}
var recordID int
for i, r := range records.Response.RR {
if r == dnsRecord {
recordID = i
}
}
_, err = d.client.DeleteRecord(dns01.UnFqdn(authZone), account.Response.Registrar[0], dnsRecord, fmt.Sprint(recordID))
if err != nil {
return fmt.Errorf("brandit: delete record: %w", err)
}
// deletes record ID from map
d.recordsMu.Lock()
delete(d.records, token)
d.recordsMu.Unlock()
return nil
}
// Timeout returns the timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval
}

View File

@ -0,0 +1,24 @@
Name = "BRANDIT"
Description = ''''''
URL = "https://www.brandit.com/"
Code = "brandit"
Since = "v4.11.0"
Example = '''
BRANDIT_API_KEY=xxxxxxxxxxxxxxxxxxxxx \
BRANDIT_API_USERNAME=yyyyyyyyyyyyyyyyyyyy \
lego --email myemail@example.com --dns brandit --domains my.example.org run
'''
[Configuration]
[Configuration.Credentials]
BRANDIT_API_KEY = "The API key"
BRANDIT_API_USERNAME = "The API username"
[Configuration.Additional]
BRANDIT_POLLING_INTERVAL = "Time between DNS propagation check"
BRANDIT_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
BRANDIT_TTL = "The TTL of the TXT record used for the DNS challenge"
BRANDIT_HTTP_TIMEOUT = "API request timeout"
[Links]
API = "https://portal.brandit.com/apidocv3"

View File

@ -0,0 +1,141 @@
package brandit
import (
"testing"
"github.com/go-acme/lego/v4/platform/tester"
"github.com/stretchr/testify/require"
)
const envDomain = envNamespace + "DOMAIN"
var envTest = tester.NewEnvTest(EnvAPIKey, EnvAPIUsername).WithDomain(envDomain)
func TestNewDNSProvider(t *testing.T) {
testCases := []struct {
desc string
envVars map[string]string
expected string
}{
{
desc: "success",
envVars: map[string]string{
EnvAPIKey: "key",
EnvAPIUsername: "test_user",
},
},
{
desc: "missing API key",
envVars: map[string]string{
EnvAPIUsername: "test_user",
},
expected: "brandit: some credentials information are missing: BRANDIT_API_KEY",
},
{
desc: "missing secret",
envVars: map[string]string{
EnvAPIKey: "key",
},
expected: "brandit: some credentials information are missing: BRANDIT_API_USERNAME",
},
{
desc: "missing credentials",
envVars: map[string]string{},
expected: "brandit: some credentials information are missing: BRANDIT_API_KEY,BRANDIT_API_USERNAME",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
envTest.ClearEnv()
envTest.Apply(test.envVars)
p, err := NewDNSProvider()
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
require.NotNil(t, p.config)
require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
})
}
}
func TestNewDNSProviderConfig(t *testing.T) {
testCases := []struct {
desc string
apiKey string
user string
expected string
}{
{
desc: "success",
apiKey: "key",
user: "test_user",
},
{
desc: "missing API key",
user: "test_user",
expected: "brandit: credentials missing",
},
{
desc: "missing secret",
apiKey: "key",
expected: "brandit: credentials missing",
},
{
desc: "missing credentials",
expected: "brandit: credentials missing",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
config := NewDefaultConfig()
config.APIKey = test.apiKey
config.APIUsername = test.user
p, err := NewDNSProviderConfig(config)
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
require.NotNil(t, p.config)
require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
})
}
}
func TestLivePresent(t *testing.T) {
if !envTest.IsLiveTest() {
t.Skip("skipping live test")
}
envTest.RestoreEnv()
provider, err := NewDNSProvider()
require.NoError(t, err)
err = provider.Present(envTest.GetDomain(), "", "123d==")
require.NoError(t, err)
}
func TestLiveCleanUp(t *testing.T) {
if !envTest.IsLiveTest() {
t.Skip("skipping live test")
}
envTest.RestoreEnv()
provider, err := NewDNSProvider()
require.NoError(t, err)
err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
require.NoError(t, err)
}

View File

@ -0,0 +1,198 @@
package internal
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
)
const defaultBaseURL = "https://portal.brandit.com/api/v3/"
// Client a BrandIT DNS API client.
type Client struct {
apiUsername string
apiKey string
BaseURL string
HTTPClient *http.Client
}
// NewClient creates a new Client.
func NewClient(apiUsername, apiKey string) (*Client, error) {
if apiKey == "" || apiUsername == "" {
return nil, errors.New("credentials missing")
}
return &Client{
apiUsername: apiUsername,
apiKey: apiKey,
BaseURL: defaultBaseURL,
HTTPClient: &http.Client{Timeout: 10 * time.Second},
}, nil
}
// ListRecords lists all records.
// https://portal.brandit.com/apidocv3#listDNSRR
func (c *Client) ListRecords(account, dnsZone string) (*ListRecords, error) {
// Create a new query
query := url.Values{}
query.Add("command", "listDNSRR")
query.Add("account", account)
query.Add("dnszone", dnsZone)
result := &ListRecords{}
err := c.do(query, result)
if err != nil {
return nil, fmt.Errorf("do: %w", err)
}
for len(result.Response.RR) < result.Response.Total[0] {
query.Add("first", fmt.Sprint(result.Response.Last[0]+1))
tmp := &ListRecords{}
err := c.do(query, tmp)
if err != nil {
return nil, fmt.Errorf("do: %w", err)
}
result.Response.RR = append(result.Response.RR, tmp.Response.RR...)
result.Response.Last = tmp.Response.Last
}
return result, nil
}
// AddRecord adds a DNS record.
// https://portal.brandit.com/apidocv3#addDNSRR
func (c *Client) AddRecord(domainName, account, newRecordID string, record Record) (*AddRecord, error) {
// Create a new query
query := url.Values{}
query.Add("command", "addDNSRR")
query.Add("account", account)
query.Add("dnszone", domainName)
query.Add("rrdata", strings.Join([]string{record.Name, fmt.Sprint(record.TTL), "IN", record.Type, record.Content}, " "))
query.Add("key", newRecordID)
result := &AddRecord{}
err := c.do(query, result)
if err != nil {
return nil, fmt.Errorf("do: %w", err)
}
result.Record = strings.Join([]string{record.Name, fmt.Sprint(record.TTL), "IN", record.Type, record.Content}, " ")
return result, nil
}
// DeleteRecord deletes a DNS record.
// https://portal.brandit.com/apidocv3#deleteDNSRR
func (c *Client) DeleteRecord(domainName, account, dnsRecord, recordID string) (*DeleteRecord, error) {
// Create a new query
query := url.Values{}
query.Add("command", "deleteDNSRR")
query.Add("account", account)
query.Add("dnszone", domainName)
query.Add("rrdata", dnsRecord)
query.Add("key", recordID)
result := &DeleteRecord{}
err := c.do(query, result)
if err != nil {
return nil, fmt.Errorf("do: %w", err)
}
return result, nil
}
// StatusDomain returns the status of a domain and account associated with it.
// https://portal.brandit.com/apidocv3#statusDomain
func (c *Client) StatusDomain(domain string) (*StatusDomain, error) {
// Create a new query
query := url.Values{}
query.Add("command", "statusDomain")
query.Add("domain", domain)
result := &StatusDomain{}
err := c.do(query, result)
if err != nil {
return nil, fmt.Errorf("do: %w", err)
}
return result, nil
}
func (c *Client) do(query url.Values, result any) error {
// Add signature
v, err := sign(c.apiUsername, c.apiKey, query)
if err != nil {
return fmt.Errorf("signature: %w", err)
}
resp, err := c.HTTPClient.PostForm(c.BaseURL, v)
if err != nil {
return err
}
defer func() { _ = resp.Body.Close() }()
raw, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read response body: %w", err)
}
// Unmarshal the error response, because the API returns a 200 OK even if there is an error.
var apiError APIError
err = json.Unmarshal(raw, &apiError)
if err != nil {
return fmt.Errorf("unmarshal error response: %w %s", err, string(raw))
}
if apiError.Code > 299 || apiError.Status != "success" {
return apiError
}
err = json.Unmarshal(raw, result)
if err != nil {
return fmt.Errorf("unmarshal response body: %w %s", err, string(raw))
}
return nil
}
func sign(apiUsername, apiKey string, query url.Values) (url.Values, error) {
location, err := time.LoadLocation("GMT")
if err != nil {
return nil, fmt.Errorf("time location: %w", err)
}
timestamp := time.Now().In(location).Format("2006-01-02T15:04:05Z")
canonicalRequest := fmt.Sprintf("%s%s%s", apiUsername, timestamp, defaultBaseURL)
mac := hmac.New(sha256.New, []byte(apiKey))
_, err = mac.Write([]byte(canonicalRequest))
if err != nil {
return nil, err
}
hashed := mac.Sum(nil)
signature := hex.EncodeToString(hashed)
query.Add("user", apiUsername)
query.Add("timestamp", timestamp)
query.Add("signature", signature)
return query, nil
}

View File

@ -0,0 +1,149 @@
package internal
import (
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func setupTest(t *testing.T, file string) *Client {
t.Helper()
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
open, err := os.Open(file)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
defer func() { _ = open.Close() }()
rw.WriteHeader(http.StatusOK)
_, err = io.Copy(rw, open)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
}))
t.Cleanup(server.Close)
client, err := NewClient("test_user", "apiKey")
require.NoError(t, err)
client.HTTPClient = server.Client()
client.BaseURL = server.URL
return client
}
func TestClient_StatusDomain(t *testing.T) {
client := setupTest(t, "./fixtures/status-domain.json")
domain, err := client.StatusDomain("example.com")
require.NoError(t, err)
expected := &StatusDomain{
Response: StatusResponse{
RenewalMode: []string{"DEFAULT"},
Status: []string{"clientTransferProhibited"},
TransferLock: []int{1},
Registrar: []string{"brandit"},
PaidUntilDate: []string{"2021-12-15 05:00:00.0"},
Nameserver: []string{"NS1.RRPPROXY.NET", "NS2.RRPPROXY.NET"},
RegistrationExpirationDate: []string{"2021-12-15 05:00:00.0"},
Domain: []string{"example.com"},
RenewalDate: []string{"2024-01-19 05:00:00.0"},
UpdatedDate: []string{"2022-12-16 08:01:27.0"},
BillingContact: []string{"example"},
XDomainRoID: []string{"example"},
AdminContact: []string{"example"},
TechContact: []string{"example"},
DomainIDN: []string{"example.com"},
CreatedDate: []string{"2016-12-16 05:00:00.0"},
RegistrarTransferDate: []string{"2021-12-09 05:17:42.0"},
Zone: []string{"com"},
Auth: []string{"example"},
UpdatedBy: []string{"example"},
RoID: []string{"example"},
OwnerContact: []string{"example"},
CreatedBy: []string{"example"},
TransferMode: []string{"auto"},
},
Code: 200,
Status: "success",
Error: "",
}
assert.Equal(t, expected, domain)
}
func TestClient_ListRecords(t *testing.T) {
client := setupTest(t, "./fixtures/list-records.json")
resp, err := client.ListRecords("example", "example.com")
require.NoError(t, err)
expected := &ListRecords{
Response: ListRecordsResponse{
Limit: []int{100},
Column: []string{"rr"},
Count: []int{1},
First: []int{0},
Total: []int{1},
RR: []string{"example.com. 600 IN TXT txttxttxt"},
Last: []int{0},
},
Code: 200,
Status: "success",
Error: "",
}
assert.Equal(t, expected, resp)
}
func TestClient_AddRecord(t *testing.T) {
client := setupTest(t, "./fixtures/add-record.json")
testRecord := Record{
ID: 2565,
Type: "TXT",
Name: "example.com",
Content: "txttxttxt",
TTL: 600,
}
resp, err := client.AddRecord("example.com", "test", "2565", testRecord)
require.NoError(t, err)
expected := &AddRecord{
Response: AddRecordResponse{
ZoneType: []string{"com"},
Signed: []int{1},
},
Record: "example.com 600 IN TXT txttxttxt",
Code: 200,
Status: "success",
Error: "",
}
assert.Equal(t, expected, resp)
}
func TestClient_DeleteRecord(t *testing.T) {
client := setupTest(t, "./fixtures/delete-record.json")
resp, err := client.DeleteRecord("example.com", "test", "example.com 600 IN TXT txttxttxt", "2374")
require.NoError(t, err)
expected := &DeleteRecord{
Code: 200,
Status: "success",
Error: "",
}
assert.Equal(t, expected, resp)
}

View File

@ -0,0 +1,14 @@
{
"response": {
"zonetype": [
"com"
],
"signed": [
1
]
},
"record": "example.com. 600 IN TXT txttxttxt",
"code": 200,
"status": "success",
"error": ""
}

View File

@ -0,0 +1,5 @@
{
"code": 200,
"status": "success",
"error": ""
}

View File

@ -0,0 +1,28 @@
{
"response": {
"limit": [
100
],
"column": [
"rr"
],
"count": [
1
],
"first": [
0
],
"total": [
1
],
"rr": [
"example.com. 600 IN TXT txttxttxt"
],
"last": [
0
]
},
"code": 200,
"status": "success",
"error": ""
}

View File

@ -0,0 +1,80 @@
{
"response": {
"renewalmode": [
"DEFAULT"
],
"status": [
"clientTransferProhibited"
],
"transferlock": [
1
],
"registrar": [
"brandit"
],
"paiduntildate": [
"2021-12-15 05:00:00.0"
],
"nameserver": [
"NS1.RRPPROXY.NET",
"NS2.RRPPROXY.NET"
],
"registrationexpirationdate": [
"2021-12-15 05:00:00.0"
],
"domain": [
"example.com"
],
"renewaldate": [
"2024-01-19 05:00:00.0"
],
"updateddate": [
"2022-12-16 08:01:27.0"
],
"billingcontact": [
"example"
],
"x-domain-roid": [
"example"
],
"admincontact": [
"example"
],
"techcontact": [
"example"
],
"domainidn": [
"example.com"
],
"createddate": [
"2016-12-16 05:00:00.0"
],
"registrartransferdate": [
"2021-12-09 05:17:42.0"
],
"zone": [
"com"
],
"auth": [
"example"
],
"updatedby": [
"example"
],
"roid": [
"example"
],
"ownercontact": [
"example"
],
"createdby": [
"example"
],
"transfermode": [
"auto"
]
},
"code": 200,
"status": "success",
"error": ""
}

View File

@ -0,0 +1,91 @@
package internal
import "fmt"
type StatusDomain struct {
Response StatusResponse `json:"response,omitempty"`
Code int `json:"code"`
Status string `json:"status"`
Error string `json:"error"`
}
type StatusResponse struct {
RenewalMode []string `json:"renewalmode"`
Status []string `json:"status"`
TransferLock []int `json:"transferlock"`
Registrar []string `json:"registrar"`
PaidUntilDate []string `json:"paiduntildate"`
Nameserver []string `json:"nameserver"`
RegistrationExpirationDate []string `json:"registrationexpirationdate"`
Domain []string `json:"domain"`
RenewalDate []string `json:"renewaldate"`
UpdatedDate []string `json:"updateddate"`
BillingContact []string `json:"billingcontact"`
XDomainRoID []string `json:"x-domain-roid"`
AdminContact []string `json:"admincontact"`
TechContact []string `json:"techcontact"`
DomainIDN []string `json:"domainidn"`
CreatedDate []string `json:"createddate"`
RegistrarTransferDate []string `json:"registrartransferdate"`
Zone []string `json:"zone"`
Auth []string `json:"auth"`
UpdatedBy []string `json:"updatedby"`
RoID []string `json:"roid"`
OwnerContact []string `json:"ownercontact"`
CreatedBy []string `json:"createdby"`
TransferMode []string `json:"transfermode"`
}
type ListRecords struct {
Response ListRecordsResponse `json:"response,omitempty"`
Code int `json:"code"`
Status string `json:"status"`
Error string `json:"error"`
}
type ListRecordsResponse struct {
Limit []int `json:"limit,omitempty"`
Column []string `json:"column,omitempty"`
Count []int `json:"count,omitempty"`
First []int `json:"first,omitempty"`
Total []int `json:"total,omitempty"`
RR []string `json:"rr,omitempty"`
Last []int `json:"last,omitempty"`
}
type APIError struct {
Code int `json:"code"`
Status string `json:"status"`
Message string `json:"error"`
}
func (a APIError) Error() string {
return fmt.Sprintf("code: %d, status: %s, message: %s", a.Code, a.Status, a.Message)
}
type AddRecord struct {
Response AddRecordResponse `json:"response"`
Record string `json:"record"`
Code int `json:"code"`
Status string `json:"status"`
Error string `json:"error"`
}
type AddRecordResponse struct {
ZoneType []string `json:"zonetype"`
Signed []int `json:"signed"`
}
type Record struct {
ID int `json:"id,omitempty"`
Type string `json:"type,omitempty"`
Name string `json:"name,omitempty"` // subdomain name or @ if you don't want subdomain
Content string `json:"content,omitempty"`
TTL int `json:"ttl,omitempty"` // default 600
}
type DeleteRecord struct {
Code int `json:"code"`
Status string `json:"status"`
Error string `json:"error"`
}

View File

@ -14,6 +14,7 @@ import (
"github.com/go-acme/lego/v4/providers/dns/azure"
"github.com/go-acme/lego/v4/providers/dns/bindman"
"github.com/go-acme/lego/v4/providers/dns/bluecat"
"github.com/go-acme/lego/v4/providers/dns/brandit"
"github.com/go-acme/lego/v4/providers/dns/bunny"
"github.com/go-acme/lego/v4/providers/dns/checkdomain"
"github.com/go-acme/lego/v4/providers/dns/civo"
@ -143,6 +144,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return bindman.NewDNSProvider()
case "bluecat":
return bluecat.NewDNSProvider()
case "brandit":
return brandit.NewDNSProvider()
case "bunny":
return bunny.NewDNSProvider()
case "checkdomain":