provider.go raw
1 // Package rimuhosting implements a DNS provider for solving the DNS-01 challenge using RimuHosting DNS.
2 package rimuhosting
3
4 import (
5 "context"
6 "errors"
7 "fmt"
8 "net/http"
9 "time"
10
11 "github.com/go-acme/lego/v4/challenge"
12 "github.com/go-acme/lego/v4/challenge/dns01"
13 "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
14 "github.com/go-acme/lego/v4/providers/dns/internal/rimuhosting/internal"
15 )
16
17 const DefaultTTL = 3600
18
19 var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
20
21 // Config is used to configure the creation of the DNSProvider.
22 type Config struct {
23 APIKey string
24
25 PropagationTimeout time.Duration
26 PollingInterval time.Duration
27 TTL int
28 HTTPClient *http.Client
29 }
30
31 // DNSProvider implements the challenge.Provider interface.
32 type DNSProvider struct {
33 config *Config
34 client *internal.Client
35 }
36
37 // NewDNSProviderConfig return a DNSProvider instance configured for RimuHosting.
38 func NewDNSProviderConfig(config *Config, baseURL string) (*DNSProvider, error) {
39 if config == nil {
40 return nil, errors.New("the configuration of the DNS provider is nil")
41 }
42
43 if config.APIKey == "" {
44 return nil, errors.New("incomplete credentials, missing API key")
45 }
46
47 client := internal.NewClient(config.APIKey)
48
49 if baseURL != "" {
50 client.BaseURL = baseURL
51 }
52
53 if config.HTTPClient != nil {
54 client.HTTPClient = config.HTTPClient
55 }
56
57 client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
58
59 return &DNSProvider{config: config, client: client}, nil
60 }
61
62 // Timeout returns the timeout and interval to use when checking for DNS propagation.
63 // Adjusting here to cope with spikes in propagation times.
64 func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
65 return d.config.PropagationTimeout, d.config.PollingInterval
66 }
67
68 // Present creates a TXT record using the specified parameters.
69 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
70 info := dns01.GetChallengeInfo(domain, keyAuth)
71
72 ctx := context.Background()
73
74 records, err := d.client.FindTXTRecords(ctx, dns01.UnFqdn(info.EffectiveFQDN))
75 if err != nil {
76 return fmt.Errorf("failed to find record(s) for %s: %w", domain, err)
77 }
78
79 actions := []internal.ActionParameter{
80 internal.NewAddRecordAction(dns01.UnFqdn(info.EffectiveFQDN), info.Value, d.config.TTL),
81 }
82
83 for _, record := range records {
84 actions = append(actions, internal.NewAddRecordAction(record.Name, record.Content, d.config.TTL))
85 }
86
87 _, err = d.client.DoActions(ctx, actions...)
88 if err != nil {
89 return fmt.Errorf("failed to add record(s) for %s: %w", domain, err)
90 }
91
92 return nil
93 }
94
95 // CleanUp removes the TXT record matching the specified parameters.
96 func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
97 info := dns01.GetChallengeInfo(domain, keyAuth)
98
99 action := internal.NewDeleteRecordAction(dns01.UnFqdn(info.EffectiveFQDN), info.Value)
100
101 _, err := d.client.DoActions(context.Background(), action)
102 if err != nil {
103 return fmt.Errorf("failed to delete record for %s: %w", domain, err)
104 }
105
106 return nil
107 }
108