Skip to content

Commit 2431f83

Browse files
authored
Add DNS provider for Liara (#1741)
1 parent 90e478e commit 2431f83

File tree

14 files changed

+859
-14
lines changed

14 files changed

+859
-14
lines changed

README.md

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,20 @@ Detailed documentation is available [here](https://go-acme.github.io/lego/dns).
6363
| [Hosttech](https://go-acme.github.io/lego/dns/hosttech/) | [HTTP request](https://go-acme.github.io/lego/dns/httpreq/) | [Hurricane Electric DNS](https://go-acme.github.io/lego/dns/hurricane/) | [HyperOne](https://go-acme.github.io/lego/dns/hyperone/) |
6464
| [IBM Cloud (SoftLayer)](https://go-acme.github.io/lego/dns/ibmcloud/) | [IIJ DNS Platform Service](https://go-acme.github.io/lego/dns/iijdpf/) | [Infoblox](https://go-acme.github.io/lego/dns/infoblox/) | [Infomaniak](https://go-acme.github.io/lego/dns/infomaniak/) |
6565
| [Internet Initiative Japan](https://go-acme.github.io/lego/dns/iij/) | [Internet.bs](https://go-acme.github.io/lego/dns/internetbs/) | [INWX](https://go-acme.github.io/lego/dns/inwx/) | [Ionos](https://go-acme.github.io/lego/dns/ionos/) |
66-
| [iwantmyname](https://go-acme.github.io/lego/dns/iwantmyname/) | [Joker](https://go-acme.github.io/lego/dns/joker/) | [Joohoi's ACME-DNS](https://go-acme.github.io/lego/dns/acme-dns/) | [Linode (v4)](https://go-acme.github.io/lego/dns/linode/) |
67-
| [Liquid Web](https://go-acme.github.io/lego/dns/liquidweb/) | [Loopia](https://go-acme.github.io/lego/dns/loopia/) | [LuaDNS](https://go-acme.github.io/lego/dns/luadns/) | [Manual](https://go-acme.github.io/lego/dns/manual/) |
68-
| [MyDNS.jp](https://go-acme.github.io/lego/dns/mydnsjp/) | [MythicBeasts](https://go-acme.github.io/lego/dns/mythicbeasts/) | [Name.com](https://go-acme.github.io/lego/dns/namedotcom/) | [Namecheap](https://go-acme.github.io/lego/dns/namecheap/) |
69-
| [Namesilo](https://go-acme.github.io/lego/dns/namesilo/) | [NearlyFreeSpeech.NET](https://go-acme.github.io/lego/dns/nearlyfreespeech/) | [Netcup](https://go-acme.github.io/lego/dns/netcup/) | [Netlify](https://go-acme.github.io/lego/dns/netlify/) |
70-
| [Nicmanager](https://go-acme.github.io/lego/dns/nicmanager/) | [NIFCloud](https://go-acme.github.io/lego/dns/nifcloud/) | [Njalla](https://go-acme.github.io/lego/dns/njalla/) | [NS1](https://go-acme.github.io/lego/dns/ns1/) |
71-
| [Open Telekom Cloud](https://go-acme.github.io/lego/dns/otc/) | [Oracle Cloud](https://go-acme.github.io/lego/dns/oraclecloud/) | [OVH](https://go-acme.github.io/lego/dns/ovh/) | [Porkbun](https://go-acme.github.io/lego/dns/porkbun/) |
72-
| [PowerDNS](https://go-acme.github.io/lego/dns/pdns/) | [Rackspace](https://go-acme.github.io/lego/dns/rackspace/) | [reg.ru](https://go-acme.github.io/lego/dns/regru/) | [RFC2136](https://go-acme.github.io/lego/dns/rfc2136/) |
73-
| [RimuHosting](https://go-acme.github.io/lego/dns/rimuhosting/) | [Sakura Cloud](https://go-acme.github.io/lego/dns/sakuracloud/) | [Scaleway](https://go-acme.github.io/lego/dns/scaleway/) | [Selectel](https://go-acme.github.io/lego/dns/selectel/) |
74-
| [Servercow](https://go-acme.github.io/lego/dns/servercow/) | [Simply.com](https://go-acme.github.io/lego/dns/simply/) | [Sonic](https://go-acme.github.io/lego/dns/sonic/) | [Stackpath](https://go-acme.github.io/lego/dns/stackpath/) |
75-
| [Tencent Cloud DNS](https://go-acme.github.io/lego/dns/tencentcloud/) | [TransIP](https://go-acme.github.io/lego/dns/transip/) | [UKFast SafeDNS](https://go-acme.github.io/lego/dns/safedns/) | [Variomedia](https://go-acme.github.io/lego/dns/variomedia/) |
76-
| [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) | [Vercel](https://go-acme.github.io/lego/dns/vercel/) | [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) | [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/) |
77-
| [VK Cloud](https://go-acme.github.io/lego/dns/vkcloud/) | [Vscale](https://go-acme.github.io/lego/dns/vscale/) | [Vultr](https://go-acme.github.io/lego/dns/vultr/) | [WEDOS](https://go-acme.github.io/lego/dns/wedos/) |
78-
| [Yandex Cloud](https://go-acme.github.io/lego/dns/yandexcloud/) | [Yandex PDD](https://go-acme.github.io/lego/dns/yandex/) | [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/) | [Zonomi](https://go-acme.github.io/lego/dns/zonomi/) |
66+
| [iwantmyname](https://go-acme.github.io/lego/dns/iwantmyname/) | [Joker](https://go-acme.github.io/lego/dns/joker/) | [Joohoi's ACME-DNS](https://go-acme.github.io/lego/dns/acme-dns/) | [Liara](https://go-acme.github.io/lego/dns/liara/) |
67+
| [Linode (v4)](https://go-acme.github.io/lego/dns/linode/) | [Liquid Web](https://go-acme.github.io/lego/dns/liquidweb/) | [Loopia](https://go-acme.github.io/lego/dns/loopia/) | [LuaDNS](https://go-acme.github.io/lego/dns/luadns/) |
68+
| [Manual](https://go-acme.github.io/lego/dns/manual/) | [MyDNS.jp](https://go-acme.github.io/lego/dns/mydnsjp/) | [MythicBeasts](https://go-acme.github.io/lego/dns/mythicbeasts/) | [Name.com](https://go-acme.github.io/lego/dns/namedotcom/) |
69+
| [Namecheap](https://go-acme.github.io/lego/dns/namecheap/) | [Namesilo](https://go-acme.github.io/lego/dns/namesilo/) | [NearlyFreeSpeech.NET](https://go-acme.github.io/lego/dns/nearlyfreespeech/) | [Netcup](https://go-acme.github.io/lego/dns/netcup/) |
70+
| [Netlify](https://go-acme.github.io/lego/dns/netlify/) | [Nicmanager](https://go-acme.github.io/lego/dns/nicmanager/) | [NIFCloud](https://go-acme.github.io/lego/dns/nifcloud/) | [Njalla](https://go-acme.github.io/lego/dns/njalla/) |
71+
| [NS1](https://go-acme.github.io/lego/dns/ns1/) | [Open Telekom Cloud](https://go-acme.github.io/lego/dns/otc/) | [Oracle Cloud](https://go-acme.github.io/lego/dns/oraclecloud/) | [OVH](https://go-acme.github.io/lego/dns/ovh/) |
72+
| [Porkbun](https://go-acme.github.io/lego/dns/porkbun/) | [PowerDNS](https://go-acme.github.io/lego/dns/pdns/) | [Rackspace](https://go-acme.github.io/lego/dns/rackspace/) | [reg.ru](https://go-acme.github.io/lego/dns/regru/) |
73+
| [RFC2136](https://go-acme.github.io/lego/dns/rfc2136/) | [RimuHosting](https://go-acme.github.io/lego/dns/rimuhosting/) | [Sakura Cloud](https://go-acme.github.io/lego/dns/sakuracloud/) | [Scaleway](https://go-acme.github.io/lego/dns/scaleway/) |
74+
| [Selectel](https://go-acme.github.io/lego/dns/selectel/) | [Servercow](https://go-acme.github.io/lego/dns/servercow/) | [Simply.com](https://go-acme.github.io/lego/dns/simply/) | [Sonic](https://go-acme.github.io/lego/dns/sonic/) |
75+
| [Stackpath](https://go-acme.github.io/lego/dns/stackpath/) | [Tencent Cloud DNS](https://go-acme.github.io/lego/dns/tencentcloud/) | [TransIP](https://go-acme.github.io/lego/dns/transip/) | [UKFast SafeDNS](https://go-acme.github.io/lego/dns/safedns/) |
76+
| [Variomedia](https://go-acme.github.io/lego/dns/variomedia/) | [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) | [Vercel](https://go-acme.github.io/lego/dns/vercel/) | [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) |
77+
| [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/) | [VK Cloud](https://go-acme.github.io/lego/dns/vkcloud/) | [Vscale](https://go-acme.github.io/lego/dns/vscale/) | [Vultr](https://go-acme.github.io/lego/dns/vultr/) |
78+
| [WEDOS](https://go-acme.github.io/lego/dns/wedos/) | [Yandex Cloud](https://go-acme.github.io/lego/dns/yandexcloud/) | [Yandex PDD](https://go-acme.github.io/lego/dns/yandex/) | [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/) |
79+
| [Zonomi](https://go-acme.github.io/lego/dns/zonomi/) | | | |
7980

8081
<!-- END DNS PROVIDERS LIST -->
8182

cmd/zz_gen_cmd_dnshelp.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ func allDNSCodes() string {
7171
"ionos",
7272
"iwantmyname",
7373
"joker",
74+
"liara",
7475
"lightsail",
7576
"linode",
7677
"liquidweb",
@@ -1336,6 +1337,26 @@ func displayDNSHelp(name string) error {
13361337
ew.writeln()
13371338
ew.writeln(`More information: https://go-acme.github.io/lego/dns/joker`)
13381339

1340+
case "liara":
1341+
// generated from: providers/dns/liara/liara.toml
1342+
ew.writeln(`Configuration for Liara.`)
1343+
ew.writeln(`Code: 'liara'`)
1344+
ew.writeln(`Since: 'v4.10.0'`)
1345+
ew.writeln()
1346+
1347+
ew.writeln(`Credentials:`)
1348+
ew.writeln(` - "LIARA_API_KEY": The API key`)
1349+
ew.writeln()
1350+
1351+
ew.writeln(`Additional Configuration:`)
1352+
ew.writeln(` - "LIARA_HTTP_TIMEOUT": API request timeout`)
1353+
ew.writeln(` - "LIARA_POLLING_INTERVAL": Time between DNS propagation check`)
1354+
ew.writeln(` - "LIARA_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
1355+
ew.writeln(` - "LIARA_TTL": The TTL of the TXT record used for the DNS challenge`)
1356+
1357+
ew.writeln()
1358+
ew.writeln(`More information: https://go-acme.github.io/lego/dns/liara`)
1359+
13391360
case "lightsail":
13401361
// generated from: providers/dns/lightsail/lightsail.toml
13411362
ew.writeln(`Configuration for Amazon Lightsail.`)

docs/content/dns/zz_gen_liara.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
title: "Liara"
3+
date: 2019-03-03T16:39:46+01:00
4+
draft: false
5+
slug: liara
6+
dnsprovider:
7+
since: "v4.10.0"
8+
code: "liara"
9+
url: "https://liara.ir"
10+
---
11+
12+
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
13+
<!-- providers/dns/liara/liara.toml -->
14+
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
15+
16+
17+
Configuration for [Liara](https://liara.ir).
18+
19+
20+
<!--more-->
21+
22+
- Code: `liara`
23+
- Since: v4.10.0
24+
25+
26+
Here is an example bash command using the Liara provider:
27+
28+
```bash
29+
LIARA_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
30+
lego --email [email protected] --dns liara --domains my.example.org run
31+
```
32+
33+
34+
35+
36+
## Credentials
37+
38+
| Environment Variable Name | Description |
39+
|-----------------------|-------------|
40+
| `LIARA_API_KEY` | The API key |
41+
42+
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
43+
More information [here]({{< ref "dns#configuration-and-credentials" >}}).
44+
45+
46+
## Additional Configuration
47+
48+
| Environment Variable Name | Description |
49+
|--------------------------------|-------------|
50+
| `LIARA_HTTP_TIMEOUT` | API request timeout |
51+
| `LIARA_POLLING_INTERVAL` | Time between DNS propagation check |
52+
| `LIARA_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
53+
| `LIARA_TTL` | The TTL of the TXT record used for the DNS challenge |
54+
55+
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
56+
More information [here]({{< ref "dns#configuration-and-credentials" >}}).
57+
58+
59+
60+
61+
## More information
62+
63+
- [API documentation](https://dns-service.iran.liara.ir/swagger)
64+
65+
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
66+
<!-- providers/dns/liara/liara.toml -->
67+
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ require (
2424
github.com/google/go-querystring v1.1.0
2525
github.com/gophercloud/gophercloud v1.0.0
2626
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae
27+
github.com/hashicorp/go-retryablehttp v0.7.1
2728
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df
2829
github.com/infobloxopen/infoblox-go-client v1.1.1
2930
github.com/labbsr0x/bindman-dns-webhook v1.0.2
@@ -95,7 +96,6 @@ require (
9596
github.com/hashicorp/errwrap v1.0.0 // indirect
9697
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
9798
github.com/hashicorp/go-multierror v1.1.1 // indirect
98-
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
9999
github.com/jmespath/go-jmespath v0.4.0 // indirect
100100
github.com/json-iterator/go v1.1.12 // indirect
101101
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect

providers/dns/dns_providers.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import (
6262
"github.com/go-acme/lego/v4/providers/dns/ionos"
6363
"github.com/go-acme/lego/v4/providers/dns/iwantmyname"
6464
"github.com/go-acme/lego/v4/providers/dns/joker"
65+
"github.com/go-acme/lego/v4/providers/dns/liara"
6566
"github.com/go-acme/lego/v4/providers/dns/lightsail"
6667
"github.com/go-acme/lego/v4/providers/dns/linode"
6768
"github.com/go-acme/lego/v4/providers/dns/liquidweb"
@@ -231,6 +232,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
231232
return iwantmyname.NewDNSProvider()
232233
case "joker":
233234
return joker.NewDNSProvider()
235+
case "liara":
236+
return liara.NewDNSProvider()
234237
case "lightsail":
235238
return lightsail.NewDNSProvider()
236239
case "linode", "linodev4": // "linodev4" is for compatibility with v3, must be dropped in v5
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package internal
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
"net/http"
9+
"net/url"
10+
"path"
11+
"time"
12+
)
13+
14+
const defaultBaseURL = "https://dns-service.iran.liara.ir"
15+
16+
// Client a Liara DNS API client.
17+
type Client struct {
18+
apiKey string
19+
baseURL *url.URL
20+
HTTPClient *http.Client
21+
}
22+
23+
// NewClient creates a new Client.
24+
func NewClient(apiKey string) *Client {
25+
baseURL, _ := url.Parse(defaultBaseURL)
26+
27+
return &Client{
28+
apiKey: apiKey,
29+
HTTPClient: &http.Client{Timeout: 10 * time.Second},
30+
baseURL: baseURL,
31+
}
32+
}
33+
34+
// GetRecords gets the records of a domain.
35+
// https://dns-service.iran.liara.ir/swagger
36+
func (c Client) GetRecords(domainName string) ([]Record, error) {
37+
endpoint, err := c.baseURL.Parse(path.Join(c.baseURL.Path, "api", "v1", "zones", domainName, "dns-records"))
38+
if err != nil {
39+
return nil, fmt.Errorf("parse URL: %w", err)
40+
}
41+
42+
req, err := http.NewRequest(http.MethodGet, endpoint.String(), nil)
43+
if err != nil {
44+
return nil, fmt.Errorf("create request: %w", err)
45+
}
46+
47+
req.Header.Set("Authorization", "Bearer "+c.apiKey)
48+
49+
resp, err := c.HTTPClient.Do(req)
50+
if err != nil {
51+
return nil, err
52+
}
53+
54+
defer func() { _ = resp.Body.Close() }()
55+
56+
if resp.StatusCode != http.StatusOK {
57+
return nil, readError(resp)
58+
}
59+
60+
var response RecordsResponse
61+
err = json.NewDecoder(resp.Body).Decode(&response)
62+
if err != nil {
63+
return nil, err
64+
}
65+
66+
return response.Data, nil
67+
}
68+
69+
// CreateRecord creates a record.
70+
func (c Client) CreateRecord(domainName string, record Record) (*Record, error) {
71+
endpoint, err := c.baseURL.Parse(path.Join(c.baseURL.Path, "api", "v1", "zones", domainName, "dns-records"))
72+
if err != nil {
73+
return nil, fmt.Errorf("parse URL: %w", err)
74+
}
75+
76+
body, err := json.Marshal(record)
77+
if err != nil {
78+
return nil, fmt.Errorf("marshal request data: %w", err)
79+
}
80+
81+
req, err := http.NewRequest(http.MethodPost, endpoint.String(), bytes.NewReader(body))
82+
if err != nil {
83+
return nil, fmt.Errorf("create request: %w", err)
84+
}
85+
86+
req.Header.Set("Authorization", "Bearer "+c.apiKey)
87+
req.Header.Set("Content-Type", "application/json")
88+
89+
resp, err := c.HTTPClient.Do(req)
90+
if err != nil {
91+
return nil, err
92+
}
93+
94+
defer func() { _ = resp.Body.Close() }()
95+
96+
if resp.StatusCode != http.StatusCreated {
97+
return nil, readError(resp)
98+
}
99+
100+
var response RecordResponse
101+
err = json.NewDecoder(resp.Body).Decode(&response)
102+
if err != nil {
103+
return nil, err
104+
}
105+
106+
return &response.Data, nil
107+
}
108+
109+
// GetRecord gets a specific record.
110+
func (c Client) GetRecord(domainName, recordID string) (*Record, error) {
111+
endpoint, err := c.baseURL.Parse(path.Join(c.baseURL.Path, "api", "v1", "zones", domainName, "dns-records", recordID))
112+
if err != nil {
113+
return nil, fmt.Errorf("parse URL: %w", err)
114+
}
115+
116+
req, err := http.NewRequest(http.MethodGet, endpoint.String(), nil)
117+
if err != nil {
118+
return nil, fmt.Errorf("create request: %w", err)
119+
}
120+
121+
req.Header.Set("Authorization", "Bearer "+c.apiKey)
122+
123+
resp, err := c.HTTPClient.Do(req)
124+
if err != nil {
125+
return nil, err
126+
}
127+
128+
defer func() { _ = resp.Body.Close() }()
129+
130+
if resp.StatusCode != http.StatusOK {
131+
return nil, readError(resp)
132+
}
133+
134+
var response RecordResponse
135+
err = json.NewDecoder(resp.Body).Decode(&response)
136+
if err != nil {
137+
return nil, err
138+
}
139+
140+
return &response.Data, nil
141+
}
142+
143+
// DeleteRecord deletes a record.
144+
func (c Client) DeleteRecord(domainName, recordID string) error {
145+
endpoint, err := c.baseURL.Parse(path.Join(c.baseURL.Path, "api", "v1", "zones", domainName, "dns-records", recordID))
146+
if err != nil {
147+
return fmt.Errorf("parse URL: %w", err)
148+
}
149+
150+
req, err := http.NewRequest(http.MethodDelete, endpoint.String(), nil)
151+
if err != nil {
152+
return fmt.Errorf("create request: %w", err)
153+
}
154+
155+
req.Header.Set("Authorization", "Bearer "+c.apiKey)
156+
157+
resp, err := c.HTTPClient.Do(req)
158+
if err != nil {
159+
return err
160+
}
161+
162+
defer func() { _ = resp.Body.Close() }()
163+
164+
if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusNotFound {
165+
return readError(resp)
166+
}
167+
168+
return nil
169+
}
170+
171+
func readError(resp *http.Response) error {
172+
all, err := io.ReadAll(resp.Body)
173+
if err != nil {
174+
return fmt.Errorf("API error (status code: %d)", resp.StatusCode)
175+
}
176+
177+
var apiError APIError
178+
err = json.Unmarshal(all, &apiError)
179+
if err != nil {
180+
return fmt.Errorf("API error (status code: %d): %s", resp.StatusCode, string(all))
181+
}
182+
183+
return fmt.Errorf("API error (status code: %d): %w", resp.StatusCode, &apiError)
184+
}

0 commit comments

Comments
 (0)