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