From 4f9e9d4e7ee5bc955e34e6a3d42b0a497bec2e07 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 12 Apr 2023 21:04:05 +0200 Subject: [PATCH] review: 5 --- cmd/zz_gen_cmd_dnshelp.go | 16 +- docs/content/dns/zz_gen_nicru.md | 40 +-- providers/dns/nicru/internal/client.go | 35 ++- providers/dns/nicru/internal/client_test.go | 286 ++++++++++++++++++ .../nicru/internal/fixtures/commit_POST.xml | 4 + .../dns/nicru/internal/fixtures/errors.xml | 7 + .../nicru/internal/fixtures/records_GET.xml | 55 ++++ .../nicru/internal/fixtures/records_PUT.xml | 10 + .../dns/nicru/internal/fixtures/zones_GET.xml | 12 + providers/dns/nicru/internal/types.go | 249 ++++++++------- providers/dns/nicru/nicru.go | 2 +- providers/dns/nicru/nicru.toml | 40 +-- providers/dns/nicru/nicru_test.go | 10 +- 13 files changed, 582 insertions(+), 184 deletions(-) create mode 100644 providers/dns/nicru/internal/client_test.go create mode 100644 providers/dns/nicru/internal/fixtures/commit_POST.xml create mode 100644 providers/dns/nicru/internal/fixtures/errors.xml create mode 100644 providers/dns/nicru/internal/fixtures/records_GET.xml create mode 100644 providers/dns/nicru/internal/fixtures/records_PUT.xml create mode 100644 providers/dns/nicru/internal/fixtures/zones_GET.xml diff --git a/cmd/zz_gen_cmd_dnshelp.go b/cmd/zz_gen_cmd_dnshelp.go index 1c59735402..50a64f4031 100644 --- a/cmd/zz_gen_cmd_dnshelp.go +++ b/cmd/zz_gen_cmd_dnshelp.go @@ -1727,17 +1727,17 @@ func displayDNSHelp(w io.Writer, name string) error { ew.writeln() ew.writeln(`Credentials:`) - ew.writeln(` - "NIC_RU_PASSWORD": Password for account in RU CENTER`) - ew.writeln(` - "NIC_RU_SECRET": Secret for application in DNS-hosting RU CENTER`) - ew.writeln(` - "NIC_RU_SERVICE_ID": Service ID for application in DNS-hosting RU CENTER`) - ew.writeln(` - "NIC_RU_SERVICE_NAME": Service Name for DNS-hosting RU CENTER`) - ew.writeln(` - "NIC_RU_USER": Agreement for account in RU CENTER`) + ew.writeln(` - "NICRU_PASSWORD": Password for account in RU CENTER`) + ew.writeln(` - "NICRU_SECRET": Secret for application in DNS-hosting RU CENTER`) + ew.writeln(` - "NICRU_SERVICE_ID": Service ID for application in DNS-hosting RU CENTER`) + ew.writeln(` - "NICRU_SERVICE_NAME": Service Name for DNS-hosting RU CENTER`) + ew.writeln(` - "NICRU_USER": Agreement for account in RU CENTER`) ew.writeln() ew.writeln(`Additional Configuration:`) - ew.writeln(` - "NIC_RU_POLLING_INTERVAL": Time between DNS propagation check`) - ew.writeln(` - "NIC_RU_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`) - ew.writeln(` - "NIC_RU_TTL": The TTL of the TXT record used for the DNS challenge`) + ew.writeln(` - "NICRU_POLLING_INTERVAL": Time between DNS propagation check`) + ew.writeln(` - "NICRU_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`) + ew.writeln(` - "NICRU_TTL": The TTL of the TXT record used for the DNS challenge`) ew.writeln() ew.writeln(`More information: https://go-acme.github.io/lego/dns/nicru`) diff --git a/docs/content/dns/zz_gen_nicru.md b/docs/content/dns/zz_gen_nicru.md index 5538ee6403..b7fa21d741 100644 --- a/docs/content/dns/zz_gen_nicru.md +++ b/docs/content/dns/zz_gen_nicru.md @@ -26,11 +26,11 @@ Configuration for [RU CENTER](https://nic.ru/). Here is an example bash command using the RU CENTER provider: ```bash -NIC_RU_USER="" \ -NIC_RU_PASSWORD="" \ -NIC_RU_SERVICE_ID="" \ -NIC_RU_SECRET="" \ -NIC_RU_SERVICE_NAME="" \ +NICRU_USER="" \ +NICRU_PASSWORD="" \ +NICRU_SERVICE_ID="" \ +NICRU_SECRET="" \ +NICRU_SERVICE_NAME="" \ ./lego --dns nicru --domains "*.example.com" --email you@example.com run ``` @@ -41,11 +41,11 @@ NIC_RU_SERVICE_NAME="" \ | Environment Variable Name | Description | |-----------------------|-------------| -| `NIC_RU_PASSWORD` | Password for account in RU CENTER | -| `NIC_RU_SECRET` | Secret for application in DNS-hosting RU CENTER | -| `NIC_RU_SERVICE_ID` | Service ID for application in DNS-hosting RU CENTER | -| `NIC_RU_SERVICE_NAME` | Service Name for DNS-hosting RU CENTER | -| `NIC_RU_USER` | Agreement for account in RU CENTER | +| `NICRU_PASSWORD` | Password for account in RU CENTER | +| `NICRU_SECRET` | Secret for application in DNS-hosting RU CENTER | +| `NICRU_SERVICE_ID` | Service ID for application in DNS-hosting RU CENTER | +| `NICRU_SERVICE_NAME` | Service Name for DNS-hosting RU CENTER | +| `NICRU_USER` | Agreement for account in RU CENTER | 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" >}}). @@ -55,9 +55,9 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}). | Environment Variable Name | Description | |--------------------------------|-------------| -| `NIC_RU_POLLING_INTERVAL` | Time between DNS propagation check | -| `NIC_RU_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation | -| `NIC_RU_TTL` | The TTL of the TXT record used for the DNS challenge | +| `NICRU_POLLING_INTERVAL` | Time between DNS propagation check | +| `NICRU_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation | +| `NICRU_TTL` | The TTL of the TXT record used for the DNS challenge | 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" >}}). @@ -66,13 +66,13 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}). You can find information about service ID and secret https://www.nic.ru/manager/oauth.cgi?step=oauth.app_list -| ENV Variable | Parameter from page | Example | -|----------------------|--------------------------------|-------------------| -| NIC_RU_USER | Username (Number of agreement) | NNNNNNN/NIC-D | -| NIC_RU_PASSWORD | Password account | | -| NIC_RU_SERVICE_ID | Application ID | hex-based, len 32 | -| NIC_RU_SECRET | Identity endpoint | string len 91 | -| NIC_RU_SERVICE_NAME | Service name in DNS-hosting | DPNNNNNNNNNN | +| ENV Variable | Parameter from page | Example | +|---------------------|--------------------------------|-------------------| +| NICRU_USER | Username (Number of agreement) | NNNNNNN/NIC-D | +| NICRU_PASSWORD | Password account | | +| NICRU_SERVICE_ID | Application ID | hex-based, len 32 | +| NICRU_SECRET | Identity endpoint | string len 91 | +| NICRU_SERVICE_NAME | Service name in DNS-hosting | DPNNNNNNNNNN | diff --git a/providers/dns/nicru/internal/client.go b/providers/dns/nicru/internal/client.go index c495b8acc1..39a5115112 100644 --- a/providers/dns/nicru/internal/client.go +++ b/providers/dns/nicru/internal/client.go @@ -6,6 +6,7 @@ import ( "encoding/xml" "errors" "fmt" + "io" "net/http" "net/url" "strconv" @@ -20,6 +21,19 @@ const tokenURL = defaultBaseURL + "/oauth/token" const successStatus = "success" +// Trimmer trim all XML fields. +type Trimmer struct { + decoder *xml.Decoder +} + +func (tr Trimmer) Token() (xml.Token, error) { + t, err := tr.decoder.Token() + if cd, ok := t.(xml.CharData); ok { + t = xml.CharData(bytes.TrimSpace(cd)) + } + return t, err +} + // OauthConfiguration credentials. type OauthConfiguration struct { OAuth2ClientID string @@ -77,7 +91,7 @@ func NewClient(httpClient *http.Client, serviceName string) (*Client, error) { }, nil } -func (c *Client) GetZones() ([]*Zone, error) { +func (c *Client) GetZones() ([]Zone, error) { endpoint := c.baseURL.JoinPath("dns-master", "services", c.serviceName, "zones") req, err := http.NewRequest(http.MethodGet, endpoint.String(), nil) @@ -93,7 +107,7 @@ func (c *Client) GetZones() ([]*Zone, error) { return apiResponse.Data.Zone, nil } -func (c *Client) GetRecords(fqdn string) ([]*RR, error) { +func (c *Client) GetRecords(fqdn string) ([]RR, error) { endpoint := c.baseURL.JoinPath("dns-master", "services", c.serviceName, "zones", fqdn, "records") req, err := http.NewRequest(http.MethodGet, endpoint.String(), nil) @@ -106,7 +120,7 @@ func (c *Client) GetRecords(fqdn string) ([]*RR, error) { return nil, err } - var records []*RR + var records []RR for _, zone := range apiResponse.Data.Zone { records = append(records, zone.RR...) } @@ -115,7 +129,7 @@ func (c *Client) GetRecords(fqdn string) ([]*RR, error) { } func (c *Client) AddTxtRecord(zoneName string, name string, content string, ttl int) (*Response, error) { - request := &Request{RRList: &RrList{RR: []*RR{{ + request := &Request{RRList: &RrList{RR: []RR{{ Name: name, TTL: strconv.Itoa(ttl), Type: "TXT", @@ -155,6 +169,9 @@ func (c *Client) addRecords(zoneName string, request *Request) (*Response, error return nil, err } + // PUT https://api.nic.ru/dns-master/services//zones//records + // PUT https://api.nic.ru/dns-master/services/TESTSERVICE/zones/TEST.RU/records + req, err := http.NewRequest(http.MethodPut, endpoint.String(), body) if err != nil { return nil, err @@ -168,15 +185,23 @@ func (c *Client) do(req *http.Request) (*Response, error) { if err != nil { return nil, err } + defer func() { _ = resp.Body.Close() }() apiResponse := &Response{} - err = xml.NewDecoder(resp.Body).Decode(apiResponse) + raw, err := io.ReadAll(resp.Body) if err != nil { return nil, err } + decoder := xml.NewTokenDecoder(Trimmer{decoder: xml.NewDecoder(bytes.NewReader(raw))}) + + err = decoder.Decode(apiResponse) + if err != nil { + return nil, fmt.Errorf("[status code=%d] %s", resp.StatusCode, string(raw)) + } + if apiResponse.Status != successStatus { return nil, apiResponse.Errors.Error } diff --git a/providers/dns/nicru/internal/client_test.go b/providers/dns/nicru/internal/client_test.go new file mode 100644 index 0000000000..8db48e97e9 --- /dev/null +++ b/providers/dns/nicru/internal/client_test.go @@ -0,0 +1,286 @@ +package internal + +import ( + "encoding/xml" + "fmt" + "io" + "net/http" + "net/http/httptest" + "net/url" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func setupTest(t *testing.T, pattern string, handler http.HandlerFunc) *Client { + t.Helper() + + mux := http.NewServeMux() + server := httptest.NewServer(mux) + t.Cleanup(server.Close) + + mux.HandleFunc(pattern, handler) + + client, err := NewClient(server.Client(), "test") + require.NoError(t, err) + + client.baseURL, _ = url.Parse(server.URL) + + return client +} + +func writeFixtures(method string, filename string, status int) http.HandlerFunc { + return func(rw http.ResponseWriter, req *http.Request) { + if req.Method != method { + http.Error(rw, fmt.Sprintf("unsupported method: %s", req.Method), http.StatusMethodNotAllowed) + return + } + + file, err := os.Open(filepath.Join("fixtures", filename)) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + defer func() { _ = file.Close() }() + + rw.WriteHeader(status) + _, err = io.Copy(rw, file) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + } +} + +func TestClient_GetZones(t *testing.T) { + client := setupTest(t, "/dns-master/services/test/zones", + writeFixtures(http.MethodGet, "zones_GET.xml", http.StatusOK)) + + zones, err := client.GetZones() + require.NoError(t, err) + + expected := []Zone{ + { + Admin: "123/NIC-REG", + Enable: "true", + HasChanges: "false", + HasPrimary: "true", + ID: "227645", + IdnName: "тест.рф", + Name: "xn—e1aybc.xn--p1ai", + Payer: "123/NIC-REG", + Service: "myservice", + }, + { + Admin: "123/NIC-REG", + Enable: "true", + HasChanges: "false", + HasPrimary: "true", + ID: "227642", + IdnName: "example.ru", + Name: "example.ru", + Payer: "123/NIC-REG", + Service: "myservice", + }, + { + Admin: "123/NIC-REG", + Enable: "true", + HasChanges: "false", + HasPrimary: "true", + ID: "227643", + IdnName: "test.su", + Name: "test.su", + Payer: "123/NIC-REG", + Service: "myservice", + }, + } + + assert.Equal(t, expected, zones) +} + +func TestClient_GetZones_error(t *testing.T) { + client := setupTest(t, "/dns-master/services/test/zones", + writeFixtures(http.MethodGet, "errors.xml", http.StatusOK)) + + _, err := client.GetZones() + require.ErrorIs(t, err, Error{ + Text: "Access token expired or not found", + Code: "4097", + }) +} + +func TestClient_GetRecords(t *testing.T) { + client := setupTest(t, "/dns-master/services/test/zones/example.com./records", + writeFixtures(http.MethodGet, "records_GET.xml", http.StatusOK)) + + records, err := client.GetRecords("example.com.") + require.NoError(t, err) + + expected := []RR{ + { + ID: "210074", + Name: "@", + IdnName: "@", + TTL: "", + Type: "SOA", + Soa: &Soa{ + MName: &MName{ + Name: "ns3-l2.nic.ru.", + IdnName: "ns3-l2.nic.ru.", + }, + RName: &RName{ + Name: "dns.nic.ru.", + IdnName: "dns.nic.ru.", + }, + Serial: "2011112002", + Refresh: "1440", + Retry: "3600", + Expire: "2592000", + Minimum: "600", + }, + }, + { + ID: "210075", + Name: "@", + IdnName: "@", + Type: "NS", + Ns: &Ns{ + Name: "ns3-l2.nic.ru.", + IdnName: "ns3- l2.nic.ru.", + }, + }, + { + ID: "210076", + Name: "@", + IdnName: "@", + Type: "NS", + Ns: &Ns{ + Name: "ns4-l2.nic.ru.", + IdnName: "ns4-l2.nic.ru.", + }, + }, + { + ID: "210077", + Name: "@", + IdnName: "@", + Type: "NS", + Ns: &Ns{ + Name: "ns8-l2.nic.ru.", + IdnName: "ns8- l2.nic.ru.", + }, + }, + } + + assert.Equal(t, expected, records) +} + +func TestClient_GetRecords_error(t *testing.T) { + client := setupTest(t, "/dns-master/services/test/zones/example.com./records", + writeFixtures(http.MethodGet, "errors.xml", http.StatusOK)) + + _, err := client.GetRecords("example.com.") + require.ErrorIs(t, err, Error{ + Text: "Access token expired or not found", + Code: "4097", + }) +} + +func TestClient_AddTxtRecord(t *testing.T) { + client := setupTest(t, "/dns-master/services/test/zones/example.com./records", + writeFixtures(http.MethodPut, "records_PUT.xml", http.StatusOK)) + + response, err := client.AddTxtRecord("example.com.", "foo", "txtTXT", 30) + require.NoError(t, err) + + expected := &Response{ + XMLName: xml.Name{Local: "response"}, + Status: "success", + Data: &Data{ + Zone: []Zone{ + { + Admin: "123/NIC-REG", + HasChanges: "true", + ID: "228095", + IdnName: "test.ru", + Name: "test.ru", + Service: "testservice", + RR: []RR{ + { + ID: "210076", + Name: "@", + IdnName: "@", + Type: "NS", + Ns: &Ns{ + Name: "ns4-l2.nic.ru.", + IdnName: "ns4-l2.nic.ru.", + }, + }, + { + ID: "210077", + Name: "@", + IdnName: "@", + Type: "NS", + Ns: &Ns{ + Name: "ns8-l2.nic.ru.", + IdnName: "ns8-l2.nic.ru.", + }, + }, + }, + }, + }, + }, + } + + assert.Equal(t, expected, response) +} + +func TestClient_AddTxtRecord_error(t *testing.T) { + client := setupTest(t, "/dns-master/services/test/zones/example.com./records", + writeFixtures(http.MethodPut, "errors.xml", http.StatusOK)) + + _, err := client.AddTxtRecord("example.com.", "foo", "txtTXT", 30) + require.ErrorIs(t, err, Error{ + Text: "Access token expired or not found", + Code: "4097", + }) +} + +func TestClient_DeleteRecord_error(t *testing.T) { + + client := setupTest(t, "/dns-master/services/test/zones/example.com./records/123", + writeFixtures(http.MethodDelete, "errors.xml", http.StatusUnauthorized)) + + _, err := client.DeleteRecord("example.com.", "123") + require.ErrorIs(t, err, Error{ + Text: "Access token expired or not found", + Code: "4097", + }) +} + +func TestClient_CommitZone(t *testing.T) { + client := setupTest(t, "/dns-master/services/test/zones/example.com./commit", writeFixtures(http.MethodPost, "commit_POST.xml", http.StatusOK)) + + response, err := client.CommitZone("example.com.") + require.NoError(t, err) + + expected := &Response{ + XMLName: xml.Name{Local: "response"}, + Status: "success", + } + + assert.Equal(t, expected, response) +} + +func TestClient_CommitZone_error(t *testing.T) { + client := setupTest(t, "/dns-master/services/test/zones/example.com./commit", writeFixtures(http.MethodPost, "errors.xml", http.StatusOK)) + + _, err := client.CommitZone("example.com.") + require.ErrorIs(t, err, Error{ + Text: "Access token expired or not found", + Code: "4097", + }) +} diff --git a/providers/dns/nicru/internal/fixtures/commit_POST.xml b/providers/dns/nicru/internal/fixtures/commit_POST.xml new file mode 100644 index 0000000000..530a22d163 --- /dev/null +++ b/providers/dns/nicru/internal/fixtures/commit_POST.xml @@ -0,0 +1,4 @@ + + + success + diff --git a/providers/dns/nicru/internal/fixtures/errors.xml b/providers/dns/nicru/internal/fixtures/errors.xml new file mode 100644 index 0000000000..961b9a4958 --- /dev/null +++ b/providers/dns/nicru/internal/fixtures/errors.xml @@ -0,0 +1,7 @@ + + + fail + + Access token expired or not found + + diff --git a/providers/dns/nicru/internal/fixtures/records_GET.xml b/providers/dns/nicru/internal/fixtures/records_GET.xml new file mode 100644 index 0000000000..a9df348f9d --- /dev/null +++ b/providers/dns/nicru/internal/fixtures/records_GET.xml @@ -0,0 +1,55 @@ + + + success + + + + @ + @ + SOA + + + ns3-l2.nic.ru. + ns3-l2.nic.ru. + + + dns.nic.ru. + dns.nic.ru. + + 2011112002 + 1440 + 3600 + 2592000 + 600 + + + + @ + @ + NS + + ns3-l2.nic.ru. + ns3- l2.nic.ru. + + + + @ + @ + NS + + ns4-l2.nic.ru. + ns4-l2.nic.ru. + + + + @ + @ + NS + + ns8-l2.nic.ru. + ns8- l2.nic.ru. + + + + + diff --git a/providers/dns/nicru/internal/fixtures/records_PUT.xml b/providers/dns/nicru/internal/fixtures/records_PUT.xml new file mode 100644 index 0000000000..a3417a8f35 --- /dev/null +++ b/providers/dns/nicru/internal/fixtures/records_PUT.xml @@ -0,0 +1,10 @@ + + + success + + + @@NSns4-l2.nic.ru.ns4-l2.nic.ru. + @@NSns8-l2.nic.ru.ns8-l2.nic.ru. + + + diff --git a/providers/dns/nicru/internal/fixtures/zones_GET.xml b/providers/dns/nicru/internal/fixtures/zones_GET.xml new file mode 100644 index 0000000000..efa2da9a24 --- /dev/null +++ b/providers/dns/nicru/internal/fixtures/zones_GET.xml @@ -0,0 +1,12 @@ + + + success + + + + + + diff --git a/providers/dns/nicru/internal/types.go b/providers/dns/nicru/internal/types.go index 649737d927..34a4c6b793 100644 --- a/providers/dns/nicru/internal/types.go +++ b/providers/dns/nicru/internal/types.go @@ -6,208 +6,207 @@ import ( ) type Request struct { - XMLName xml.Name `xml:"request" json:"xml_name,omitempty"` - Text string `xml:",chardata" json:"text,omitempty"` - RRList *RrList `xml:"rr-list" json:"rr_list,omitempty"` + XMLName xml.Name `xml:"request"` + Text string `xml:",chardata"` + RRList *RrList `xml:"rr-list"` } type RrList struct { - Text string `xml:",chardata" json:"text,omitempty"` - RR []*RR `xml:"rr" json:"rr,omitempty"` + Text string `xml:",chardata"` + RR []RR `xml:"rr"` } type RR struct { - Text string `xml:",chardata" json:"text,omitempty"` - ID string `xml:"id,attr,omitempty" json:"id,omitempty"` - Name string `xml:"name" json:"name,omitempty"` - IdnName string `xml:"idn-name,omitempty" json:"idn_name,omitempty"` - TTL string `xml:"ttl" json:"ttl,omitempty"` - Type string `xml:"type" json:"type,omitempty"` - Soa *Soa `xml:"soa" json:"soa,omitempty"` - A *string `xml:"a" json:"a,omitempty"` - AAAA *string `xml:"aaaa" json:"aaaa,omitempty"` - CName *CName `xml:"cname" json:"cname,omitempty"` - Ns *Ns `xml:"ns" json:"ns,omitempty"` - Mx *Mx `xml:"mx" json:"mx,omitempty"` - Srv *Srv `xml:"srv" json:"srv,omitempty"` - Ptr *Ptr `xml:"ptr" json:"ptr,omitempty"` - Txt *Txt `xml:"txt" json:"txt,omitempty"` - DName *DName `xml:"dname" json:"dname,omitempty"` - HInfo *HInfo `xml:"hinfo" json:"hinfo,omitempty"` - Naptr *Naptr `xml:"naptr" json:"naptr,omitempty"` - RP *RP `xml:"rp" json:"rp,omitempty"` + Text string `xml:",chardata"` + ID string `xml:"id,attr,omitempty"` + Name string `xml:"name"` + IdnName string `xml:"idn-name,omitempty"` + TTL string `xml:"ttl"` + Type string `xml:"type"` + Soa *Soa `xml:"soa"` + A *string `xml:"a"` + AAAA *string `xml:"aaaa"` + CName *CName `xml:"cname"` + Ns *Ns `xml:"ns"` + Mx *Mx `xml:"mx"` + Srv *Srv `xml:"srv"` + Ptr *Ptr `xml:"ptr"` + Txt *Txt `xml:"txt"` + DName *DName `xml:"dname"` + HInfo *HInfo `xml:"hinfo"` + Naptr *Naptr `xml:"naptr"` + RP *RP `xml:"rp"` +} + +type Response struct { + XMLName xml.Name `xml:"response"` + Text string `xml:",chardata"` + Status string `xml:"status"` + Errors Errors `xml:"errors"` + Data *Data `xml:"data"` } type Service struct { - Text string `xml:",chardata" json:"text,omitempty"` - Admin string `xml:"admin,attr" json:"admin,omitempty"` - DomainsLimit string `xml:"domains-limit,attr" json:"domains_limit,omitempty"` - DomainsNum string `xml:"domains-num,attr" json:"domains_num,omitempty"` - Enable string `xml:"enable,attr" json:"enable,omitempty"` - HasPrimary string `xml:"has-primary,attr" json:"has_primary,omitempty"` - Name string `xml:"name,attr" json:"name,omitempty"` - Payer string `xml:"payer,attr" json:"payer,omitempty"` - Tariff string `xml:"tariff,attr" json:"tariff,omitempty"` - RRLimit string `xml:"rr-limit,attr" json:"rr_limit,omitempty"` - RRNum string `xml:"rr-num,attr" json:"rr_num,omitempty"` + Text string `xml:",chardata"` + Admin string `xml:"admin,attr"` + DomainsLimit string `xml:"domains-limit,attr"` + DomainsNum string `xml:"domains-num,attr"` + Enable string `xml:"enable,attr"` + HasPrimary string `xml:"has-primary,attr"` + Name string `xml:"name,attr"` + Payer string `xml:"payer,attr"` + Tariff string `xml:"tariff,attr"` + RRLimit string `xml:"rr-limit,attr"` + RRNum string `xml:"rr-num,attr"` } type Soa struct { - Text string `xml:",chardata" json:"text,omitempty"` - MName *MName `xml:"mname" json:"mname,omitempty"` - RName *RName `xml:"rname" json:"rname,omitempty"` - Serial string `xml:"serial" json:"serial,omitempty"` - Refresh string `xml:"refresh" json:"refresh,omitempty"` - Retry string `xml:"retry" json:"retry,omitempty"` - Expire string `xml:"expire" json:"expire,omitempty"` - Minimum string `xml:"minimum" json:"minimum,omitempty"` + Text string `xml:",chardata"` + MName *MName `xml:"mname"` + RName *RName `xml:"rname"` + Serial string `xml:"serial"` + Refresh string `xml:"refresh"` + Retry string `xml:"retry"` + Expire string `xml:"expire"` + Minimum string `xml:"minimum"` } type MName struct { - Text string `xml:",chardata" json:"text,omitempty"` - Name string `xml:"name" json:"name,omitempty"` - IdnName string `xml:"idn-name,omitempty" json:"idn_name,omitempty"` + Text string `xml:",chardata"` + Name string `xml:"name"` + IdnName string `xml:"idn-name,omitempty"` } type RName struct { - Text string `xml:",chardata" json:"text,omitempty"` - Name string `xml:"name" json:"name,omitempty"` - IdnName string `xml:"idn-name,omitempty" json:"idn_name,omitempty"` + Text string `xml:",chardata"` + Name string `xml:"name"` + IdnName string `xml:"idn-name,omitempty"` } type Ns struct { - Text string `xml:",chardata" json:"text,omitempty"` - Name string `xml:"name" json:"name,omitempty"` - IdnName string `xml:"idn-name,omitempty" json:"idn_name,omitempty"` + Text string `xml:",chardata"` + Name string `xml:"name"` + IdnName string `xml:"idn-name,omitempty"` } type Mx struct { - Text string `xml:",chardata" json:"text,omitempty"` - Preference string `xml:"preference" json:"preference,omitempty"` - Exchange *Exchange `xml:"exchange" json:"exchange,omitempty"` + Text string `xml:",chardata"` + Preference string `xml:"preference"` + Exchange *Exchange `xml:"exchange"` } type Exchange struct { - Text string `xml:",chardata" json:"text,omitempty"` - Name string `xml:"name" json:"name,omitempty"` + Name string `xml:"name"` } type Srv struct { - Text string `xml:",chardata" json:"text,omitempty"` - Priority string `xml:"priority" json:"priority,omitempty"` - Weight string `xml:"weight" json:"weight,omitempty"` - Port string `xml:"port" json:"port,omitempty"` - Target *Target `xml:"target" json:"target,omitempty"` + Priority string `xml:"priority"` + Weight string `xml:"weight"` + Port string `xml:"port"` + Target *Target `xml:"target"` } type Target struct { - Text string `xml:",chardata" json:"text,omitempty"` - Name string `xml:"name" json:"name,omitempty"` + Text string `xml:",chardata"` + Name string `xml:"name"` } type Ptr struct { - Text string `xml:",chardata" json:"text,omitempty"` - Name string `xml:"name" json:"name,omitempty"` + Text string `xml:",chardata"` + Name string `xml:"name"` } type HInfo struct { - Text string `xml:",chardata" json:"text,omitempty"` - Hardware string `xml:"hardware" json:"hardware,omitempty"` - OS string `xml:"os" json:"os,omitempty"` + Hardware string `xml:"hardware"` + OS string `xml:"os"` } type Naptr struct { - Text string `xml:",chardata" json:"text,omitempty"` - Order string `xml:"order" json:"order,omitempty"` - Preference string `xml:"preference" json:"preference,omitempty"` - Flags string `xml:"flags" json:"flags,omitempty"` - Service string `xml:"service" json:"service,omitempty"` - Regexp string `xml:"regexp" json:"regexp,omitempty"` - Replacement *Replacement `xml:"replacement" json:"replacement,omitempty"` + Text string `xml:",chardata"` + Order string `xml:"order"` + Preference string `xml:"preference"` + Flags string `xml:"flags"` + Service string `xml:"service"` + Regexp string `xml:"regexp"` + Replacement *Replacement `xml:"replacement"` } type Replacement struct { - Text string `xml:",chardata" json:"text,omitempty"` - Name string `xml:"name" json:"name,omitempty"` + Text string `xml:",chardata"` + Name string `xml:"name"` } type RP struct { - Text string `xml:",chardata" json:"text,omitempty"` - MboxDName *MboxDName `xml:"mbox-dname" json:"mbox_dname,omitempty"` - TxtDName *TxtDName `xml:"txt-dname" json:"txt_dname,omitempty"` + Text string `xml:",chardata"` + MboxDName *MboxDName `xml:"mbox-dname"` + TxtDName *TxtDName `xml:"txt-dname"` } type MboxDName struct { - Text string `xml:",chardata" json:"text,omitempty"` - Name string `xml:"name" json:"name,omitempty"` + Text string `xml:",chardata"` + Name string `xml:"name"` } type TxtDName struct { - Text string `xml:",chardata" json:"text,omitempty"` - Name string `xml:"name" json:"name,omitempty"` + Text string `xml:",chardata"` + Name string `xml:"name"` } type CName struct { - Text string `xml:",chardata" json:"text,omitempty"` - Name string `xml:"name" json:"name,omitempty"` - IdnName string `xml:"idn-name,omitempty" json:"idn_name,omitempty"` + Text string `xml:",chardata"` + Name string `xml:"name"` + IdnName string `xml:"idn-name,omitempty"` } type DName struct { - Text string `xml:",chardata" json:"text,omitempty"` - Name string `xml:"name" json:"name,omitempty"` + Text string `xml:",chardata"` + Name string `xml:"name"` } type Txt struct { - Text string `xml:",chardata" json:"text,omitempty"` - String string `xml:"string" json:"string,omitempty"` + Text string `xml:",chardata"` + String string `xml:"string"` } type Zone struct { - Text string `xml:",chardata" json:"text,omitempty"` - Admin string `xml:"admin,attr" json:"admin,omitempty"` - Enable string `xml:"enable,attr" json:"enable,omitempty"` - HasChanges string `xml:"has-changes,attr" json:"has_changes,omitempty"` - HasPrimary string `xml:"has-primary,attr" json:"has_primary,omitempty"` - ID string `xml:"id,attr" json:"id,omitempty"` - IdnName string `xml:"idn-name,attr" json:"idn_name,omitempty"` - Name string `xml:"name,attr" json:"name,omitempty"` - Payer string `xml:"payer,attr" json:"payer,omitempty"` - Service string `xml:"service,attr" json:"service,omitempty"` - RR []*RR `xml:"rr" json:"rr,omitempty"` + Text string `xml:",chardata"` + Admin string `xml:"admin,attr"` + Enable string `xml:"enable,attr"` + HasChanges string `xml:"has-changes,attr"` + HasPrimary string `xml:"has-primary,attr"` + ID string `xml:"id,attr"` + IdnName string `xml:"idn-name,attr"` + Name string `xml:"name,attr"` + Payer string `xml:"payer,attr"` + Service string `xml:"service,attr"` + RR []RR `xml:"rr"` } type Revision struct { - Text string `xml:",chardata" json:"text,omitempty"` - Date string `xml:"date,attr" json:"date,omitempty"` - IP string `xml:"ip,attr" json:"ip,omitempty"` - Number string `xml:"number,attr" json:"number,omitempty"` + Text string `xml:",chardata"` + Date string `xml:"date,attr"` + IP string `xml:"ip,attr"` + Number string `xml:"number,attr"` +} + +type Errors struct { + Text string `xml:",chardata"` + Error Error `xml:"error"` } type Error struct { - Text string `xml:",chardata" json:"text,omitempty"` - Code string `xml:"code,attr" json:"code,omitempty"` + Text string `xml:",chardata"` + Code string `xml:"code,attr"` } func (e Error) Error() string { return fmt.Sprintf("%s (code %s)", e.Text, e.Code) } -type Response struct { - XMLName xml.Name `xml:"response" json:"xml_name,omitempty"` - Text string `xml:",chardata" json:"text,omitempty"` - Status string `xml:"status" json:"status,omitempty"` - Errors struct { - Text string `xml:",chardata" json:"text,omitempty"` - Error Error `xml:"error" json:"error,omitempty"` - } `xml:"errors" json:"errors,omitempty"` - Data *Data `xml:"data" json:"data,omitempty"` -} - type Data struct { - Text string `xml:",chardata" json:"text,omitempty"` - Service []*Service `xml:"service" json:"service,omitempty"` - Zone []*Zone `xml:"zone" json:"zone,omitempty"` - Address []*string `xml:"address" json:"address,omitempty"` - Revision []*Revision `xml:"revision" json:"revision,omitempty"` + Text string `xml:",chardata"` + Service []Service `xml:"service"` + Zone []Zone `xml:"zone"` + Address []string `xml:"address"` + Revision []Revision `xml:"revision"` } diff --git a/providers/dns/nicru/nicru.go b/providers/dns/nicru/nicru.go index f69ac0b651..8d4f9dd3ee 100644 --- a/providers/dns/nicru/nicru.go +++ b/providers/dns/nicru/nicru.go @@ -14,7 +14,7 @@ import ( // Environment variables names. const ( - envNamespace = "NIC_RU_" + envNamespace = "NICRU_" EnvUsername = envNamespace + "USER" EnvPassword = envNamespace + "PASSWORD" diff --git a/providers/dns/nicru/nicru.toml b/providers/dns/nicru/nicru.toml index d695061700..bccd043c90 100644 --- a/providers/dns/nicru/nicru.toml +++ b/providers/dns/nicru/nicru.toml @@ -5,11 +5,11 @@ Code = "nicru" Since = "v4.11.0" Example = ''' -NIC_RU_USER="" \ -NIC_RU_PASSWORD="" \ -NIC_RU_SERVICE_ID="" \ -NIC_RU_SECRET="" \ -NIC_RU_SERVICE_NAME="" \ +NICRU_USER="" \ +NICRU_PASSWORD="" \ +NICRU_SERVICE_ID="" \ +NICRU_SECRET="" \ +NICRU_SERVICE_NAME="" \ ./lego --dns nicru --domains "*.example.com" --email you@example.com run ''' @@ -18,26 +18,26 @@ Additional = ''' You can find information about service ID and secret https://www.nic.ru/manager/oauth.cgi?step=oauth.app_list -| ENV Variable | Parameter from page | Example | -|----------------------|--------------------------------|-------------------| -| NIC_RU_USER | Username (Number of agreement) | NNNNNNN/NIC-D | -| NIC_RU_PASSWORD | Password account | | -| NIC_RU_SERVICE_ID | Application ID | hex-based, len 32 | -| NIC_RU_SECRET | Identity endpoint | string len 91 | -| NIC_RU_SERVICE_NAME | Service name in DNS-hosting | DPNNNNNNNNNN | +| ENV Variable | Parameter from page | Example | +|---------------------|--------------------------------|-------------------| +| NICRU_USER | Username (Number of agreement) | NNNNNNN/NIC-D | +| NICRU_PASSWORD | Password account | | +| NICRU_SERVICE_ID | Application ID | hex-based, len 32 | +| NICRU_SECRET | Identity endpoint | string len 91 | +| NICRU_SERVICE_NAME | Service name in DNS-hosting | DPNNNNNNNNNN | ''' [Configuration] [Configuration.Credentials] - NIC_RU_USER = "Agreement for account in RU CENTER" - NIC_RU_PASSWORD = "Password for account in RU CENTER" - NIC_RU_SERVICE_ID = "Service ID for application in DNS-hosting RU CENTER" - NIC_RU_SECRET = "Secret for application in DNS-hosting RU CENTER" - NIC_RU_SERVICE_NAME = "Service Name for DNS-hosting RU CENTER" + NICRU_USER = "Agreement for account in RU CENTER" + NICRU_PASSWORD = "Password for account in RU CENTER" + NICRU_SERVICE_ID = "Service ID for application in DNS-hosting RU CENTER" + NICRU_SECRET = "Secret for application in DNS-hosting RU CENTER" + NICRU_SERVICE_NAME = "Service Name for DNS-hosting RU CENTER" [Configuration.Additional] - NIC_RU_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation" - NIC_RU_POLLING_INTERVAL = "Time between DNS propagation check" - NIC_RU_TTL = "The TTL of the TXT record used for the DNS challenge" + NICRU_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation" + NICRU_POLLING_INTERVAL = "Time between DNS propagation check" + NICRU_TTL = "The TTL of the TXT record used for the DNS challenge" [Links] API = "https://www.nic.ru/help/api-dns-hostinga_3643.html" diff --git a/providers/dns/nicru/nicru_test.go b/providers/dns/nicru/nicru_test.go index 289797f7a6..a80fedd17a 100644 --- a/providers/dns/nicru/nicru_test.go +++ b/providers/dns/nicru/nicru_test.go @@ -44,7 +44,7 @@ func TestNewDNSProvider(t *testing.T) { EnvUsername: fakeUsername, EnvPassword: fakePassword, }, - expected: "nicru: some credentials information are missing: NIC_RU_SERVICE_ID", + expected: "nicru: some credentials information are missing: NICRU_SERVICE_ID", }, { desc: "missing secret", @@ -54,7 +54,7 @@ func TestNewDNSProvider(t *testing.T) { EnvUsername: fakeUsername, EnvPassword: fakePassword, }, - expected: "nicru: some credentials information are missing: NIC_RU_SECRET", + expected: "nicru: some credentials information are missing: NICRU_SECRET", }, { desc: "missing service name", @@ -64,7 +64,7 @@ func TestNewDNSProvider(t *testing.T) { EnvUsername: fakeUsername, EnvPassword: fakePassword, }, - expected: "nicru: some credentials information are missing: NIC_RU_SERVICE_NAME", + expected: "nicru: some credentials information are missing: NICRU_SERVICE_NAME", }, { desc: "missing username", @@ -74,7 +74,7 @@ func TestNewDNSProvider(t *testing.T) { EnvServiceName: fakeServiceName, EnvPassword: fakePassword, }, - expected: "nicru: some credentials information are missing: NIC_RU_USER", + expected: "nicru: some credentials information are missing: NICRU_USER", }, { desc: "missing password", @@ -84,7 +84,7 @@ func TestNewDNSProvider(t *testing.T) { EnvServiceName: fakeServiceName, EnvUsername: fakeUsername, }, - expected: "nicru: some credentials information are missing: NIC_RU_PASSWORD", + expected: "nicru: some credentials information are missing: NICRU_PASSWORD", }, }