Skip to content
Draft
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
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,77 +197,77 @@ Detailed documentation is available [here](https://go-acme.github.io/lego/dns).
<td><a href="https://go-acme.github.io/lego/dns/nicmanager/">Nicmanager</a></td>
<td><a href="https://go-acme.github.io/lego/dns/nifcloud/">NIFCloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/njalla/">Njalla</a></td>
<td><a href="https://go-acme.github.io/lego/dns/nodion/">Nodion</a></td>
<td><a href="https://go-acme.github.io/lego/dns/noip/">No-IP</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/nodion/">Nodion</a></td>
<td><a href="https://go-acme.github.io/lego/dns/ns1/">NS1</a></td>
<td><a href="https://go-acme.github.io/lego/dns/octenium/">Octenium</a></td>
<td><a href="https://go-acme.github.io/lego/dns/otc/">Open Telekom Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/oraclecloud/">Oracle Cloud</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/oraclecloud/">Oracle Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/ovh/">OVH</a></td>
<td><a href="https://go-acme.github.io/lego/dns/plesk/">plesk.com</a></td>
<td><a href="https://go-acme.github.io/lego/dns/porkbun/">Porkbun</a></td>
<td><a href="https://go-acme.github.io/lego/dns/pdns/">PowerDNS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/pdns/">PowerDNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/rackspace/">Rackspace</a></td>
<td><a href="https://go-acme.github.io/lego/dns/rainyun/">Rain Yun/雨云</a></td>
<td><a href="https://go-acme.github.io/lego/dns/rcodezero/">RcodeZero</a></td>
<td><a href="https://go-acme.github.io/lego/dns/regru/">reg.ru</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/regru/">reg.ru</a></td>
<td><a href="https://go-acme.github.io/lego/dns/regfish/">Regfish</a></td>
<td><a href="https://go-acme.github.io/lego/dns/rfc2136/">RFC2136</a></td>
<td><a href="https://go-acme.github.io/lego/dns/rimuhosting/">RimuHosting</a></td>
<td><a href="https://go-acme.github.io/lego/dns/nicru/">RU CENTER</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/nicru/">RU CENTER</a></td>
<td><a href="https://go-acme.github.io/lego/dns/sakuracloud/">Sakura Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/scaleway/">Scaleway</a></td>
<td><a href="https://go-acme.github.io/lego/dns/selectel/">Selectel</a></td>
<td><a href="https://go-acme.github.io/lego/dns/selectelv2/">Selectel v2</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/selectelv2/">Selectel v2</a></td>
<td><a href="https://go-acme.github.io/lego/dns/selfhostde/">SelfHost.(de|eu)</a></td>
<td><a href="https://go-acme.github.io/lego/dns/servercow/">Servercow</a></td>
<td><a href="https://go-acme.github.io/lego/dns/shellrent/">Shellrent</a></td>
<td><a href="https://go-acme.github.io/lego/dns/simply/">Simply.com</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/simply/">Simply.com</a></td>
<td><a href="https://go-acme.github.io/lego/dns/sonic/">Sonic</a></td>
<td><a href="https://go-acme.github.io/lego/dns/spaceship/">Spaceship</a></td>
<td><a href="https://go-acme.github.io/lego/dns/stackpath/">Stackpath</a></td>
<td><a href="https://go-acme.github.io/lego/dns/technitium/">Technitium</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/technitium/">Technitium</a></td>
<td><a href="https://go-acme.github.io/lego/dns/tencentcloud/">Tencent Cloud DNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/edgeone/">Tencent EdgeOne</a></td>
<td><a href="https://go-acme.github.io/lego/dns/timewebcloud/">Timeweb Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/transip/">TransIP</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/transip/">TransIP</a></td>
<td><a href="https://go-acme.github.io/lego/dns/safedns/">UKFast SafeDNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/ultradns/">Ultradns</a></td>
<td><a href="https://go-acme.github.io/lego/dns/variomedia/">Variomedia</a></td>
<td><a href="https://go-acme.github.io/lego/dns/vegadns/">VegaDNS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/vegadns/">VegaDNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/vercel/">Vercel</a></td>
<td><a href="https://go-acme.github.io/lego/dns/versio/">Versio.[nl|eu|uk]</a></td>
<td><a href="https://go-acme.github.io/lego/dns/vinyldns/">VinylDNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/vkcloud/">VK Cloud</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/vkcloud/">VK Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/volcengine/">Volcano Engine/火山引擎</a></td>
<td><a href="https://go-acme.github.io/lego/dns/vscale/">Vscale</a></td>
<td><a href="https://go-acme.github.io/lego/dns/vultr/">Vultr</a></td>
<td><a href="https://go-acme.github.io/lego/dns/webnames/">Webnames</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/webnames/">Webnames</a></td>
<td><a href="https://go-acme.github.io/lego/dns/websupport/">Websupport</a></td>
<td><a href="https://go-acme.github.io/lego/dns/wedos/">WEDOS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/westcn/">West.cn/西部数码</a></td>
<td><a href="https://go-acme.github.io/lego/dns/yandex360/">Yandex 360</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/yandex360/">Yandex 360</a></td>
<td><a href="https://go-acme.github.io/lego/dns/yandexcloud/">Yandex Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/yandex/">Yandex PDD</a></td>
<td><a href="https://go-acme.github.io/lego/dns/zoneee/">Zone.ee</a></td>
<td><a href="https://go-acme.github.io/lego/dns/zoneedit/">ZoneEdit</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/zoneedit/">ZoneEdit</a></td>
<td><a href="https://go-acme.github.io/lego/dns/zonomi/">Zonomi</a></td>
<td></td>
<td></td>
<td></td>
</tr></table>

<!-- END DNS PROVIDERS LIST -->
Expand Down
21 changes: 21 additions & 0 deletions cmd/zz_gen_cmd_dnshelp.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 67 additions & 0 deletions docs/content/dns/zz_gen_noip.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/data/zz_cli_help.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

144 changes: 144 additions & 0 deletions providers/dns/noip/internal/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package internal

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"time"

"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
"github.com/go-acme/lego/v4/providers/dns/internal/useragent"
"golang.org/x/oauth2"
)

const defaultBaseURL = "https://api.noip.com"

// Client the No-IP API client.
type Client struct {
BaseURL *url.URL
httpClient *http.Client
}

// NewClient creates a new Client.
func NewClient(hc *http.Client) (*Client, error) {
baseURL, _ := url.Parse(defaultBaseURL)
if hc == nil {
hc = &http.Client{Timeout: 10 * time.Second}
}

return &Client{
BaseURL: baseURL,
httpClient: hc,
}, nil
}

// CreateRData creates a record.
// https://developer.noip.com/reference/v1-dns-records-create-rdata
func (c *Client) CreateRData(ctx context.Context, zone, name, dnsType string, data RData) error {
endpoint := c.BaseURL.JoinPath("v1", "dns", "records", zone, name, "rrsets", dnsType, "rdata")

req, err := newJSONRequest(ctx, http.MethodPost, endpoint, []RData{data})
if err != nil {
return err
}

return c.do(req, nil)
}

// DeleteRDataByLabel deletes a record by label.
// https://developer.noip.com/reference/v1-dns-records-delete-rdata-by-label
func (c *Client) DeleteRDataByLabel(ctx context.Context, zone, name, dnsType, label string) error {
endpoint := c.BaseURL.JoinPath("v1", "dns", "records", zone, name, "rrsets", dnsType, "rdata", label)

req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
if err != nil {
return err
}

return c.do(req, nil)
}

func (c *Client) do(req *http.Request, result any) error {
useragent.SetHeader(req.Header)

resp, err := c.httpClient.Do(req)
if err != nil {
return errutils.NewHTTPDoError(req, err)
}

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

if resp.StatusCode/100 != 2 {
return parseError(req, resp)
}

if result == nil {
return nil
}

raw, err := io.ReadAll(resp.Body)
if err != nil {
return errutils.NewReadResponseError(req, resp.StatusCode, err)
}

err = json.Unmarshal(raw, result)
if err != nil {
return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
}

return nil
}

func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
buf := new(bytes.Buffer)

if payload != nil {
err := json.NewEncoder(buf).Encode(payload)
if err != nil {
return nil, fmt.Errorf("failed to create request JSON body: %w", err)
}
}

req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
if err != nil {
return nil, fmt.Errorf("unable to create request: %w", err)
}

req.Header.Set("Accept", "application/json")

if payload != nil {
req.Header.Set("Content-Type", "application/json")
}

return req, nil
}

func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)

var apiResp APIResponse[any]

err := json.Unmarshal(raw, &apiResp)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
}

return fmt.Errorf("[status code %d] %w", resp.StatusCode, apiResp.Errors)
}

func OAuthStaticAccessToken(client *http.Client, accessToken string) *http.Client {
if client == nil {
client = &http.Client{Timeout: 5 * time.Second}
}

client.Transport = &oauth2.Transport{
Source: oauth2.StaticTokenSource(&oauth2.Token{AccessToken: accessToken}),
Base: client.Transport,
}

return client
}
Loading