Skip to content

Commit

Permalink
Add DNS provider for DirectAdmin (#2225)
Browse files Browse the repository at this point in the history
Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
  • Loading branch information
jwklijnsma and ldez authored Jul 21, 2024
1 parent 9873b9b commit c759f56
Show file tree
Hide file tree
Showing 11 changed files with 750 additions and 27 deletions.
52 changes: 26 additions & 26 deletions README.md

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions cmd/zz_gen_cmd_dnshelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func allDNSCodes() string {
"desec",
"designate",
"digitalocean",
"directadmin",
"dnshomede",
"dnsimple",
"dnsmadeeasy",
Expand Down Expand Up @@ -733,6 +734,29 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/digitalocean`)

case "directadmin":
// generated from: providers/dns/directadmin/directadmin.toml
ew.writeln(`Configuration for directadmin.`)
ew.writeln(`Code: 'directadmin'`)
ew.writeln(`Since: ''`)
ew.writeln()

ew.writeln(`Credentials:`)
ew.writeln(` - "DIRECTADMIN_API_URL": URL of the API`)
ew.writeln(` - "DIRECTADMIN_PASSWORD": API password`)
ew.writeln(` - "DIRECTADMIN_USERNAME": API username`)
ew.writeln()

ew.writeln(`Additional Configuration:`)
ew.writeln(` - "DIRECTADMIN_HTTP_TIMEOUT": API request timeout`)
ew.writeln(` - "DIRECTADMIN_POLLING_INTERVAL": Time between DNS propagation check`)
ew.writeln(` - "DIRECTADMIN_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
ew.writeln(` - "DIRECTADMIN_TTL": The TTL of the TXT record used for the DNS challenge`)
ew.writeln(` - "DIRECTADMIN_ZONE_NAME": API password`)

ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/directadmin`)

case "dnshomede":
// generated from: providers/dns/dnshomede/dnshomede.toml
ew.writeln(`Configuration for dnsHome.de.`)
Expand Down
71 changes: 71 additions & 0 deletions docs/content/dns/zz_gen_directadmin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: "directadmin"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: directadmin
dnsprovider:
since: ""
code: "directadmin"
url: "directadmin"
---

<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/directadmin/directadmin.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

directadmin api


<!--more-->

- Code: `directadmin`
- Since:


Here is an example bash command using the directadmin provider:

```bash
DIRECTADMIN_API_URL="http://example.com:2222" \
DIRECTADMIN_USERNAME=xxxx \
DIRECTADMIN_PASSWORD=yyy \
lego --email you@example.com --dns directadmin -d "my.example.org" -d "*.example.org" run
```




## Credentials

| Environment Variable Name | Description |
|-----------------------|-------------|
| `DIRECTADMIN_API_URL` | URL of the API |
| `DIRECTADMIN_PASSWORD` | API password |
| `DIRECTADMIN_USERNAME` | 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 |
|--------------------------------|-------------|
| `DIRECTADMIN_HTTP_TIMEOUT` | API request timeout |
| `DIRECTADMIN_POLLING_INTERVAL` | Time between DNS propagation check |
| `DIRECTADMIN_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
| `DIRECTADMIN_TTL` | The TTL of the TXT record used for the DNS challenge |
| `DIRECTADMIN_ZONE_NAME` | API password |

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://www.directadmin.com/api.php)

<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/directadmin/directadmin.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
2 changes: 1 addition & 1 deletion docs/data/zz_cli_help.toml
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,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, azuredns, bindman, bluecat, brandit, bunny, checkdomain, civo, clouddns, cloudflare, cloudns, cloudru, cloudxns, conoha, constellix, cpanel, derak, desec, designate, digitalocean, dnshomede, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, dreamhost, duckdns, dyn, dynu, easydns, edgedns, efficientip, epik, exec, exoscale, freemyip, gandi, gandiv5, gcloud, gcore, glesys, godaddy, googledomains, hetzner, hostingde, hosttech, httpnet, httpreq, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, infomaniak, internetbs, inwx, ionos, ipv64, iwantmyname, joker, liara, lightsail, linode, liquidweb, loopia, luadns, mailinabox, manual, metaname, mydnsjp, mythicbeasts, namecheap, namedotcom, namesilo, nearlyfreespeech, netcup, netlify, nicmanager, nifcloud, njalla, nodion, ns1, oraclecloud, otc, ovh, pdns, plesk, porkbun, rackspace, rcodezero, regru, rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, selectelv2, servercow, shellrent, simply, sonic, stackpath, tencentcloud, transip, ultradns, variomedia, vegadns, vercel, versio, vinyldns, vkcloud, vscale, vultr, webnames, websupport, wedos, yandex, yandex360, yandexcloud, zoneee, zonomi
acme-dns, alidns, allinkl, arvancloud, auroradns, autodns, azure, azuredns, bindman, bluecat, brandit, bunny, checkdomain, civo, clouddns, cloudflare, cloudns, cloudru, cloudxns, conoha, constellix, cpanel, derak, desec, designate, digitalocean, directadmin, dnshomede, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, dreamhost, duckdns, dyn, dynu, easydns, edgedns, efficientip, epik, exec, exoscale, freemyip, gandi, gandiv5, gcloud, gcore, glesys, godaddy, googledomains, hetzner, hostingde, hosttech, httpnet, httpreq, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, infomaniak, internetbs, inwx, ionos, ipv64, iwantmyname, joker, liara, lightsail, linode, liquidweb, loopia, luadns, mailinabox, manual, metaname, mydnsjp, mythicbeasts, namecheap, namedotcom, namesilo, nearlyfreespeech, netcup, netlify, nicmanager, nifcloud, njalla, nodion, ns1, oraclecloud, otc, ovh, pdns, plesk, porkbun, rackspace, rcodezero, regru, rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, selectelv2, servercow, shellrent, simply, sonic, stackpath, tencentcloud, transip, ultradns, variomedia, vegadns, vercel, versio, vinyldns, vkcloud, vscale, vultr, webnames, websupport, wedos, yandex, yandex360, yandexcloud, zoneee, zonomi
More information: https://go-acme.github.io/lego/dns
"""
163 changes: 163 additions & 0 deletions providers/dns/directadmin/directadmin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package directadmin

import (
"context"
"errors"
"fmt"
"net/http"
"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/directadmin/internal"
)

// Environment variables names.
const (
envNamespace = "DIRECTADMIN_"

EnvAPIURL = envNamespace + "API_URL"
EnvUsername = envNamespace + "USERNAME"
EnvPassword = envNamespace + "PASSWORD"
EnvZoneName = envNamespace + "ZONE_NAME"

EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)

// Config is used to configure the creation of the DNSProvider.
type Config struct {
BaseURL string
Username string
Password string
TTL int
PropagationTimeout time.Duration
PollingInterval time.Duration
HTTPClient *http.Client
}

// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
TTL: env.GetOrDefaultInt(EnvTTL, 30),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 60*time.Second),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 5*time.Second),
HTTPClient: &http.Client{
Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
},
}
}

// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
client *internal.Client
config *Config
}

// NewDNSProvider returns a DNSProvider instance configured for DirectAdmin.
// Credentials must be passed in the environment variables:
// DIRECTADMIN_API_URL, DIRECTADMIN_USERNAME, DIRECTADMIN_PASSWORD.
func NewDNSProvider() (*DNSProvider, error) {
values, err := env.Get(EnvAPIURL, EnvUsername, EnvPassword)
if err != nil {
return nil, fmt.Errorf("directadmin: %w", err)
}

config := NewDefaultConfig()
config.BaseURL = values[EnvAPIURL]
config.Username = values[EnvUsername]
config.Password = values[EnvPassword]

return NewDNSProviderConfig(config)
}

// NewDNSProviderConfig return a DNSProvider instance configured for DirectAdmin.
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config.BaseURL == "" {
return nil, errors.New("directadmin: missing API URL")
}

if config.Username == "" || config.Password == "" {
return nil, errors.New("directadmin: some credentials information are missing")
}

client, err := internal.NewClient(config.BaseURL, config.Username, config.Password)
if err != nil {
return nil, fmt.Errorf("directadmin: %w", err)
}

return &DNSProvider{client: client, config: config}, 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 := getAuthZone(info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("directadmin: [domain: %q] %w", domain, err)
}

subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
if err != nil {
return fmt.Errorf("directadmin: %w", err)
}

record := internal.Record{
Name: subDomain,
Type: "TXT",
Value: info.Value,
TTL: d.config.TTL,
}

err = d.client.SetRecord(context.Background(), dns01.UnFqdn(authZone), record)
if err != nil {
return fmt.Errorf("directadmin: set record for zone %s and subdomain %s: %w", authZone, subDomain, err)
}

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 := getAuthZone(info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("directadmin: [domain: %q] %w", domain, err)
}

subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
if err != nil {
return fmt.Errorf("directadmin: %w", err)
}

record := internal.Record{
Name: subDomain,
Type: "TXT",
Value: info.Value,
}

err = d.client.DeleteRecord(context.Background(), dns01.UnFqdn(authZone), record)
if err != nil {
return fmt.Errorf("directadmin: delete record for zone %s and subdomain %s: %w", authZone, subDomain, err)
}

return nil
}

func getAuthZone(fqdn string) (string, error) {
authZone := env.GetOrFile(EnvZoneName)
if authZone != "" {
return authZone, nil
}

authZone, err := dns01.FindZoneByFqdn(fqdn)
if err != nil {
return "", fmt.Errorf("could not find zone for %s: %w", fqdn, err)
}

return authZone, nil
}
27 changes: 27 additions & 0 deletions providers/dns/directadmin/directadmin.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Name = "directadmin"
Description = '''directadmin api'''
URL = "directadmin"
Code = "directadmin"


Example = '''
DIRECTADMIN_API_URL="http://example.com:2222" \
DIRECTADMIN_USERNAME=xxxx \
DIRECTADMIN_PASSWORD=yyy \
lego --email you@example.com --dns directadmin -d "my.example.org" -d "*.example.org" run
'''

[Configuration]
[Configuration.Credentials]
DIRECTADMIN_API_URL = "URL of the API"
DIRECTADMIN_USERNAME = "API username"
DIRECTADMIN_PASSWORD = "API password"
[Configuration.Additional]
DIRECTADMIN_ZONE_NAME = "API password"
DIRECTADMIN_POLLING_INTERVAL = "Time between DNS propagation check"
DIRECTADMIN_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
DIRECTADMIN_TTL = "The TTL of the TXT record used for the DNS challenge"
DIRECTADMIN_HTTP_TIMEOUT = "API request timeout"

[Links]
API = "https://www.directadmin.com/api.php"
Loading

0 comments on commit c759f56

Please sign in to comment.