From 2d88d813925d1a6f926550c4d2865b214d282334 Mon Sep 17 00:00:00 2001 From: Anton Yurchenko Date: Mon, 27 Jan 2020 20:25:20 +0700 Subject: [PATCH] NEW PROVIDER: Internet.bs (#590) * Ineternet.bs: first version of provider * Ineternet.bs: code and documentation cleanup --- OWNERS | 1 + README.md | 1 + docs/_providers/internetbs.md | 40 ++++++++++ docs/provider-list.md | 1 + providers/_all/all.go | 1 + providers/internetbs/api.go | 88 ++++++++++++++++++++++ providers/internetbs/internetbsProvider.go | 64 ++++++++++++++++ 7 files changed, 196 insertions(+) create mode 100644 docs/_providers/internetbs.md create mode 100644 providers/internetbs/api.go create mode 100644 providers/internetbs/internetbsProvider.go diff --git a/OWNERS b/OWNERS index 2d45d946f..7a9af02a0 100644 --- a/OWNERS +++ b/OWNERS @@ -8,6 +8,7 @@ providers/dnsimple @aeden providers/gandi @TomOnTime # providers/gcloud providers/hexonet @papakai +providers/internetbs @pragmaton providers/linode @koesie10 providers/namecheap @captncraig # providers/namedotcom diff --git a/README.md b/README.md index efc56a0b8..1afff2f17 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Currently supported DNS providers: - Gandi - Google - HEXONET + - Internet.bs - Linode - Namecheap - Name.com diff --git a/docs/_providers/internetbs.md b/docs/_providers/internetbs.md new file mode 100644 index 000000000..e3e299c41 --- /dev/null +++ b/docs/_providers/internetbs.md @@ -0,0 +1,40 @@ +--- +name: Internet.bs +title: Internet.bs Provider +layout: default +jsId: INTERNETBS +--- +# Internet.bs Provider + +DNSControl's Internet.bs provider supports being a Registrar. Support for being a DNS Provider is not included, but could be added in the future. + +## Configuration +In your credentials file, you must provide your API key and account password + +{% highlight json %} +{ + "internetbs": { + "api-key": "your-api-key", + "password": "account-password" + } +} +{% endhighlight %} + +## Metadata +This provider does not recognize any special metadata fields unique to Internet.bs. + +## Usage +Example Javascript: + +{% highlight js %} +var REG_INTERNETBS = NewRegistrar('internetbs', 'INTERNETBS'); +var GCLOUD = NewDnsProvider("gcloud", "GCLOUD"); // Any provider + +D("example.tld", REG_INTERNETBS, DnsProvider(GCLOUD), + A("test","1.2.3.4") +); +{% endhighlight %} + +## Activation + +Pay attention, you need to define white list of IP for API. But you always can change it on `My Profile > Reseller Settings` diff --git a/docs/provider-list.md b/docs/provider-list.md index 8b89895d9..e9e98c62d 100644 --- a/docs/provider-list.md +++ b/docs/provider-list.md @@ -66,6 +66,7 @@ Maintainers of contributed providers: * dnsimple @aeden * gandi @TomOnTime * HEXONET @papakai +* Internet.bs @pragmaton * Linode @koesie10 * namecheap @captncraig * ns1 @captncraig diff --git a/providers/_all/all.go b/providers/_all/all.go index 4380cf288..885231dc8 100644 --- a/providers/_all/all.go +++ b/providers/_all/all.go @@ -15,6 +15,7 @@ import ( _ "github.com/StackExchange/dnscontrol/providers/gandi_v5" _ "github.com/StackExchange/dnscontrol/providers/gcloud" _ "github.com/StackExchange/dnscontrol/providers/hexonet" + _ "github.com/StackExchange/dnscontrol/providers/internetbs" _ "github.com/StackExchange/dnscontrol/providers/linode" _ "github.com/StackExchange/dnscontrol/providers/namecheap" _ "github.com/StackExchange/dnscontrol/providers/namedotcom" diff --git a/providers/internetbs/api.go b/providers/internetbs/api.go new file mode 100644 index 000000000..3c9d6fb90 --- /dev/null +++ b/providers/internetbs/api.go @@ -0,0 +1,88 @@ +package internetbs + +import ( + "encoding/json" + "github.com/pkg/errors" + "io/ioutil" + "net/http" + "strings" +) + +// Api layer for Internet.bs + +type api struct { + key string + password string +} + +type requestParams map[string]string + +type errorResponse struct { + TransactID string `json:"transactid"` + Status string `json:"status"` + Message string `json:"message,omitempty"` + Code uint `json:"code,omitempty"` +} + +type domainRecord struct { + Nameserver []string `json:"nameserver"` +} + +func (c *api) getNameservers(domain string) ([]string, error) { + var bodyString, err = c.get("/Domain/Info", requestParams{"Domain": domain}) + if err != nil { + return []string{}, errors.Errorf("Error fetching nameservers list from Internet.bs: %s", err) + } + var dr domainRecord + json.Unmarshal(bodyString, &dr) + ns := []string{} + for _, nameserver := range dr.Nameserver { + ns = append(ns, nameserver) + } + return ns, nil +} + +func (c *api) updateNameservers(ns []string, domain string) error { + rec := requestParams{} + rec["Domain"] = domain + rec["Ns_list"] = strings.Join(ns, ",") + if _, err := c.get("/Domain/Update", rec); err != nil { + return errors.Errorf("Internet.ns: Error update NS : %s", err) + } + return nil +} + +func (c *api) get(endpoint string, params requestParams) ([]byte, error) { + client := &http.Client{} + req, _ := http.NewRequest("GET", "https://api.internet.bs/"+endpoint, nil) + q := req.URL.Query() + + // Add auth params + q.Add("ApiKey", c.key) + q.Add("Password", c.password) + q.Add("ResponseFormat", "JSON") + + for pName, pValue := range params { + q.Add(pName, pValue) + } + + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + return []byte{}, err + } + + bodyString, _ := ioutil.ReadAll(resp.Body) + + // Got error from API ? + var errResp errorResponse + err = json.Unmarshal(bodyString, &errResp) + if errResp.Status == "FAILURE" { + return bodyString, errors.Errorf("Internet.bs API error: %s code: %d transactid: %s URL:%s%s ", + errResp.Message, errResp.Code, errResp.TransactID, + req.Host, req.URL.RequestURI()) + } + + return bodyString, nil +} diff --git a/providers/internetbs/internetbsProvider.go b/providers/internetbs/internetbsProvider.go new file mode 100644 index 000000000..1194407bd --- /dev/null +++ b/providers/internetbs/internetbsProvider.go @@ -0,0 +1,64 @@ +package internetbs + +import ( + "fmt" + "github.com/StackExchange/dnscontrol/models" + "github.com/StackExchange/dnscontrol/providers" + "github.com/pkg/errors" + "sort" + "strings" +) + +/* + +Internet.bs Registrator: + +Info required in `creds.json`: + - api-key ApiKey + - password Your account password + +*/ + +func init() { + providers.RegisterRegistrarType("INTERNETBS", newInternetBs) +} + +func newInternetBs(m map[string]string) (providers.Registrar, error) { + api := &api{} + + api.key, api.password = m["api-key"], m["password"] + if api.key == "" || api.password == "" { + return nil, errors.Errorf("missing Internet.bs api-key and password") + } + + return api, nil +} + +// GetRegistrarCorrections gathers corrections that would being n to match dc. +func (c *api) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { + nss, err := c.getNameservers(dc.Name) + if err != nil { + return nil, err + } + foundNameservers := strings.Join(nss, ",") + + expected := []string{} + for _, ns := range dc.Nameservers { + name := strings.TrimRight(ns.Name, ".") + expected = append(expected, name) + } + sort.Strings(expected) + expectedNameservers := strings.Join(expected, ",") + + if foundNameservers != expectedNameservers { + return []*models.Correction{ + { + Msg: fmt.Sprintf("Update nameservers (%s) -> (%s)", foundNameservers, expectedNameservers), + F: func() error { + return c.updateNameservers(expected, dc.Name) + }, + }, + }, nil + } + return nil, nil +}