Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DNS provider for nicmanager #1473

Merged
merged 2 commits into from
Aug 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ Detailed documentation is available [here](https://go-acme.github.io/lego/dns).
| [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/) | [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/) | [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/) | [Namesilo](https://go-acme.github.io/lego/dns/namesilo/) |
| [Netcup](https://go-acme.github.io/lego/dns/netcup/) | [Netlify](https://go-acme.github.io/lego/dns/netlify/) | [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/) | [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/) | [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/) | [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/) | [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/) | [TransIP](https://go-acme.github.io/lego/dns/transip/) | [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) | [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) |
| [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/) | [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/) |
| [Yandex](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/) | |
| [Netcup](https://go-acme.github.io/lego/dns/netcup/) | [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/) | [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/) | [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/) | [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/) | [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/) | [Stackpath](https://go-acme.github.io/lego/dns/stackpath/) | [TransIP](https://go-acme.github.io/lego/dns/transip/) | [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) |
| [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) | [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/) | [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/) | [Yandex](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/) |

<!-- END DNS PROVIDERS LIST -->

Expand Down
26 changes: 26 additions & 0 deletions cmd/zz_gen_cmd_dnshelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func allDNSCodes() string {
"namesilo",
"netcup",
"netlify",
"nicmanager",
"nifcloud",
"njalla",
"ns1",
Expand Down Expand Up @@ -1472,6 +1473,31 @@ func displayDNSHelp(name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/netlify`)

case "nicmanager":
// generated from: providers/dns/nicmanager/nicmanager.toml
ew.writeln(`Configuration for Nicmanager.`)
ew.writeln(`Code: 'nicmanager'`)
ew.writeln(`Since: 'v4.5.0'`)
ew.writeln()

ew.writeln(`Credentials:`)
ew.writeln(` - "NICMANAGER_API_EMAIL": Email-based login`)
ew.writeln(` - "NICMANAGER_API_LOGIN": Login, used for Username-based login`)
ew.writeln(` - "NICMANAGER_API_PASSWORD": Password, always required`)
ew.writeln(` - "NICMANAGER_API_USERNAME": Username, used for Username-based login`)
ew.writeln()

ew.writeln(`Additional Configuration:`)
ew.writeln(` - "NICMANAGER_API_MODE": mode: 'anycast' or 'zone' (default: 'anycast')`)
ew.writeln(` - "NICMANAGER_API_OTP": TOTP Secret (optional)`)
ew.writeln(` - "NICMANAGER_HTTP_TIMEOUT": API request timeout`)
ew.writeln(` - "NICMANAGER_POLLING_INTERVAL": Time between DNS propagation check`)
ew.writeln(` - "NICMANAGER_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
ew.writeln(` - "NICMANAGER_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/nicmanager`)

case "nifcloud":
// generated from: providers/dns/nifcloud/nifcloud.toml
ew.writeln(`Configuration for NIFCloud.`)
Expand Down
89 changes: 89 additions & 0 deletions docs/content/dns/zz_gen_nicmanager.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
title: "Nicmanager"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: nicmanager
---

<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/nicmanager/nicmanager.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

Since: v4.5.0

Configuration for [Nicmanager](https://www.nicmanager.com/).


<!--more-->

- Code: `nicmanager`

Here is an example bash command using the Nicmanager provider:

```bash
## Login using email

NICMANAGER_API_EMAIL = "foo@bar.baz" \
NICMANAGER_API_PASSWORD = "password" \

# Optionally, if your account has TOTP enabled, set the secret here
NICMANAGER_API_OTP = "long-secret" \

lego --email myemail@example.com --dns nicmanager --domains my.example.org run

## Login using account name + username

NICMANAGER_API_LOGIN = "myaccount" \
NICMANAGER_API_USERNAME = "myuser" \
NICMANAGER_API_PASSWORD = "password" \

# Optionally, if your account has TOTP enabled, set the secret here
NICMANAGER_API_OTP = "long-secret" \

lego --email myemail@example.com --dns nicmanager --domains my.example.org run
```




## Credentials

| Environment Variable Name | Description |
|-----------------------|-------------|
| `NICMANAGER_API_EMAIL` | Email-based login |
| `NICMANAGER_API_LOGIN` | Login, used for Username-based login |
| `NICMANAGER_API_PASSWORD` | Password, always required |
| `NICMANAGER_API_USERNAME` | Username, used for Username-based login |

The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here](/lego/dns/#configuration-and-credentials).


## Additional Configuration

| Environment Variable Name | Description |
|--------------------------------|-------------|
| `NICMANAGER_API_MODE` | mode: 'anycast' or 'zone' (default: 'anycast') |
| `NICMANAGER_API_OTP` | TOTP Secret (optional) |
| `NICMANAGER_HTTP_TIMEOUT` | API request timeout |
| `NICMANAGER_POLLING_INTERVAL` | Time between DNS propagation check |
| `NICMANAGER_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
| `NICMANAGER_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](/lego/dns/#configuration-and-credentials).

## Description

You can login using your account name + username or using your email address.
Optionally if TOTP is configured for your account, set `NICMANAGER_API_OTP`.



## More information

- [API documentation](https://api.nicmanager.com/docs/v1/)

<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/nicmanager/nicmanager.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
3 changes: 3 additions & 0 deletions providers/dns/dns_providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import (
"github.com/go-acme/lego/v4/providers/dns/namesilo"
"github.com/go-acme/lego/v4/providers/dns/netcup"
"github.com/go-acme/lego/v4/providers/dns/netlify"
"github.com/go-acme/lego/v4/providers/dns/nicmanager"
"github.com/go-acme/lego/v4/providers/dns/nifcloud"
"github.com/go-acme/lego/v4/providers/dns/njalla"
"github.com/go-acme/lego/v4/providers/dns/ns1"
Expand Down Expand Up @@ -234,6 +235,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return netcup.NewDNSProvider()
case "netlify":
return netlify.NewDNSProvider()
case "nicmanager":
return nicmanager.NewDNSProvider()
case "nifcloud":
return nifcloud.NewDNSProvider()
case "njalla":
Expand Down
185 changes: 185 additions & 0 deletions providers/dns/nicmanager/internal/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package internal

import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"path"
"strconv"
"time"

"github.com/pquerna/otp/totp"
)

const (
defaultBaseURL = "https://api.nicmanager.com/v1"
headerTOTPToken = "X-Auth-Token"
)

// Modes.
const (
ModeAnycast = "anycast"
ModeZone = "zone"
)

// Options the Client options.
type Options struct {
Login string
Username string

Email string

Password string
OTP string

Mode string
}

// Client a nicmanager DNS client.
type Client struct {
HTTPClient *http.Client
baseURL *url.URL

username string
password string
otp string

mode string
}

// NewClient create a new Client.
func NewClient(opts Options) *Client {
c := &Client{
mode: ModeAnycast,
username: opts.Email,
password: opts.Password,
otp: opts.OTP,
HTTPClient: &http.Client{Timeout: 10 * time.Second},
}

c.baseURL, _ = url.Parse(defaultBaseURL)

if opts.Mode != "" {
c.mode = opts.Mode
}

if opts.Login != "" && opts.Username != "" {
c.username = fmt.Sprintf("%s.%s", opts.Login, opts.Username)
}

return c
}

func (c Client) GetZone(name string) (*Zone, error) {
resp, err := c.do(http.MethodGet, name, nil)
if err != nil {
return nil, err
}

defer func() { _ = resp.Body.Close() }()

if resp.StatusCode >= http.StatusBadRequest {
b, _ := ioutil.ReadAll(resp.Body)

msg := APIError{StatusCode: resp.StatusCode}
if err = json.Unmarshal(b, &msg); err != nil {
return nil, fmt.Errorf("failed to get zone info for %s", name)
}

return nil, msg
}

var zone Zone
err = json.NewDecoder(resp.Body).Decode(&zone)
if err != nil {
return nil, err
}

return &zone, nil
}

func (c Client) AddRecord(zone string, req RecordCreateUpdate) error {
resp, err := c.do(http.MethodPost, path.Join(zone, "records"), req)
if err != nil {
return err
}

defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != http.StatusAccepted {
b, _ := ioutil.ReadAll(resp.Body)

msg := APIError{StatusCode: resp.StatusCode}
if err = json.Unmarshal(b, &msg); err != nil {
return fmt.Errorf("records create should've returned %d but returned %d", http.StatusAccepted, resp.StatusCode)
}

return msg
}

return nil
}

func (c Client) DeleteRecord(zone string, record int) error {
resp, err := c.do(http.MethodDelete, path.Join(zone, "records", strconv.Itoa(record)), nil)
if err != nil {
return err
}

defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != http.StatusAccepted {
b, _ := ioutil.ReadAll(resp.Body)

msg := APIError{StatusCode: resp.StatusCode}
if err = json.Unmarshal(b, &msg); err != nil {
return fmt.Errorf("records delete should've returned %d but returned %d", http.StatusAccepted, resp.StatusCode)
}

return msg
}

return nil
}

func (c Client) do(method, uri string, body interface{}) (*http.Response, error) {
var reqBody io.Reader
if body != nil {
jsonValue, err := json.Marshal(body)
if err != nil {
return nil, err
}

reqBody = bytes.NewBuffer(jsonValue)
}

endpoint, err := c.baseURL.Parse(path.Join(c.baseURL.Path, c.mode, uri))
if err != nil {
return nil, err
}

r, err := http.NewRequest(method, endpoint.String(), reqBody)
if err != nil {
return nil, err
}

r.Header.Set("Accept", "application/json")
r.Header.Set("Content-Type", "application/json")

r.SetBasicAuth(c.username, c.password)

if c.otp != "" {
tan, err := totp.GenerateCode(c.otp, time.Now())
if err != nil {
return nil, err
}

r.Header.Set(headerTOTPToken, tan)
}

return c.HTTPClient.Do(r)
}
Loading