provider_svc.go raw
1 package joker
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "time"
8
9 "github.com/go-acme/lego/v4/challenge"
10 "github.com/go-acme/lego/v4/challenge/dns01"
11 "github.com/go-acme/lego/v4/platform/config/env"
12 "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
13 "github.com/go-acme/lego/v4/providers/dns/joker/internal/svc"
14 )
15
16 var _ challenge.ProviderTimeout = (*svcProvider)(nil)
17
18 // svcProvider implements the challenge.Provider interface.
19 type svcProvider struct {
20 config *Config
21 client *svc.Client
22 }
23
24 // newSvcProvider returns a DNSProvider instance configured for Joker.
25 // Credentials must be passed in the environment variable: JOKER_USERNAME, JOKER_PASSWORD.
26 func newSvcProvider() (*svcProvider, error) {
27 values, err := env.Get(EnvUsername, EnvPassword)
28 if err != nil {
29 return nil, fmt.Errorf("joker: %w", err)
30 }
31
32 config := NewDefaultConfig()
33 config.Username = values[EnvUsername]
34 config.Password = values[EnvPassword]
35
36 return newSvcProviderConfig(config)
37 }
38
39 // newSvcProviderConfig return a DNSProvider instance configured for Joker.
40 func newSvcProviderConfig(config *Config) (*svcProvider, error) {
41 if config == nil {
42 return nil, errors.New("joker: the configuration of the DNS provider is nil")
43 }
44
45 if config.Username == "" || config.Password == "" {
46 return nil, errors.New("joker: credentials missing")
47 }
48
49 client := svc.NewClient(config.Username, config.Password)
50
51 client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
52
53 return &svcProvider{config: config, client: client}, nil
54 }
55
56 // Timeout returns the timeout and interval to use when checking for DNS propagation.
57 // Adjusting here to cope with spikes in propagation times.
58 func (d *svcProvider) Timeout() (timeout, interval time.Duration) {
59 return d.config.PropagationTimeout, d.config.PollingInterval
60 }
61
62 // Present creates a TXT record using the specified parameters.
63 func (d *svcProvider) Present(domain, token, keyAuth string) error {
64 info := dns01.GetChallengeInfo(domain, keyAuth)
65
66 zone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
67 if err != nil {
68 return fmt.Errorf("joker: could not find zone for domain %q: %w", domain, err)
69 }
70
71 subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
72 if err != nil {
73 return fmt.Errorf("joker: %w", err)
74 }
75
76 return d.client.SendRequest(context.Background(), dns01.UnFqdn(zone), subDomain, info.Value)
77 }
78
79 // CleanUp removes the TXT record matching the specified parameters.
80 func (d *svcProvider) CleanUp(domain, token, keyAuth string) error {
81 info := dns01.GetChallengeInfo(domain, keyAuth)
82
83 zone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
84 if err != nil {
85 return fmt.Errorf("joker: could not find zone for domain %q: %w", domain, err)
86 }
87
88 subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
89 if err != nil {
90 return fmt.Errorf("joker: %w", err)
91 }
92
93 return d.client.SendRequest(context.Background(), dns01.UnFqdn(zone), subDomain, "")
94 }
95
96 // Sequential All DNS challenges for this provider will be resolved sequentially.
97 // Returns the interval between each iteration.
98 func (d *svcProvider) Sequential() time.Duration {
99 return d.config.SequenceInterval
100 }
101