client.go raw
1 package internal
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "io"
8 "net/http"
9 "net/url"
10 "strings"
11 "time"
12
13 "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
14 )
15
16 const defaultBaseURL = "https://www.webnames.ru/scripts/json_domain_zone_manager.pl"
17
18 // Client the Webnames API client.
19 type Client struct {
20 apiKey string
21
22 baseURL string
23 HTTPClient *http.Client
24 }
25
26 // NewClient Creates a new Client.
27 func NewClient(apiKey string) *Client {
28 return &Client{
29 apiKey: apiKey,
30 baseURL: defaultBaseURL,
31 HTTPClient: &http.Client{Timeout: 10 * time.Second},
32 }
33 }
34
35 // AddTXTRecord adds a TXT record.
36 // Inspired by https://github.com/regtime-ltd/certbot-dns-webnames/blob/master/authenticator.sh
37 func (c *Client) AddTXTRecord(ctx context.Context, domain, subDomain, value string) error {
38 data := url.Values{}
39 data.Set("domain", domain)
40 data.Set("type", "TXT")
41 data.Set("record", subDomain+":"+value)
42 data.Set("action", "add")
43
44 return c.doRequest(ctx, data)
45 }
46
47 // RemoveTXTRecord removes a TXT record.
48 // Inspired by https://github.com/regtime-ltd/certbot-dns-webnames/blob/master/cleanup.sh
49 func (c *Client) RemoveTXTRecord(ctx context.Context, domain, subDomain, value string) error {
50 data := url.Values{}
51 data.Set("domain", domain)
52 data.Set("type", "TXT")
53 data.Set("record", subDomain+":"+value)
54 data.Set("action", "delete")
55
56 return c.doRequest(ctx, data)
57 }
58
59 func (c *Client) doRequest(ctx context.Context, data url.Values) error {
60 data.Set("apikey", c.apiKey)
61
62 req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL, strings.NewReader(data.Encode()))
63 if err != nil {
64 return err
65 }
66
67 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
68
69 resp, err := c.HTTPClient.Do(req)
70 if err != nil {
71 return errutils.NewHTTPDoError(req, err)
72 }
73
74 defer func() { _ = resp.Body.Close() }()
75
76 if resp.StatusCode/100 != 2 {
77 return errutils.NewUnexpectedResponseStatusCodeError(req, resp)
78 }
79
80 raw, err := io.ReadAll(resp.Body)
81 if err != nil {
82 return errutils.NewReadResponseError(req, resp.StatusCode, err)
83 }
84
85 var r APIResponse
86
87 err = json.Unmarshal(raw, &r)
88 if err != nil {
89 return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
90 }
91
92 if r.Result == "OK" {
93 return nil
94 }
95
96 return fmt.Errorf("%s: %s", r.Result, r.Details)
97 }
98