vendor deps
This commit is contained in:
parent
8c8d5b150f
commit
750f339f58
189
vendor/github.com/go-acme/lego/v3/providers/dns/namedotcom/namedotcom.go
generated
vendored
Normal file
189
vendor/github.com/go-acme/lego/v3/providers/dns/namedotcom/namedotcom.go
generated
vendored
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
// Package namedotcom implements a DNS provider for solving the DNS-01 challenge using Name.com's DNS service.
|
||||||
|
package namedotcom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v3/challenge/dns01"
|
||||||
|
"github.com/go-acme/lego/v3/platform/config/env"
|
||||||
|
"github.com/namedotcom/go/namecom"
|
||||||
|
)
|
||||||
|
|
||||||
|
// according to https://www.name.com/api-docs/DNS#CreateRecord
|
||||||
|
const minTTL = 300
|
||||||
|
|
||||||
|
// Environment variables names.
|
||||||
|
const (
|
||||||
|
envNamespace = "NAMECOM_"
|
||||||
|
|
||||||
|
EnvUsername = envNamespace + "USERNAME"
|
||||||
|
EnvAPIToken = envNamespace + "API_TOKEN"
|
||||||
|
EnvServer = envNamespace + "SERVER"
|
||||||
|
|
||||||
|
EnvTTL = envNamespace + "TTL"
|
||||||
|
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
||||||
|
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
|
||||||
|
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config is used to configure the creation of the DNSProvider.
|
||||||
|
type Config struct {
|
||||||
|
Username string
|
||||||
|
APIToken string
|
||||||
|
Server string
|
||||||
|
TTL int
|
||||||
|
PropagationTimeout time.Duration
|
||||||
|
PollingInterval time.Duration
|
||||||
|
HTTPClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultConfig returns a default configuration for the DNSProvider.
|
||||||
|
func NewDefaultConfig() *Config {
|
||||||
|
return &Config{
|
||||||
|
TTL: env.GetOrDefaultInt(EnvTTL, minTTL),
|
||||||
|
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 15*time.Minute),
|
||||||
|
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 20*time.Second),
|
||||||
|
HTTPClient: &http.Client{
|
||||||
|
Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 10*time.Second),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSProvider implements the challenge.Provider interface.
|
||||||
|
type DNSProvider struct {
|
||||||
|
client *namecom.NameCom
|
||||||
|
config *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDNSProvider returns a DNSProvider instance configured for namedotcom.
|
||||||
|
// Credentials must be passed in the environment variables:
|
||||||
|
// NAMECOM_USERNAME and NAMECOM_API_TOKEN.
|
||||||
|
func NewDNSProvider() (*DNSProvider, error) {
|
||||||
|
values, err := env.Get(EnvUsername, EnvAPIToken)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("namedotcom: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := NewDefaultConfig()
|
||||||
|
config.Username = values[EnvUsername]
|
||||||
|
config.APIToken = values[EnvAPIToken]
|
||||||
|
config.Server = env.GetOrFile(EnvServer)
|
||||||
|
|
||||||
|
return NewDNSProviderConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDNSProviderConfig return a DNSProvider instance configured for namedotcom.
|
||||||
|
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||||
|
if config == nil {
|
||||||
|
return nil, errors.New("namedotcom: the configuration of the DNS provider is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Username == "" {
|
||||||
|
return nil, errors.New("namedotcom: username is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.APIToken == "" {
|
||||||
|
return nil, errors.New("namedotcom: API token is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.TTL < minTTL {
|
||||||
|
return nil, fmt.Errorf("namedotcom: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := namecom.New(config.Username, config.APIToken)
|
||||||
|
client.Client = config.HTTPClient
|
||||||
|
|
||||||
|
if config.Server != "" {
|
||||||
|
client.Server = config.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DNSProvider{client: client, config: config}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Present creates a TXT record to fulfill the dns-01 challenge.
|
||||||
|
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
|
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
|
domainDetails, err := d.client.GetDomain(&namecom.GetDomainRequest{DomainName: domain})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("namedotcom API call failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
request := &namecom.Record{
|
||||||
|
DomainName: domain,
|
||||||
|
Host: d.extractRecordName(fqdn, domainDetails.DomainName),
|
||||||
|
Type: "TXT",
|
||||||
|
TTL: uint32(d.config.TTL),
|
||||||
|
Answer: value,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = d.client.CreateRecord(request)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("namedotcom: API call failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanUp removes the TXT record matching the specified parameters.
|
||||||
|
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
|
fqdn, _ := dns01.GetRecord(domain, keyAuth)
|
||||||
|
|
||||||
|
records, err := d.getRecords(domain)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("namedotcom: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rec := range records {
|
||||||
|
if rec.Fqdn == fqdn && rec.Type == "TXT" {
|
||||||
|
request := &namecom.DeleteRecordRequest{
|
||||||
|
DomainName: domain,
|
||||||
|
ID: rec.ID,
|
||||||
|
}
|
||||||
|
_, err := d.client.DeleteRecord(request)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("namedotcom: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout returns the timeout and interval to use when checking for DNS propagation.
|
||||||
|
// Adjusting here to cope with spikes in propagation times.
|
||||||
|
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||||
|
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) getRecords(domain string) ([]*namecom.Record, error) {
|
||||||
|
request := &namecom.ListRecordsRequest{
|
||||||
|
DomainName: domain,
|
||||||
|
Page: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
var records []*namecom.Record
|
||||||
|
for request.Page > 0 {
|
||||||
|
response, err := d.client.ListRecords(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
records = append(records, response.Records...)
|
||||||
|
request.Page = response.NextPage
|
||||||
|
}
|
||||||
|
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) extractRecordName(fqdn, domain string) string {
|
||||||
|
name := dns01.UnFqdn(fqdn)
|
||||||
|
if idx := strings.Index(name, "."+domain); idx != -1 {
|
||||||
|
return name[:idx]
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
26
vendor/github.com/go-acme/lego/v3/providers/dns/namedotcom/namedotcom.toml
generated
vendored
Normal file
26
vendor/github.com/go-acme/lego/v3/providers/dns/namedotcom/namedotcom.toml
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
Name = "Name.com"
|
||||||
|
Description = ''''''
|
||||||
|
URL = "https://www.name.com"
|
||||||
|
Code = "namedotcom"
|
||||||
|
Since = "v0.5.0"
|
||||||
|
|
||||||
|
Example = '''
|
||||||
|
NAMECOM_USERNAME=foo.bar \
|
||||||
|
NAMECOM_API_TOKEN=a379a6f6eeafb9a55e378c118034e2751e682fab \
|
||||||
|
lego --dns="namedotcom" --domains="my.domain.com" --email="my@email.com" run
|
||||||
|
'''
|
||||||
|
|
||||||
|
[Configuration]
|
||||||
|
[Configuration.Credentials]
|
||||||
|
NAMECOM_USERNAME = "Username"
|
||||||
|
NAMECOM_API_TOKEN = "API token"
|
||||||
|
[Configuration.Additional]
|
||||||
|
NAMECOM_POLLING_INTERVAL = "Time between DNS propagation check"
|
||||||
|
NAMECOM_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
|
||||||
|
NAMECOM_TTL = "The TTL of the TXT record used for the DNS challenge"
|
||||||
|
NAMECOM_HTTP_TIMEOUT = "API request timeout"
|
||||||
|
|
||||||
|
[Links]
|
||||||
|
API = "https://www.name.com/api-docs/DNS"
|
||||||
|
GoClient = "https://github.com/namedotcom/go"
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Name.com
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,133 @@
|
||||||
|
package namecom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = bytes.MinRead
|
||||||
|
|
||||||
|
// ListRecords returns all records for a zone.
|
||||||
|
func (n *NameCom) ListRecords(request *ListRecordsRequest) (*ListRecordsResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/records", request.DomainName)
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
if request.PerPage != 0 {
|
||||||
|
values.Set("perPage", fmt.Sprintf("%d", request.PerPage))
|
||||||
|
}
|
||||||
|
if request.Page != 0 {
|
||||||
|
values.Set("page", fmt.Sprintf("%d", request.Page))
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &ListRecordsResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRecord returns details about an individual record.
|
||||||
|
func (n *NameCom) GetRecord(request *GetRecordRequest) (*Record, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/records/%d", request.DomainName, request.ID)
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Record{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRecord creates a new record in the zone.
|
||||||
|
func (n *NameCom) CreateRecord(request *Record) (*Record, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/records", request.DomainName)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Record{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRecord replaces the record with the new record that is passed.
|
||||||
|
func (n *NameCom) UpdateRecord(request *Record) (*Record, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/records/%d", request.DomainName, request.ID)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.put(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Record{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRecord deletes a record from the zone.
|
||||||
|
func (n *NameCom) DeleteRecord(request *DeleteRecordRequest) (*EmptyResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/records/%d", request.DomainName, request.ID)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.delete(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &EmptyResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
package namecom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = bytes.MinRead
|
||||||
|
|
||||||
|
// ListDNSSECs lists all of the DNSSEC keys registered with the registry.
|
||||||
|
func (n *NameCom) ListDNSSECs(request *ListDNSSECsRequest) (*ListDNSSECsResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/dnssec", request.DomainName)
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &ListDNSSECsResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDNSSEC retrieves the details for a key registered with the registry.
|
||||||
|
func (n *NameCom) GetDNSSEC(request *GetDNSSECRequest) (*DNSSEC, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/dnssec/%s", request.DomainName, request.Digest)
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &DNSSEC{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateDNSSEC registers a DNSSEC key with the registry.
|
||||||
|
func (n *NameCom) CreateDNSSEC(request *DNSSEC) (*DNSSEC, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/dnssec", request.DomainName)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &DNSSEC{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteDNSSEC removes a DNSSEC key from the registry.
|
||||||
|
func (n *NameCom) DeleteDNSSEC(request *DeleteDNSSECRequest) (*EmptyResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/dnssec/%s", request.DomainName, request.Digest)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.delete(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &EmptyResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
|
@ -0,0 +1,382 @@
|
||||||
|
package namecom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = bytes.MinRead
|
||||||
|
|
||||||
|
// ListDomains returns all domains in the account. It omits some information that can be retrieved from GetDomain.
|
||||||
|
func (n *NameCom) ListDomains(request *ListDomainsRequest) (*ListDomainsResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains")
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
if request.PerPage != 0 {
|
||||||
|
values.Set("perPage", fmt.Sprintf("%d", request.PerPage))
|
||||||
|
}
|
||||||
|
if request.Page != 0 {
|
||||||
|
values.Set("page", fmt.Sprintf("%d", request.Page))
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &ListDomainsResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDomain returns details about a specific domain
|
||||||
|
func (n *NameCom) GetDomain(request *GetDomainRequest) (*Domain, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s", request.DomainName)
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Domain{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateDomain purchases a new domain. Domains that are not regularly priced require the purchase_price field to be specified.
|
||||||
|
func (n *NameCom) CreateDomain(request *CreateDomainRequest) (*CreateDomainResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &CreateDomainResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableAutorenew enables the domain to be automatically renewed when it gets close to expiring.
|
||||||
|
func (n *NameCom) EnableAutorenew(request *EnableAutorenewForDomainRequest) (*Domain, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Domain{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableAutorenew disables automatic renewals, thus requiring the domain to be renewed manually.
|
||||||
|
func (n *NameCom) DisableAutorenew(request *DisableAutorenewForDomainRequest) (*Domain, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Domain{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenewDomain will renew a domain. Purchase_price is required if the renewal is not regularly priced.
|
||||||
|
func (n *NameCom) RenewDomain(request *RenewDomainRequest) (*RenewDomainResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &RenewDomainResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAuthCodeForDomain returns the Transfer Authorization Code for the domain.
|
||||||
|
func (n *NameCom) GetAuthCodeForDomain(request *AuthCodeRequest) (*AuthCodeResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains")
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
if request.DomainName != "" {
|
||||||
|
values.Set("domainName", request.DomainName)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &AuthCodeResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PurchasePrivacy will add Whois Privacy protection to a domain or will an renew existing subscription.
|
||||||
|
func (n *NameCom) PurchasePrivacy(request *PrivacyRequest) (*PrivacyResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &PrivacyResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNameservers will set the nameservers for the Domain.
|
||||||
|
func (n *NameCom) SetNameservers(request *SetNameserversRequest) (*Domain, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s:setNameservers", request.DomainName)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Domain{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContacts will set the contacts for the Domain.
|
||||||
|
func (n *NameCom) SetContacts(request *SetContactsRequest) (*Domain, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Domain{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LockDomain will lock a domain so that it cannot be transfered to another registrar.
|
||||||
|
func (n *NameCom) LockDomain(request *LockDomainRequest) (*Domain, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Domain{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnlockDomain will unlock a domain so that it can be transfered to another registrar.
|
||||||
|
func (n *NameCom) UnlockDomain(request *UnlockDomainRequest) (*Domain, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Domain{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckAvailability will check a list of domains to see if they are purchaseable. A Maximum of 50 domains can be specified.
|
||||||
|
func (n *NameCom) CheckAvailability(request *AvailabilityRequest) (*SearchResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains:checkAvailability")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &SearchResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search will perform a search for specified keywords.
|
||||||
|
func (n *NameCom) Search(request *SearchRequest) (*SearchResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains:search")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &SearchResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchStream will return JSON encoded SearchResults as they are recieved from the registry. The SearchResults are separated by newlines. This can allow clients to react to results before the search is fully completed.
|
||||||
|
func (n *NameCom) SearchStream(request *SearchRequest) (*SearchResult, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains:searchStream")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &SearchResult{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
package namecom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = bytes.MinRead
|
||||||
|
|
||||||
|
// ListEmailForwardings returns a pagenated list of email forwarding entries for a domain.
|
||||||
|
func (n *NameCom) ListEmailForwardings(request *ListEmailForwardingsRequest) (*ListEmailForwardingsResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/email/forwarding", request.DomainName)
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
if request.PerPage != 0 {
|
||||||
|
values.Set("perPage", fmt.Sprintf("%d", request.PerPage))
|
||||||
|
}
|
||||||
|
if request.Page != 0 {
|
||||||
|
values.Set("page", fmt.Sprintf("%d", request.Page))
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &ListEmailForwardingsResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEmailForwarding returns an email forwarding entry.
|
||||||
|
func (n *NameCom) GetEmailForwarding(request *GetEmailForwardingRequest) (*EmailForwarding, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/email/forwarding/%s", request.DomainName, request.EmailBox)
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &EmailForwarding{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEmailForwarding creates an email forwarding entry. If this is the first email forwarding entry, it may modify the MX records for the domain accordingly.
|
||||||
|
func (n *NameCom) CreateEmailForwarding(request *EmailForwarding) (*EmailForwarding, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/email/forwarding", request.DomainName)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &EmailForwarding{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEmailForwarding updates which email address the email is being forwarded to.
|
||||||
|
func (n *NameCom) UpdateEmailForwarding(request *EmailForwarding) (*EmailForwarding, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/email/forwarding/%s", request.DomainName, request.EmailBox)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.put(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &EmailForwarding{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteEmailForwarding deletes the email forwarding entry.
|
||||||
|
func (n *NameCom) DeleteEmailForwarding(request *DeleteEmailForwardingRequest) (*EmptyResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/email/forwarding/%s", request.DomainName, request.EmailBox)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.delete(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &EmptyResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package namecom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = bytes.MinRead
|
||||||
|
|
||||||
|
// HelloFunc returns some information about the API server.
|
||||||
|
func (n *NameCom) HelloFunc(request *HelloRequest) (*HelloResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/hello")
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &HelloResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
|
@ -0,0 +1,729 @@
|
||||||
|
/*
|
||||||
|
Package namecom provides a client for accessing the Name.com v4 API.
|
||||||
|
|
||||||
|
See https://www.name.com/api-docs for an introduction
|
||||||
|
to the Name.com v4 API.
|
||||||
|
|
||||||
|
Creating a Client
|
||||||
|
|
||||||
|
To start working with this package, create a client with user credentials
|
||||||
|
|
||||||
|
nc := namecom.New("username","apitoken")
|
||||||
|
|
||||||
|
To check if the username and token are correct using the HelloFunc endpoint
|
||||||
|
|
||||||
|
response, err := nc.HelloFunc(&namecom.HelloRequest{})
|
||||||
|
if err != nil {
|
||||||
|
// TODO: handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
package namecom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NameCom is a client for connecting to the Name.com API.
|
||||||
|
type NameCom struct {
|
||||||
|
Server string
|
||||||
|
User string
|
||||||
|
Token string
|
||||||
|
Client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new NameCom client using the production environment server endpoint.
|
||||||
|
func New(user, token string) *NameCom {
|
||||||
|
return &NameCom{
|
||||||
|
Server: "api.name.com",
|
||||||
|
User: user,
|
||||||
|
Token: token,
|
||||||
|
Client: &http.Client{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test creates a new NameCom client using the test environment server enpoint.
|
||||||
|
func Test(user, token string) *NameCom {
|
||||||
|
return &NameCom{
|
||||||
|
Server: "api.dev.name.com",
|
||||||
|
User: user,
|
||||||
|
Token: token,
|
||||||
|
Client: &http.Client{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error allows an ErrorResponse object to implement the error interface.
|
||||||
|
func (er ErrorResponse) Error() string {
|
||||||
|
return er.Message + ": " + er.Details
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NameCom) errorResponse(resp *http.Response) error {
|
||||||
|
er := &ErrorResponse{}
|
||||||
|
err := json.NewDecoder(resp.Body).Decode(er)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "api returned unexpected response")
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.WithStack(er)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NameCom) get(endpoint string, values url.Values) (io.Reader, error) {
|
||||||
|
if len(values) == 0 {
|
||||||
|
endpoint = endpoint + "?" + values.Encode()
|
||||||
|
}
|
||||||
|
return n.doRequest("GET", endpoint, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NameCom) post(endpoint string, post io.Reader) (io.Reader, error) {
|
||||||
|
return n.doRequest("POST", endpoint, post)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NameCom) put(endpoint string, post io.Reader) (io.Reader, error) {
|
||||||
|
return n.doRequest("PUT", endpoint, post)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NameCom) delete(endpoint string, post io.Reader) (io.Reader, error) {
|
||||||
|
return n.doRequest("DELETE", endpoint, post)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NameCom) doRequest(method, endpoint string, post io.Reader) (io.Reader, error) {
|
||||||
|
if n.User == "" || n.Token == "" {
|
||||||
|
return nil, errors.New("both User and Token must be specified")
|
||||||
|
}
|
||||||
|
if n.Server == "" {
|
||||||
|
n.Server = "api.name.com"
|
||||||
|
}
|
||||||
|
if n.Client == nil {
|
||||||
|
n.Client = &http.Client{Timeout: 10 * time.Second}
|
||||||
|
}
|
||||||
|
|
||||||
|
url := "https://" + n.Server + endpoint
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, url, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.SetBasicAuth(n.User, n.Token)
|
||||||
|
|
||||||
|
resp, err := n.Client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return nil, n.errorResponse(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.Body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmptyResponse is an empty response used for DELETE endpoints.
|
||||||
|
type EmptyResponse struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorResponse is what is returned if the HTTP status code is not 200.
|
||||||
|
type ErrorResponse struct {
|
||||||
|
// Message is the error message.
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
// Details may have some additional details about the error.
|
||||||
|
Details string `json:"details,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record is an individual DNS resource record.
|
||||||
|
type Record struct {
|
||||||
|
// Unique record id. Value is ignored on Create, and must match the URI on Update.
|
||||||
|
ID int32 `json:"id,omitempty"`
|
||||||
|
// DomainName is the zone that the record belongs to.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Host is the hostname relative to the zone: e.g. for a record for blog.example.org, domain would be "example.org" and host would be "blog".
|
||||||
|
// An apex record would be specified by either an empty host "" or "@".
|
||||||
|
// A SRV record would be specified by "_{service}._{protocal}.{host}": e.g. "_sip._tcp.phone" for _sip._tcp.phone.example.org.
|
||||||
|
Host string `json:"host,omitempty"`
|
||||||
|
// FQDN is the Fully Qualified Domain Name. It is the combination of the host and the domain name. It always ends in a ".". FQDN is ignored in CreateRecord, specify via the Host field instead.
|
||||||
|
Fqdn string `json:"fqdn,omitempty"`
|
||||||
|
// Type is one of the following: A, AAAA, ANAME, CNAME, MX, NS, SRV, or TXT.
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
// Answer is either the IP address for A or AAAA records; the target for ANAME, CNAME, MX, or NS records; the text for TXT records.
|
||||||
|
// For SRV records, answer has the following format: "{weight} {port} {target}" e.g. "1 5061 sip.example.org".
|
||||||
|
Answer string `json:"answer,omitempty"`
|
||||||
|
// TTL is the time this record can be cached for in seconds. Name.com allows a minimum TTL of 300, or 5 minutes.
|
||||||
|
TTL uint32 `json:"ttl,omitempty"`
|
||||||
|
// Priority is only required for MX and SRV records, it is ignored for all others.
|
||||||
|
Priority uint32 `json:"priority,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRecordsRequest requests a list of records that exist for the domain
|
||||||
|
type ListRecordsRequest struct {
|
||||||
|
// DomainName is the zone to list the records for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Per Page is the number of records to return per request. Per Page defaults to 1,000.
|
||||||
|
PerPage int32 `json:"perPage,omitempty"`
|
||||||
|
// Page is which page to return
|
||||||
|
Page int32 `json:"page,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRecordsResponse is the response for the ListRecords function.
|
||||||
|
type ListRecordsResponse struct {
|
||||||
|
// Records contains the records in the zone
|
||||||
|
Records []*Record `json:"records,omitempty"`
|
||||||
|
// NextPage is the identifier for the next page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
NextPage int32 `json:"nextPage,omitempty"`
|
||||||
|
// LastPage is the identifier for the final page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
LastPage int32 `json:"lastPage,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRecordRequest requests the record identified by id and domain.
|
||||||
|
type GetRecordRequest struct {
|
||||||
|
// DomainName is the zone the record exists in
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// ID is the server-assigned unique identifier for this record
|
||||||
|
ID int32 `json:"id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRecordRequest deletes a specific record
|
||||||
|
type DeleteRecordRequest struct {
|
||||||
|
// DomainName is the zone that the record to be deleted exists in.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// ID is the server-assigned unique identifier for the Record to be deleted. If the Record with that ID does not exist in the specified Domain, an error is returned.
|
||||||
|
ID int32 `json:"id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSSEC contains all the data required to create a DS record at the registry.
|
||||||
|
type DNSSEC struct {
|
||||||
|
// DomainName is the domain name.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// KeyTag contains the key tag value of the DNSKEY RR that validates this signature. The algorithm to generate it is here: https://tools.ietf.org/html/rfc4034#appendix-B
|
||||||
|
KeyTag int32 `json:"keyTag,omitempty"`
|
||||||
|
// Algorithm is an integer identifying the algorithm used for signing. Valid values can be found here: https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
|
||||||
|
Algorithm int32 `json:"algorithm,omitempty"`
|
||||||
|
// DigestType is an integer identifying the algorithm used to create the digest. Valid values can be found here: https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml
|
||||||
|
DigestType int32 `json:"digestType,omitempty"`
|
||||||
|
// Digest is a digest of the DNSKEY RR that is registered with the registry.
|
||||||
|
Digest string `json:"digest,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListDNSSECsRequest contains the domain name to list DS records for.
|
||||||
|
type ListDNSSECsRequest struct {
|
||||||
|
// DomainName is the domain name to list keys for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListDNSSECsResponse contains the list of DS records at the registry.
|
||||||
|
type ListDNSSECsResponse struct {
|
||||||
|
// Dnssec is the list of registered DNSSEC keys.
|
||||||
|
Dnssec []*DNSSEC `json:"dnssec,omitempty"`
|
||||||
|
// NextPage is the identifier for the next page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
NextPage int32 `json:"nextPage,omitempty"`
|
||||||
|
// LastPage is the identifier for the final page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
LastPage int32 `json:"lastPage,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDNSSECRequest gets the information for a specific DS record at the registry.
|
||||||
|
type GetDNSSECRequest struct {
|
||||||
|
// DomainName is the domain name.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Digest is the digest for the DNSKEY RR to retrieve.
|
||||||
|
Digest string `json:"digest,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteDNSSECRequest specifies the domain name and digest to remove from the registry.
|
||||||
|
type DeleteDNSSECRequest struct {
|
||||||
|
// DomainName is the domain name the key is registered for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Digest is the digest for the DNSKEY RR to remove from the registry.
|
||||||
|
Digest string `json:"digest,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contact contains all the contact data.
|
||||||
|
type Contact struct {
|
||||||
|
// First name of the contact.
|
||||||
|
FirstName string `json:"firstName,omitempty"`
|
||||||
|
// Last name of the contact.
|
||||||
|
LastName string `json:"lastName,omitempty"`
|
||||||
|
// Company name of the contact. Leave blank if the contact is an individual as some registries will assume it is a corporate entity otherwise.
|
||||||
|
CompanyName string `json:"companyName,omitempty"`
|
||||||
|
// Address1 is the first line of the contact's address.
|
||||||
|
Address1 string `json:"address1,omitempty"`
|
||||||
|
// Address2 is the second line of the contact's address.
|
||||||
|
Address2 string `json:"address2,omitempty"`
|
||||||
|
// City of the contact's address.
|
||||||
|
City string `json:"city,omitempty"`
|
||||||
|
// State or Province for the contact's address.
|
||||||
|
State string `json:"state,omitempty"`
|
||||||
|
// Zip or Postal Code for the contact's address.
|
||||||
|
Zip string `json:"zip,omitempty"`
|
||||||
|
// Country code for the contact's address. Required to be a ISO 3166-1 alpha-2 code.
|
||||||
|
Country string `json:"country,omitempty"`
|
||||||
|
// Phone number of the contact. Should be specified in the following format: "+cc.llllllll" where cc is the country code and llllllll is the local number.
|
||||||
|
Phone string `json:"phone,omitempty"`
|
||||||
|
// Fax number of the contact. Should be specified in the following format: "+cc.llllllll" where cc is the country code and llllllll is the local number.
|
||||||
|
Fax string `json:"fax,omitempty"`
|
||||||
|
// Email of the contact. Should be a complete and valid email address.
|
||||||
|
Email string `json:"email,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contacts stores the contact information for the roles related to domains.
|
||||||
|
type Contacts struct {
|
||||||
|
// Registrant is the rightful owner of the account and has the right to use and/or sell the domain name. They are able to make changes to all account, domain, and product settings. This information should be reviewed and updated regularly to ensure accuracy.
|
||||||
|
Registrant *Contact `json:"registrant,omitempty"`
|
||||||
|
// Registrants often designate an administrative contact to manage their domain name(s). They primarily deal with business information such as the name on record, postal address, and contact information for the official registrant.
|
||||||
|
Admin *Contact `json:"admin,omitempty"`
|
||||||
|
// The technical contact manages and maintains a domain’s nameservers. If you’re working with a web designer or someone in a similar role, you many want to assign them as a technical contact.
|
||||||
|
Tech *Contact `json:"tech,omitempty"`
|
||||||
|
// The billing contact is the party responsible for paying bills for the account and taking care of renewals.
|
||||||
|
Billing *Contact `json:"billing,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Domain lists all the data for a domain.
|
||||||
|
type Domain struct {
|
||||||
|
// DomainName is the punycode encoded value of the domain name.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Nameservers is the list of nameservers for this domain. If unspecified it defaults to your account default nameservers.
|
||||||
|
Nameservers []string `json:"nameservers,omitempty"`
|
||||||
|
// Contacts for the domain.
|
||||||
|
Contacts *Contacts `json:"contacts,omitempty"`
|
||||||
|
// PrivacyEnabled reflects if Whois Privacy is enabled for this domain.
|
||||||
|
PrivacyEnabled bool `json:"privacyEnabled,omitempty"`
|
||||||
|
// Locked indicates that the domain cannot be transfered to another registrar.
|
||||||
|
Locked bool `json:"locked,omitempty"`
|
||||||
|
// AutorenewEnabled indicates if the domain will attempt to renew automatically before expiration.
|
||||||
|
AutorenewEnabled bool `json:"autorenewEnabled,omitempty"`
|
||||||
|
// ExpireDate is the date the domain will expire.
|
||||||
|
ExpireDate string `json:"expireDate,omitempty"`
|
||||||
|
// CreateDate is the date the domain was created at the registry.
|
||||||
|
CreateDate string `json:"createDate,omitempty"`
|
||||||
|
// RenewalPrice is the price to renew the domain. It may be required for the RenewDomain command.
|
||||||
|
RenewalPrice float64 `json:"renewalPrice,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchRequest is used to specify the search parameters.
|
||||||
|
type SearchRequest struct {
|
||||||
|
// Timeout is a value in milliseconds on how long to perform the search for. Valid timeouts are between 500ms to 5,000ms. If not specified, timeout defaults to 1,000ms.
|
||||||
|
// Since some additional processing is performed on the results, a response may take longer then the timeout.
|
||||||
|
Timeout int32 `json:"timeout,omitempty"`
|
||||||
|
// Keyword is the search term to search for. It can be just a word, or a whole domain name.
|
||||||
|
Keyword string `json:"keyword,omitempty"`
|
||||||
|
// TLDFilter will limit results to only contain the specified TLDs.
|
||||||
|
TldFilter []string `json:"tldFilter,omitempty"`
|
||||||
|
// PromoCode is not implemented yet.
|
||||||
|
PromoCode string `json:"promoCode,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AvailabilityRequest is used to list the domain names to check availability for.
|
||||||
|
type AvailabilityRequest struct {
|
||||||
|
// DomainNames is the list of domains to check if they are available.
|
||||||
|
DomainNames []string `json:"domainNames,omitempty"`
|
||||||
|
// PromoCode is not implemented yet.
|
||||||
|
PromoCode string `json:"promoCode,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchResult is returned by the CheckAvailability, Search, and SearchStream functions.
|
||||||
|
type SearchResult struct {
|
||||||
|
// DomainName is the punycode encoding of the result domain name.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// SLD is first portion of the domain_name.
|
||||||
|
Sld string `json:"sld,omitempty"`
|
||||||
|
// TLD is the rest of the domain_name after the SLD.
|
||||||
|
Tld string `json:"tld,omitempty"`
|
||||||
|
// Purchaseable indicates whether the search result is available for purchase.
|
||||||
|
Purchasable bool `json:"purchasable,omitempty"`
|
||||||
|
// Premium indicates that this search result is a premium result and the purchase_price needs to be passed to the DomainCreate command.
|
||||||
|
Premium bool `json:"premium,omitempty"`
|
||||||
|
// PurchasePrice is the price for purchasing this domain for 1 year. Purchase_price is always in USD.
|
||||||
|
PurchasePrice float64 `json:"purchasePrice,omitempty"`
|
||||||
|
// PurchaseType indicates what kind of purchase this result is for. It should be passed to the DomainCreate command.
|
||||||
|
PurchaseType string `json:"purchaseType,omitempty"`
|
||||||
|
// RenewalPrice is the annual renewal price for this domain as it may be different then the purchase_price.
|
||||||
|
RenewalPrice float64 `json:"renewalPrice,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchResponse returns a list of search results.
|
||||||
|
type SearchResponse struct {
|
||||||
|
// Results of the search are returned here, the order should not be relied upon.
|
||||||
|
Results []*SearchResult `json:"results,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListDomainsRequest is used to pass the pagination parameters to the ListDomains function.
|
||||||
|
type ListDomainsRequest struct {
|
||||||
|
// Per Page is the number of records to return per request. Per Page defaults to 1,000.
|
||||||
|
PerPage int32 `json:"perPage,omitempty"`
|
||||||
|
// Page is which page to return
|
||||||
|
Page int32 `json:"page,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListDomainsResponse is the response from a list request, it contains the paginated list of Domains.
|
||||||
|
type ListDomainsResponse struct {
|
||||||
|
// Domains is the list of domains in your account.
|
||||||
|
Domains []*Domain `json:"domains,omitempty"`
|
||||||
|
// NextPage is the identifier for the next page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
NextPage int32 `json:"nextPage,omitempty"`
|
||||||
|
// LastPage is the identifier for the final page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
LastPage int32 `json:"lastPage,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDomainRequest specifies the domain name to request data for in the GetDomain function.
|
||||||
|
type GetDomainRequest struct {
|
||||||
|
// DomainName is the domain to retrieve.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateDomainRequest has the information that is needed to create a domain with the CreateDomain function.
|
||||||
|
type CreateDomainRequest struct {
|
||||||
|
// Domain is the domain object to create. If privacy_enabled is set, Whois Privacy will also be purchased for an additional amount.
|
||||||
|
Domain *Domain `json:"domain,omitempty"`
|
||||||
|
// PurchasePrice is the amount to pay for the domain. If privacy_enabled is set, the regular price for whois protection will be added automatically. If VAT tax applies, it will also be added automatically.
|
||||||
|
// PurchasePrice is required if purchase_type is not "registration" or if it is a premium domain.
|
||||||
|
PurchasePrice float64 `json:"purchasePrice,omitempty"`
|
||||||
|
// PurchaseType defaults to "registration" but should be copied from the result of a search command otherwise.
|
||||||
|
PurchaseType string `json:"purchaseType,omitempty"`
|
||||||
|
// Years is for how many years to register the domain for. Years defaults to 1 if not passed and cannot be more than 10.
|
||||||
|
// If passing purchase_price make sure to adjust it accordingly.
|
||||||
|
Years int32 `json:"years,omitempty"`
|
||||||
|
// TLDRequirements is a way to pass additional data that is required by some registries.
|
||||||
|
TldRequirements map[string]string `json:"tldRequirements,omitempty"`
|
||||||
|
// PromoCode is not yet implemented.
|
||||||
|
PromoCode string `json:"promoCode,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateDomainResponse contains the domain info as well as the order info for the created domain.
|
||||||
|
type CreateDomainResponse struct {
|
||||||
|
// Domain is the newly created domain.
|
||||||
|
Domain *Domain `json:"domain,omitempty"`
|
||||||
|
// Order is an identifier for this purchase.
|
||||||
|
Order int32 `json:"order,omitempty"`
|
||||||
|
// TotalPaid is the total amount paid, including VAT and whois protection.
|
||||||
|
TotalPaid float64 `json:"totalPaid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenewDomainRequest passes the domain name and purchase parameters to the RenewDomain function.
|
||||||
|
type RenewDomainRequest struct {
|
||||||
|
// DomainName is the domain to renew.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// PurchasePrice is the amount to pay for the domain renewal. If VAT tax applies, it will also be added automatically.
|
||||||
|
// PurchasePrice is required if this is a premium domain.
|
||||||
|
PurchasePrice float64 `json:"purchasePrice,omitempty"`
|
||||||
|
// Years is for how many years to renew the domain for. Years defaults to 1 if not passed and cannot be more than 10.
|
||||||
|
Years int32 `json:"years,omitempty"`
|
||||||
|
// PromoCode is not yet implemented.
|
||||||
|
PromoCode string `json:"promoCode,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenewDomainResponse contains the updated domain info as well as the order info for the renewed domain.
|
||||||
|
type RenewDomainResponse struct {
|
||||||
|
// Domain reflects the status of the domain after renewing.
|
||||||
|
Domain *Domain `json:"domain,omitempty"`
|
||||||
|
// Order is an identifier for this purchase
|
||||||
|
Order int32 `json:"order,omitempty"`
|
||||||
|
// TotalPaid is the total amount paid, including VAT.
|
||||||
|
TotalPaid float64 `json:"totalPaid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthCodeRequest passes the domain name to the GetAuthCodeForDomain funtion.
|
||||||
|
type AuthCodeRequest struct {
|
||||||
|
// DomainName is the domain name to retrieve the authorization code for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthCodeResponse returns the auth code from the GetAuthCodeForDomain funtion.
|
||||||
|
type AuthCodeResponse struct {
|
||||||
|
// AuthCode is the authorization code needed to transfer a domain to another registrar. If you are storing auth codes, be sure to store them in a secure manner.
|
||||||
|
AuthCode string `json:"authCode,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrivacyRequest passes the domain name as well as the purchase parameters to the PurchasePrivacy function.
|
||||||
|
type PrivacyRequest struct {
|
||||||
|
// DomainName is the domain to purchase Whois Privacy for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// PurchasePrice is the amount you expect to pay.
|
||||||
|
PurchasePrice float64 `json:"purchasePrice,omitempty"`
|
||||||
|
// Years is the number of years you wish to purchase Whois Privacy for. Years defaults to 1 and cannot be more then the domain expiration date.
|
||||||
|
Years int32 `json:"years,omitempty"`
|
||||||
|
// PromoCode is not yet implemented
|
||||||
|
PromoCode string `json:"promoCode,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrivacyResponse contains the updated domain info as well as the order info for the newly purchased Whois Privacy.
|
||||||
|
type PrivacyResponse struct {
|
||||||
|
// Domain is the status of the domain after the purchase of Whois Privacy.
|
||||||
|
Domain *Domain `json:"domain,omitempty"`
|
||||||
|
// Order is an identifier for this purchase.
|
||||||
|
Order int32 `json:"order,omitempty"`
|
||||||
|
// TotalPaid is the total amount paid, including VAT.
|
||||||
|
TotalPaid float64 `json:"totalPaid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNameserversRequest passes the list of nameservers to set for the SetNameserver function.
|
||||||
|
type SetNameserversRequest struct {
|
||||||
|
// DomainName is the domain name to set the nameservers for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Namesevers is a list of the nameservers to set. Nameservers should already be set up and hosting the zone properly as some registries will verify before allowing the change.
|
||||||
|
Nameservers []string `json:"nameservers,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContactsRequest passes the contact info for each role to the SetContacts function.
|
||||||
|
type SetContactsRequest struct {
|
||||||
|
// DomainName is the domain name to set the contacts for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Contacts is the list of contacts to set.
|
||||||
|
Contacts *Contacts `json:"contacts,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableAutorenewForDomainRequest is used to pass the domain name to the EnableAutorenewForDomain function.
|
||||||
|
type EnableAutorenewForDomainRequest struct {
|
||||||
|
// DomainName is the domain name to enable autorenew for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableAutorenewForDomainRequest is used to pass the domain name to the DisableAutorenewForDomain function.
|
||||||
|
type DisableAutorenewForDomainRequest struct {
|
||||||
|
// DomainName is the domain name to disable autorenew for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LockDomainRequest is used to pass the domain name to the LockDomain function.
|
||||||
|
type LockDomainRequest struct {
|
||||||
|
// DomainName is the domain name to lock.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnlockDomainRequest is used to pass the domain name to the UnlockDomain function.
|
||||||
|
type UnlockDomainRequest struct {
|
||||||
|
// DomainName is the domain name to unlock.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmailForwarding contains all the information for an email forwarding entry.
|
||||||
|
type EmailForwarding struct {
|
||||||
|
// DomainName is the domain part of the email address to forward.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// EmailBox is the user portion of the email address to forward.
|
||||||
|
EmailBox string `json:"emailBox,omitempty"`
|
||||||
|
// EmailTo is the entire email address to forward email to.
|
||||||
|
EmailTo string `json:"emailTo,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEmailForwardingsRequest passes the domain name and pagination information to the ListEmailForwardings function.
|
||||||
|
type ListEmailForwardingsRequest struct {
|
||||||
|
// DomainName is the domain to list email forwarded boxes for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Per Page is the number of records to return per request. Per Page defaults to 1,000.
|
||||||
|
PerPage int32 `json:"perPage,omitempty"`
|
||||||
|
// Page is which page to return.
|
||||||
|
Page int32 `json:"page,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEmailForwardingsResponse returns the list of email forwarding entries as well as the pagination information.
|
||||||
|
type ListEmailForwardingsResponse struct {
|
||||||
|
// EmailForwarding is the list of forwarded email boxes.
|
||||||
|
EmailForwarding []*EmailForwarding `json:"emailForwarding,omitempty"`
|
||||||
|
// NextPage is the identifier for the next page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
NextPage int32 `json:"nextPage,omitempty"`
|
||||||
|
// LastPage is the identifier for the final page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
LastPage int32 `json:"lastPage,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEmailForwardingRequest passes the domain name and email box to request the email forwarding information for.
|
||||||
|
type GetEmailForwardingRequest struct {
|
||||||
|
// DomainName is the domain to list email forwarded box for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// EmailBox is which email box to retrieve.
|
||||||
|
EmailBox string `json:"emailBox,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteEmailForwardingRequest passes the domain name and email box to the DeleteEmailForwarding function.
|
||||||
|
type DeleteEmailForwardingRequest struct {
|
||||||
|
// DomainName is the domain to delete the email forwarded box from.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// EmailBox is which email box to delete.
|
||||||
|
EmailBox string `json:"emailBox,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HelloRequest doesn't take any parameters.
|
||||||
|
type HelloRequest struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// HelloResponse is the response from the HelloFunc command
|
||||||
|
type HelloResponse struct {
|
||||||
|
// ServerName is an identfier for which server is being accessed.
|
||||||
|
ServerName string `json:"serverName,omitempty"`
|
||||||
|
// Motd is a message of the day. It might provide some useful information.
|
||||||
|
Motd string `json:"motd,omitempty"`
|
||||||
|
// Username is the account name you are currently logged into.
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
// ServerTime is the current date/time at the server.
|
||||||
|
ServerTime string `json:"serverTime,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer contains the information related to a transfer of a domain name to Name.com.
|
||||||
|
type Transfer struct {
|
||||||
|
// DomainName is the domain to be transfered to Name.com.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Email is the email address that the approval email was sent to. Not every TLD requries an approval email. This is usaully pulled from Whois.
|
||||||
|
Email string `json:"email,omitempty"`
|
||||||
|
// Status is the current status of the transfer. Details about statuses can be found in the following Knowledge Base article: <https://www.name.com/support/articles/115012519688-Transfer-status-FAQ>.
|
||||||
|
Status string `json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListTransfersRequest passes the pagination information to the ListTransfers function.
|
||||||
|
type ListTransfersRequest struct {
|
||||||
|
// Per Page is the number of records to return per request. Per Page defaults to 1,000.
|
||||||
|
PerPage int32 `json:"perPage,omitempty"`
|
||||||
|
// Page is which page to return
|
||||||
|
Page int32 `json:"page,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListTransfersResponse returns the list of pending transfers as well as the paginiation information if relevent.
|
||||||
|
type ListTransfersResponse struct {
|
||||||
|
// Transfers is a list of pending transfers
|
||||||
|
Transfers []*Transfer `json:"transfers,omitempty"`
|
||||||
|
// NextPage is the identifier for the next page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
NextPage int32 `json:"nextPage,omitempty"`
|
||||||
|
// LastPage is the identifier for the final page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
LastPage int32 `json:"lastPage,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransferRequest passes the domain name to the GetTransfer function.
|
||||||
|
type GetTransferRequest struct {
|
||||||
|
// DomainName is the domain you want to get the transfer information for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTransferRequest passes the required transfer info to the CreateTransfer function.
|
||||||
|
type CreateTransferRequest struct {
|
||||||
|
// DomainName is the domain you want to transfer to Name.com.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// AuthCode is the authorization code for the transfer. Not all TLDs require authorization codes, but most do.
|
||||||
|
AuthCode string `json:"authCode,omitempty"`
|
||||||
|
// PrivacyEnabled is a flag on whether to purchase Whois Privacy with the transfer.
|
||||||
|
PrivacyEnabled bool `json:"privacyEnabled,omitempty"`
|
||||||
|
// PurchasePrice is the amount to pay for the transfer of the domain. If privacy_enabled is set, the regular price for Whois Privacy will be added automatically. If VAT tax applies, it will also be added automatically.
|
||||||
|
// PurchasePrice is required if the domain to transfer is a premium domain.
|
||||||
|
PurchasePrice float64 `json:"purchasePrice,omitempty"`
|
||||||
|
// PromoCode is not implemented yet
|
||||||
|
PromoCode string `json:"promoCode,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTransferResponse returns the newly created transfer resource as well as the order information.
|
||||||
|
type CreateTransferResponse struct {
|
||||||
|
// Transfer is the transfer resource created.
|
||||||
|
Transfer *Transfer `json:"transfer,omitempty"`
|
||||||
|
// Order is an identifier for this purchase.
|
||||||
|
Order int32 `json:"order,omitempty"`
|
||||||
|
// TotalPaid is the total amount paid, including VAT and Whois Privacy.
|
||||||
|
TotalPaid float64 `json:"totalPaid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelTransferRequest passes the domain name to be canceled to the CancelTransfer function.
|
||||||
|
type CancelTransferRequest struct {
|
||||||
|
// DomainName is the domain to cancel the transfer for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLForwarding is the model for URL forwarding entries.
|
||||||
|
type URLForwarding struct {
|
||||||
|
// DomainName is the domain part of the hostname to forward.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Host is the entirety of the hostname. i.e. www.example.org
|
||||||
|
Host string `json:"host,omitempty"`
|
||||||
|
// ForwardsTo is the URL this host will be forwarded to.
|
||||||
|
ForwardsTo string `json:"forwardsTo,omitempty"`
|
||||||
|
// Type is the type of forwarding. Valid types are: Masked - This retains the original domain in the address bar and will not reveal or display the actual destination URL. If you are forwarding knowledgebase.ninja to Name.com, the address bar will say knowledgebase.ninja. This is sometimes called iframe forwarding. And: Redirect - This does not retain the original domain in the address bar, so the user will see it change and realize they were forwarded from the URL they originally entered. If you are forwarding knowledgebase.ninja to Name.com, the address bar will say Name.com. This is also called 301 forwarding.
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
// Title is the title for the html page to use if the type is masked. Values are ignored for types other then "masked".
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
// Meta is the meta tags to add to the html page if the type is masked. ex: "<meta name='keywords' content='fish, denver, platte'>". Values are ignored for types other then "masked".
|
||||||
|
Meta string `json:"meta,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListURLForwardingsRequest is the request for the ListURLForwardings function.
|
||||||
|
type ListURLForwardingsRequest struct {
|
||||||
|
// DomainName is the domain to list URL forwarding entries for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Per Page is the number of records to return per request. Per Page defaults to 1,000.
|
||||||
|
PerPage int32 `json:"perPage,omitempty"`
|
||||||
|
// Page is which page to return.
|
||||||
|
Page int32 `json:"page,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListURLForwardingsResponse is the response for the ListURLForwardings function.
|
||||||
|
type ListURLForwardingsResponse struct {
|
||||||
|
// URLForwarding is the list of URL forwarding entries.
|
||||||
|
URLForwarding []*URLForwarding `json:"urlForwarding,omitempty"`
|
||||||
|
// NextPage is the identifier for the next page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
NextPage int32 `json:"nextPage,omitempty"`
|
||||||
|
// LastPage is the identifier for the final page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
LastPage int32 `json:"lastPage,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetURLForwardingRequest is the request for the GetURLForwarding function.
|
||||||
|
type GetURLForwardingRequest struct {
|
||||||
|
// DomainName is the domain to list URL forwarding entry for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Host is the part of the domain name before the domain. i.e. www is the host for www.example.org.
|
||||||
|
Host string `json:"host,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteURLForwardingRequest is the request for the DeleteURLForwarding function.
|
||||||
|
type DeleteURLForwardingRequest struct {
|
||||||
|
// DomainName is the domain to delete the URL forwardind entry from.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Host is the part of the domain name before the domain. i.e. www is the host for www.example.org.
|
||||||
|
Host string `json:"host,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VanityNameserver contains the hostname as well as the list of IP addresses for nameservers.
|
||||||
|
type VanityNameserver struct {
|
||||||
|
// DomainName is the domain the nameserver is a subdomain of.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Hostname is the hostname of the nameserver.
|
||||||
|
Hostname string `json:"hostname,omitempty"`
|
||||||
|
// IPs is a list of IP addresses that are used for glue records for this nameserver.
|
||||||
|
Ips []string `json:"ips,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListVanityNameserversRequest passes the domain name as well as the pagination parameters to the ListVanityNameservers function.
|
||||||
|
type ListVanityNameserversRequest struct {
|
||||||
|
// DomainName is the domain to list the vanity nameservers for.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Per Page is the number of records to return per request. Per Page defaults to 1,000.
|
||||||
|
PerPage int32 `json:"perPage,omitempty"`
|
||||||
|
// Page is which page to return
|
||||||
|
Page int32 `json:"page,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListVanityNameserversResponse returns the list of vanity nameservers for the domain.
|
||||||
|
type ListVanityNameserversResponse struct {
|
||||||
|
// VanityNameservers is the list of vanity nameservers.
|
||||||
|
VanityNameservers []*VanityNameserver `json:"vanityNameservers,omitempty"`
|
||||||
|
// NextPage is the identifier for the next page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
NextPage int32 `json:"nextPage,omitempty"`
|
||||||
|
// LastPage is the identifier for the final page of results. It is only populated if there is another page of results after the current page.
|
||||||
|
LastPage int32 `json:"lastPage,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVanityNameserverRequest passes the hostname to get the details for.
|
||||||
|
type GetVanityNameserverRequest struct {
|
||||||
|
// DomainName is the domain to for the vanity nameserver.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Hostname is the hostname for the vanity nameserver.
|
||||||
|
Hostname string `json:"hostname,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteVanityNameserverRequest passes which hostname to remove from the registry.
|
||||||
|
type DeleteVanityNameserverRequest struct {
|
||||||
|
// DomainName is the domain of the vanity nameserver to delete.
|
||||||
|
DomainName string `json:"domainName,omitempty"`
|
||||||
|
// Hostname is the hostname of the vanity nameserver to delete.
|
||||||
|
Hostname string `json:"hostname,omitempty"`
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
package namecom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = bytes.MinRead
|
||||||
|
|
||||||
|
// ListTransfers lists all pending transfer in requests. To get the information related to a non-pending transfer, you can use the GetTransfer function for that.
|
||||||
|
func (n *NameCom) ListTransfers(request *ListTransfersRequest) (*ListTransfersResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/transfers")
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
if request.PerPage != 0 {
|
||||||
|
values.Set("perPage", fmt.Sprintf("%d", request.PerPage))
|
||||||
|
}
|
||||||
|
if request.Page != 0 {
|
||||||
|
values.Set("page", fmt.Sprintf("%d", request.Page))
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &ListTransfersResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransfer gets details for a transfer request.
|
||||||
|
func (n *NameCom) GetTransfer(request *GetTransferRequest) (*Transfer, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/transfers/%s", request.DomainName)
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Transfer{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTransfer purchases a new domain transfer request.
|
||||||
|
func (n *NameCom) CreateTransfer(request *CreateTransferRequest) (*CreateTransferResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/transfers")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &CreateTransferResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelTransfer cancels a pending transfer request and refunds the amount to account credit.
|
||||||
|
func (n *NameCom) CancelTransfer(request *CancelTransferRequest) (*Transfer, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/transfers")
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &Transfer{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
package namecom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = bytes.MinRead
|
||||||
|
|
||||||
|
// ListURLForwardings returns a pagenated list of URL forwarding entries for a domain.
|
||||||
|
func (n *NameCom) ListURLForwardings(request *ListURLForwardingsRequest) (*ListURLForwardingsResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/url/forwarding", request.DomainName)
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
if request.PerPage != 0 {
|
||||||
|
values.Set("perPage", fmt.Sprintf("%d", request.PerPage))
|
||||||
|
}
|
||||||
|
if request.Page != 0 {
|
||||||
|
values.Set("page", fmt.Sprintf("%d", request.Page))
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &ListURLForwardingsResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetURLForwarding returns an URL forwarding entry.
|
||||||
|
func (n *NameCom) GetURLForwarding(request *GetURLForwardingRequest) (*URLForwarding, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/url/forwarding/%s", request.DomainName, request.Host)
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &URLForwarding{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateURLForwarding creates an URL forwarding entry. If this is the first URL forwarding entry, it may modify the A records for the domain accordingly.
|
||||||
|
func (n *NameCom) CreateURLForwarding(request *URLForwarding) (*URLForwarding, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/url/forwarding", request.DomainName)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &URLForwarding{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateURLForwarding updates which URL the host is being forwarded to.
|
||||||
|
func (n *NameCom) UpdateURLForwarding(request *URLForwarding) (*URLForwarding, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/url/forwarding/%s", request.DomainName, request.Host)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.put(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &URLForwarding{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteURLForwarding deletes the URL forwarding entry.
|
||||||
|
func (n *NameCom) DeleteURLForwarding(request *DeleteURLForwardingRequest) (*EmptyResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/url/forwarding/%s", request.DomainName, request.Host)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.delete(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &EmptyResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
package namecom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = bytes.MinRead
|
||||||
|
|
||||||
|
// ListVanityNameservers lists all nameservers registered with the registry. It omits the IP addresses from the response. Those can be found from calling GetVanityNameserver.
|
||||||
|
func (n *NameCom) ListVanityNameservers(request *ListVanityNameserversRequest) (*ListVanityNameserversResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/vanity_nameservers", request.DomainName)
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
if request.PerPage != 0 {
|
||||||
|
values.Set("perPage", fmt.Sprintf("%d", request.PerPage))
|
||||||
|
}
|
||||||
|
if request.Page != 0 {
|
||||||
|
values.Set("page", fmt.Sprintf("%d", request.Page))
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &ListVanityNameserversResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVanityNameserver gets the details for a vanity nameserver registered with the registry.
|
||||||
|
func (n *NameCom) GetVanityNameserver(request *GetVanityNameserverRequest) (*VanityNameserver, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/vanity_nameservers/%s", request.DomainName, request.Hostname)
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
|
||||||
|
body, err := n.get(endpoint, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &VanityNameserver{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateVanityNameserver registers a nameserver with the registry.
|
||||||
|
func (n *NameCom) CreateVanityNameserver(request *VanityNameserver) (*VanityNameserver, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/vanity_nameservers", request.DomainName)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.post(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &VanityNameserver{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateVanityNameserver allows you to update the glue record IP addresses at the registry.
|
||||||
|
func (n *NameCom) UpdateVanityNameserver(request *VanityNameserver) (*VanityNameserver, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/vanity_nameservers/%s", request.DomainName, request.Hostname)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.put(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &VanityNameserver{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteVanityNameserver unregisteres the nameserver at the registry. This might fail if the registry believes the nameserver is in use.
|
||||||
|
func (n *NameCom) DeleteVanityNameserver(request *DeleteVanityNameserverRequest) (*EmptyResponse, error) {
|
||||||
|
endpoint := fmt.Sprintf("/v4/domains/%s/vanity_nameservers/%s", request.DomainName, request.Hostname)
|
||||||
|
|
||||||
|
post := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(post).Encode(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := n.delete(endpoint, post)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &EmptyResponse{}
|
||||||
|
|
||||||
|
err = json.NewDecoder(body).Decode(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
||||||
|
*.prof
|
|
@ -0,0 +1,10 @@
|
||||||
|
language: go
|
||||||
|
go_import_path: github.com/pkg/errors
|
||||||
|
go:
|
||||||
|
- 1.11.x
|
||||||
|
- 1.12.x
|
||||||
|
- 1.13.x
|
||||||
|
- tip
|
||||||
|
|
||||||
|
script:
|
||||||
|
- make check
|
|
@ -0,0 +1,23 @@
|
||||||
|
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,44 @@
|
||||||
|
PKGS := github.com/pkg/errors
|
||||||
|
SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS))
|
||||||
|
GO := go
|
||||||
|
|
||||||
|
check: test vet gofmt misspell unconvert staticcheck ineffassign unparam
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(GO) test $(PKGS)
|
||||||
|
|
||||||
|
vet: | test
|
||||||
|
$(GO) vet $(PKGS)
|
||||||
|
|
||||||
|
staticcheck:
|
||||||
|
$(GO) get honnef.co/go/tools/cmd/staticcheck
|
||||||
|
staticcheck -checks all $(PKGS)
|
||||||
|
|
||||||
|
misspell:
|
||||||
|
$(GO) get github.com/client9/misspell/cmd/misspell
|
||||||
|
misspell \
|
||||||
|
-locale GB \
|
||||||
|
-error \
|
||||||
|
*.md *.go
|
||||||
|
|
||||||
|
unconvert:
|
||||||
|
$(GO) get github.com/mdempsky/unconvert
|
||||||
|
unconvert -v $(PKGS)
|
||||||
|
|
||||||
|
ineffassign:
|
||||||
|
$(GO) get github.com/gordonklaus/ineffassign
|
||||||
|
find $(SRCDIRS) -name '*.go' | xargs ineffassign
|
||||||
|
|
||||||
|
pedantic: check errcheck
|
||||||
|
|
||||||
|
unparam:
|
||||||
|
$(GO) get mvdan.cc/unparam
|
||||||
|
unparam ./...
|
||||||
|
|
||||||
|
errcheck:
|
||||||
|
$(GO) get github.com/kisielk/errcheck
|
||||||
|
errcheck $(PKGS)
|
||||||
|
|
||||||
|
gofmt:
|
||||||
|
@echo Checking code is gofmted
|
||||||
|
@test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)"
|
|
@ -0,0 +1,59 @@
|
||||||
|
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge)
|
||||||
|
|
||||||
|
Package errors provides simple error handling primitives.
|
||||||
|
|
||||||
|
`go get github.com/pkg/errors`
|
||||||
|
|
||||||
|
The traditional error handling idiom in Go is roughly akin to
|
||||||
|
```go
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
```
|
||||||
|
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
|
||||||
|
|
||||||
|
## Adding context to an error
|
||||||
|
|
||||||
|
The errors.Wrap function returns a new error that adds context to the original error. For example
|
||||||
|
```go
|
||||||
|
_, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "read failed")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Retrieving the cause of an error
|
||||||
|
|
||||||
|
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
|
||||||
|
```go
|
||||||
|
type causer interface {
|
||||||
|
Cause() error
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
|
||||||
|
```go
|
||||||
|
switch err := errors.Cause(err).(type) {
|
||||||
|
case *MyError:
|
||||||
|
// handle specifically
|
||||||
|
default:
|
||||||
|
// unknown error
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows:
|
||||||
|
|
||||||
|
- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible)
|
||||||
|
- 1.0. Final release.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports.
|
||||||
|
|
||||||
|
Before sending a PR, please discuss your change by raising an issue.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
BSD-2-Clause
|
|
@ -0,0 +1,32 @@
|
||||||
|
version: build-{build}.{branch}
|
||||||
|
|
||||||
|
clone_folder: C:\gopath\src\github.com\pkg\errors
|
||||||
|
shallow_clone: true # for startup speed
|
||||||
|
|
||||||
|
environment:
|
||||||
|
GOPATH: C:\gopath
|
||||||
|
|
||||||
|
platform:
|
||||||
|
- x64
|
||||||
|
|
||||||
|
# http://www.appveyor.com/docs/installed-software
|
||||||
|
install:
|
||||||
|
# some helpful output for debugging builds
|
||||||
|
- go version
|
||||||
|
- go env
|
||||||
|
# pre-installed MinGW at C:\MinGW is 32bit only
|
||||||
|
# but MSYS2 at C:\msys64 has mingw64
|
||||||
|
- set PATH=C:\msys64\mingw64\bin;%PATH%
|
||||||
|
- gcc --version
|
||||||
|
- g++ --version
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- go install -v ./...
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- set PATH=C:\gopath\bin;%PATH%
|
||||||
|
- go test -v ./...
|
||||||
|
|
||||||
|
#artifacts:
|
||||||
|
# - path: '%GOPATH%\bin\*.exe'
|
||||||
|
deploy: off
|
|
@ -0,0 +1,288 @@
|
||||||
|
// Package errors provides simple error handling primitives.
|
||||||
|
//
|
||||||
|
// The traditional error handling idiom in Go is roughly akin to
|
||||||
|
//
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// which when applied recursively up the call stack results in error reports
|
||||||
|
// without context or debugging information. The errors package allows
|
||||||
|
// programmers to add context to the failure path in their code in a way
|
||||||
|
// that does not destroy the original value of the error.
|
||||||
|
//
|
||||||
|
// Adding context to an error
|
||||||
|
//
|
||||||
|
// The errors.Wrap function returns a new error that adds context to the
|
||||||
|
// original error by recording a stack trace at the point Wrap is called,
|
||||||
|
// together with the supplied message. For example
|
||||||
|
//
|
||||||
|
// _, err := ioutil.ReadAll(r)
|
||||||
|
// if err != nil {
|
||||||
|
// return errors.Wrap(err, "read failed")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If additional control is required, the errors.WithStack and
|
||||||
|
// errors.WithMessage functions destructure errors.Wrap into its component
|
||||||
|
// operations: annotating an error with a stack trace and with a message,
|
||||||
|
// respectively.
|
||||||
|
//
|
||||||
|
// Retrieving the cause of an error
|
||||||
|
//
|
||||||
|
// Using errors.Wrap constructs a stack of errors, adding context to the
|
||||||
|
// preceding error. Depending on the nature of the error it may be necessary
|
||||||
|
// to reverse the operation of errors.Wrap to retrieve the original error
|
||||||
|
// for inspection. Any error value which implements this interface
|
||||||
|
//
|
||||||
|
// type causer interface {
|
||||||
|
// Cause() error
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
||||||
|
// the topmost error that does not implement causer, which is assumed to be
|
||||||
|
// the original cause. For example:
|
||||||
|
//
|
||||||
|
// switch err := errors.Cause(err).(type) {
|
||||||
|
// case *MyError:
|
||||||
|
// // handle specifically
|
||||||
|
// default:
|
||||||
|
// // unknown error
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Although the causer interface is not exported by this package, it is
|
||||||
|
// considered a part of its stable public interface.
|
||||||
|
//
|
||||||
|
// Formatted printing of errors
|
||||||
|
//
|
||||||
|
// All error values returned from this package implement fmt.Formatter and can
|
||||||
|
// be formatted by the fmt package. The following verbs are supported:
|
||||||
|
//
|
||||||
|
// %s print the error. If the error has a Cause it will be
|
||||||
|
// printed recursively.
|
||||||
|
// %v see %s
|
||||||
|
// %+v extended format. Each Frame of the error's StackTrace will
|
||||||
|
// be printed in detail.
|
||||||
|
//
|
||||||
|
// Retrieving the stack trace of an error or wrapper
|
||||||
|
//
|
||||||
|
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
||||||
|
// invoked. This information can be retrieved with the following interface:
|
||||||
|
//
|
||||||
|
// type stackTracer interface {
|
||||||
|
// StackTrace() errors.StackTrace
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The returned errors.StackTrace type is defined as
|
||||||
|
//
|
||||||
|
// type StackTrace []Frame
|
||||||
|
//
|
||||||
|
// The Frame type represents a call site in the stack trace. Frame supports
|
||||||
|
// the fmt.Formatter interface that can be used for printing information about
|
||||||
|
// the stack trace of this error. For example:
|
||||||
|
//
|
||||||
|
// if err, ok := err.(stackTracer); ok {
|
||||||
|
// for _, f := range err.StackTrace() {
|
||||||
|
// fmt.Printf("%+s:%d\n", f, f)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Although the stackTracer interface is not exported by this package, it is
|
||||||
|
// considered a part of its stable public interface.
|
||||||
|
//
|
||||||
|
// See the documentation for Frame.Format for more details.
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// New returns an error with the supplied message.
|
||||||
|
// New also records the stack trace at the point it was called.
|
||||||
|
func New(message string) error {
|
||||||
|
return &fundamental{
|
||||||
|
msg: message,
|
||||||
|
stack: callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf formats according to a format specifier and returns the string
|
||||||
|
// as a value that satisfies error.
|
||||||
|
// Errorf also records the stack trace at the point it was called.
|
||||||
|
func Errorf(format string, args ...interface{}) error {
|
||||||
|
return &fundamental{
|
||||||
|
msg: fmt.Sprintf(format, args...),
|
||||||
|
stack: callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fundamental is an error that has a message and a stack, but no caller.
|
||||||
|
type fundamental struct {
|
||||||
|
msg string
|
||||||
|
*stack
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fundamental) Error() string { return f.msg }
|
||||||
|
|
||||||
|
func (f *fundamental) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
if s.Flag('+') {
|
||||||
|
io.WriteString(s, f.msg)
|
||||||
|
f.stack.Format(s, verb)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 's':
|
||||||
|
io.WriteString(s, f.msg)
|
||||||
|
case 'q':
|
||||||
|
fmt.Fprintf(s, "%q", f.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithStack annotates err with a stack trace at the point WithStack was called.
|
||||||
|
// If err is nil, WithStack returns nil.
|
||||||
|
func WithStack(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &withStack{
|
||||||
|
err,
|
||||||
|
callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type withStack struct {
|
||||||
|
error
|
||||||
|
*stack
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *withStack) Cause() error { return w.error }
|
||||||
|
|
||||||
|
// Unwrap provides compatibility for Go 1.13 error chains.
|
||||||
|
func (w *withStack) Unwrap() error { return w.error }
|
||||||
|
|
||||||
|
func (w *withStack) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
if s.Flag('+') {
|
||||||
|
fmt.Fprintf(s, "%+v", w.Cause())
|
||||||
|
w.stack.Format(s, verb)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 's':
|
||||||
|
io.WriteString(s, w.Error())
|
||||||
|
case 'q':
|
||||||
|
fmt.Fprintf(s, "%q", w.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap returns an error annotating err with a stack trace
|
||||||
|
// at the point Wrap is called, and the supplied message.
|
||||||
|
// If err is nil, Wrap returns nil.
|
||||||
|
func Wrap(err error, message string) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: message,
|
||||||
|
}
|
||||||
|
return &withStack{
|
||||||
|
err,
|
||||||
|
callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapf returns an error annotating err with a stack trace
|
||||||
|
// at the point Wrapf is called, and the format specifier.
|
||||||
|
// If err is nil, Wrapf returns nil.
|
||||||
|
func Wrapf(err error, format string, args ...interface{}) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: fmt.Sprintf(format, args...),
|
||||||
|
}
|
||||||
|
return &withStack{
|
||||||
|
err,
|
||||||
|
callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMessage annotates err with a new message.
|
||||||
|
// If err is nil, WithMessage returns nil.
|
||||||
|
func WithMessage(err error, message string) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMessagef annotates err with the format specifier.
|
||||||
|
// If err is nil, WithMessagef returns nil.
|
||||||
|
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: fmt.Sprintf(format, args...),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type withMessage struct {
|
||||||
|
cause error
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
|
||||||
|
func (w *withMessage) Cause() error { return w.cause }
|
||||||
|
|
||||||
|
// Unwrap provides compatibility for Go 1.13 error chains.
|
||||||
|
func (w *withMessage) Unwrap() error { return w.cause }
|
||||||
|
|
||||||
|
func (w *withMessage) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
if s.Flag('+') {
|
||||||
|
fmt.Fprintf(s, "%+v\n", w.Cause())
|
||||||
|
io.WriteString(s, w.msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 's', 'q':
|
||||||
|
io.WriteString(s, w.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cause returns the underlying cause of the error, if possible.
|
||||||
|
// An error value has a cause if it implements the following
|
||||||
|
// interface:
|
||||||
|
//
|
||||||
|
// type causer interface {
|
||||||
|
// Cause() error
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If the error does not implement Cause, the original error will
|
||||||
|
// be returned. If the error is nil, nil will be returned without further
|
||||||
|
// investigation.
|
||||||
|
func Cause(err error) error {
|
||||||
|
type causer interface {
|
||||||
|
Cause() error
|
||||||
|
}
|
||||||
|
|
||||||
|
for err != nil {
|
||||||
|
cause, ok := err.(causer)
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err = cause.Cause()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
// +build go1.13
|
||||||
|
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
stderrors "errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Is reports whether any error in err's chain matches target.
|
||||||
|
//
|
||||||
|
// The chain consists of err itself followed by the sequence of errors obtained by
|
||||||
|
// repeatedly calling Unwrap.
|
||||||
|
//
|
||||||
|
// An error is considered to match a target if it is equal to that target or if
|
||||||
|
// it implements a method Is(error) bool such that Is(target) returns true.
|
||||||
|
func Is(err, target error) bool { return stderrors.Is(err, target) }
|
||||||
|
|
||||||
|
// As finds the first error in err's chain that matches target, and if so, sets
|
||||||
|
// target to that error value and returns true.
|
||||||
|
//
|
||||||
|
// The chain consists of err itself followed by the sequence of errors obtained by
|
||||||
|
// repeatedly calling Unwrap.
|
||||||
|
//
|
||||||
|
// An error matches target if the error's concrete value is assignable to the value
|
||||||
|
// pointed to by target, or if the error has a method As(interface{}) bool such that
|
||||||
|
// As(target) returns true. In the latter case, the As method is responsible for
|
||||||
|
// setting target.
|
||||||
|
//
|
||||||
|
// As will panic if target is not a non-nil pointer to either a type that implements
|
||||||
|
// error, or to any interface type. As returns false if err is nil.
|
||||||
|
func As(err error, target interface{}) bool { return stderrors.As(err, target) }
|
||||||
|
|
||||||
|
// Unwrap returns the result of calling the Unwrap method on err, if err's
|
||||||
|
// type contains an Unwrap method returning error.
|
||||||
|
// Otherwise, Unwrap returns nil.
|
||||||
|
func Unwrap(err error) error {
|
||||||
|
return stderrors.Unwrap(err)
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"path"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Frame represents a program counter inside a stack frame.
|
||||||
|
// For historical reasons if Frame is interpreted as a uintptr
|
||||||
|
// its value represents the program counter + 1.
|
||||||
|
type Frame uintptr
|
||||||
|
|
||||||
|
// pc returns the program counter for this frame;
|
||||||
|
// multiple frames may have the same PC value.
|
||||||
|
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
|
||||||
|
|
||||||
|
// file returns the full path to the file that contains the
|
||||||
|
// function for this Frame's pc.
|
||||||
|
func (f Frame) file() string {
|
||||||
|
fn := runtime.FuncForPC(f.pc())
|
||||||
|
if fn == nil {
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
file, _ := fn.FileLine(f.pc())
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
// line returns the line number of source code of the
|
||||||
|
// function for this Frame's pc.
|
||||||
|
func (f Frame) line() int {
|
||||||
|
fn := runtime.FuncForPC(f.pc())
|
||||||
|
if fn == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
_, line := fn.FileLine(f.pc())
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|
||||||
|
// name returns the name of this function, if known.
|
||||||
|
func (f Frame) name() string {
|
||||||
|
fn := runtime.FuncForPC(f.pc())
|
||||||
|
if fn == nil {
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
return fn.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format formats the frame according to the fmt.Formatter interface.
|
||||||
|
//
|
||||||
|
// %s source file
|
||||||
|
// %d source line
|
||||||
|
// %n function name
|
||||||
|
// %v equivalent to %s:%d
|
||||||
|
//
|
||||||
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||||
|
//
|
||||||
|
// %+s function name and path of source file relative to the compile time
|
||||||
|
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
||||||
|
// %+v equivalent to %+s:%d
|
||||||
|
func (f Frame) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 's':
|
||||||
|
switch {
|
||||||
|
case s.Flag('+'):
|
||||||
|
io.WriteString(s, f.name())
|
||||||
|
io.WriteString(s, "\n\t")
|
||||||
|
io.WriteString(s, f.file())
|
||||||
|
default:
|
||||||
|
io.WriteString(s, path.Base(f.file()))
|
||||||
|
}
|
||||||
|
case 'd':
|
||||||
|
io.WriteString(s, strconv.Itoa(f.line()))
|
||||||
|
case 'n':
|
||||||
|
io.WriteString(s, funcname(f.name()))
|
||||||
|
case 'v':
|
||||||
|
f.Format(s, 's')
|
||||||
|
io.WriteString(s, ":")
|
||||||
|
f.Format(s, 'd')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText formats a stacktrace Frame as a text string. The output is the
|
||||||
|
// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
|
||||||
|
func (f Frame) MarshalText() ([]byte, error) {
|
||||||
|
name := f.name()
|
||||||
|
if name == "unknown" {
|
||||||
|
return []byte(name), nil
|
||||||
|
}
|
||||||
|
return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
||||||
|
type StackTrace []Frame
|
||||||
|
|
||||||
|
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
||||||
|
//
|
||||||
|
// %s lists source files for each Frame in the stack
|
||||||
|
// %v lists the source file and line number for each Frame in the stack
|
||||||
|
//
|
||||||
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||||
|
//
|
||||||
|
// %+v Prints filename, function, and line number for each Frame in the stack.
|
||||||
|
func (st StackTrace) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
switch {
|
||||||
|
case s.Flag('+'):
|
||||||
|
for _, f := range st {
|
||||||
|
io.WriteString(s, "\n")
|
||||||
|
f.Format(s, verb)
|
||||||
|
}
|
||||||
|
case s.Flag('#'):
|
||||||
|
fmt.Fprintf(s, "%#v", []Frame(st))
|
||||||
|
default:
|
||||||
|
st.formatSlice(s, verb)
|
||||||
|
}
|
||||||
|
case 's':
|
||||||
|
st.formatSlice(s, verb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatSlice will format this StackTrace into the given buffer as a slice of
|
||||||
|
// Frame, only valid when called with '%s' or '%v'.
|
||||||
|
func (st StackTrace) formatSlice(s fmt.State, verb rune) {
|
||||||
|
io.WriteString(s, "[")
|
||||||
|
for i, f := range st {
|
||||||
|
if i > 0 {
|
||||||
|
io.WriteString(s, " ")
|
||||||
|
}
|
||||||
|
f.Format(s, verb)
|
||||||
|
}
|
||||||
|
io.WriteString(s, "]")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stack represents a stack of program counters.
|
||||||
|
type stack []uintptr
|
||||||
|
|
||||||
|
func (s *stack) Format(st fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
switch {
|
||||||
|
case st.Flag('+'):
|
||||||
|
for _, pc := range *s {
|
||||||
|
f := Frame(pc)
|
||||||
|
fmt.Fprintf(st, "\n%+v", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stack) StackTrace() StackTrace {
|
||||||
|
f := make([]Frame, len(*s))
|
||||||
|
for i := 0; i < len(f); i++ {
|
||||||
|
f[i] = Frame((*s)[i])
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func callers() *stack {
|
||||||
|
const depth = 32
|
||||||
|
var pcs [depth]uintptr
|
||||||
|
n := runtime.Callers(3, pcs[:])
|
||||||
|
var st stack = pcs[0:n]
|
||||||
|
return &st
|
||||||
|
}
|
||||||
|
|
||||||
|
// funcname removes the path prefix component of a function's name reported by func.Name().
|
||||||
|
func funcname(name string) string {
|
||||||
|
i := strings.LastIndex(name, "/")
|
||||||
|
name = name[i+1:]
|
||||||
|
i = strings.Index(name, ".")
|
||||||
|
return name[i+1:]
|
||||||
|
}
|
Loading…
Reference in New Issue