mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-09-20 06:46:19 +08:00
New provider: INWX (#808)
* adds initial support for INWX * adds all features to the INWX provider * allows domain for tests in creds.json for INWX * runs go generate to update docs for INWX * fixes formatting with gofmt * changes goinwx to github.com/nrdcg/goinwx v0.8.0 * simplifies inwx sandbox check * changes inwx unknown key error to a warning * adds models.PostProcessRecords for inwx records * replaces strings.TrimRight with [:-1] to remove final dot for inwx * adds a comment about the domain creds.json key for the inwx provider * removes warning for invalid creds.json keys in the inwx provider * adds TOTP calculation support for inwx * adds comments to inwxProvider * improves INWX error messages * adds additional documentation about the TOTP support for INWX * adds inwx documentation * bumps goinwx to 0.8.1 to fix the inwx API
This commit is contained in:
parent
889ed75668
commit
f88c60a8f3
1
OWNERS
1
OWNERS
|
@ -11,6 +11,7 @@ providers/gandi_v5 @TomOnTime
|
|||
# providers/gcloud
|
||||
providers/hexonet @papakai
|
||||
providers/internetbs @pragmaton
|
||||
providers/inwx @svenpeter42
|
||||
providers/linode @koesie10
|
||||
providers/namecheap @captncraig
|
||||
# providers/namedotcom
|
||||
|
|
|
@ -29,6 +29,7 @@ Currently supported DNS providers:
|
|||
- Google DNS
|
||||
- HEXONET
|
||||
- Internet.bs
|
||||
- INWX
|
||||
- Linode
|
||||
- NS1
|
||||
- Name.com
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<th class="rotate"><div><span>GCLOUD</span></div></th>
|
||||
<th class="rotate"><div><span>HEXONET</span></div></th>
|
||||
<th class="rotate"><div><span>INTERNETBS</span></div></th>
|
||||
<th class="rotate"><div><span>INWX</span></div></th>
|
||||
<th class="rotate"><div><span>LINODE</span></div></th>
|
||||
<th class="rotate"><div><span>NAMECHEAP</span></div></th>
|
||||
<th class="rotate"><div><span>NAMEDOTCOM</span></div></th>
|
||||
|
@ -85,6 +86,9 @@
|
|||
<td class="danger">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td class="danger">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
|
@ -178,6 +182,9 @@
|
|||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td class="danger">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
</td>
|
||||
|
@ -241,6 +248,9 @@
|
|||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td class="danger">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
</td>
|
||||
|
@ -312,6 +322,9 @@
|
|||
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="INWX does not support the ALIAS or ANAME record type.">
|
||||
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="danger">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
|
@ -363,6 +376,9 @@
|
|||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="info" data-toggle="tooltip" data-container="body" data-placement="top" title="Supported by INWX but not implemented yet.">
|
||||
<i class="fa fa-circle-o text-info" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
|
@ -420,6 +436,9 @@
|
|||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
|
@ -485,6 +504,9 @@
|
|||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="success" data-toggle="tooltip" data-container="body" data-placement="top" title="PTR records with empty targets are not supported">
|
||||
<i class="fa has-tooltip fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="danger">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
|
@ -540,6 +562,9 @@
|
|||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
|
@ -595,6 +620,9 @@
|
|||
<i class="fa has-tooltip fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="success" data-toggle="tooltip" data-container="body" data-placement="top" title="SRV records with empty targets are not supported.">
|
||||
<i class="fa has-tooltip fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="The namecheap web console allows you to make SRV records, but their api does not let you read or set them">
|
||||
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||
|
@ -662,6 +690,9 @@
|
|||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
|
@ -717,6 +748,9 @@
|
|||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="danger">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
|
@ -768,6 +802,9 @@
|
|||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="INWX only supports a single entry for TXT records">
|
||||
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="danger">
|
||||
|
@ -816,6 +853,7 @@
|
|||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
|
@ -840,6 +878,9 @@
|
|||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="danger">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
|
@ -877,6 +918,9 @@
|
|||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="info" data-toggle="tooltip" data-container="body" data-placement="top" title="DS records are only supported at the apex and require a different API call that hasn't been implemented yet.">
|
||||
<i class="fa fa-circle-o text-info" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
|
@ -928,6 +972,9 @@
|
|||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td class="danger">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
</td>
|
||||
|
@ -1001,6 +1048,9 @@
|
|||
<td class="danger">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td class="info" data-toggle="tooltip" data-container="body" data-placement="top" title="Supported by INWX but not implemented yet.">
|
||||
<i class="fa fa-circle-o text-info" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td class="danger">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
</td>
|
||||
|
@ -1085,6 +1135,9 @@
|
|||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td class="danger">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
</td>
|
||||
|
@ -1161,6 +1214,9 @@
|
|||
<i class="fa fa-circle-o text-info" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><i class="fa fa-minus dim"></i></td>
|
||||
<td class="success">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td class="info">
|
||||
<i class="fa fa-circle-o text-info" aria-hidden="true"></i>
|
||||
</td>
|
||||
|
|
99
docs/_providers/inwx.md
Normal file
99
docs/_providers/inwx.md
Normal file
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
name: INWX
|
||||
layout: default
|
||||
jsId: INWX
|
||||
---
|
||||
|
||||
# INWX
|
||||
|
||||
INWX.de is a Berlin-based domain registrar.
|
||||
|
||||
## Configuration
|
||||
In your `creds.json` file you must provide your INWX
|
||||
username and password:
|
||||
|
||||
{% highlight json %}
|
||||
{
|
||||
"inwx":{
|
||||
"username": "yourUsername",
|
||||
"password": "yourPassword"
|
||||
}
|
||||
}
|
||||
{% endhighlight %}
|
||||
|
||||
### Two factor authentication
|
||||
|
||||
If two factor authentication has been enabled you will also need to provide a valid TOTP number.
|
||||
This can also be done
|
||||
via an environment variable:
|
||||
{% highlight json %}
|
||||
{
|
||||
"inwx":{
|
||||
"username": "yourUsername",
|
||||
"password": "yourPassword",
|
||||
"totp": "$INWX_TOTP"
|
||||
}
|
||||
}
|
||||
{% endhighlight %}
|
||||
|
||||
and then you can run
|
||||
|
||||
{% highlight bash %}
|
||||
$ INWX_TOTP=12345 dnscontrol preview
|
||||
{% endhighlight %}
|
||||
|
||||
It is also possible to directly provide the shared TOTP secret using the key "totp-key" in `creds.json`.
|
||||
This secret is only shown once when two factor authentication is enabled and you'll have to make sure to write it down then.
|
||||
|
||||
**Important Notes**:
|
||||
* Anyone with access to this `creds.json` file will have *full* access to your INWX account and will be able to transfer and/or delete your domains
|
||||
* Storing the shared secret together with the password weakens two factor authentication because both factors are stored in a single place.
|
||||
|
||||
{% highlight json %}
|
||||
{
|
||||
"inwx":{
|
||||
"username": "yourUsername",
|
||||
"password": "yourPassword",
|
||||
"totp-key": "yourTOTPSharedSecret"
|
||||
}
|
||||
}
|
||||
{% endhighlight %}
|
||||
|
||||
|
||||
### Sandbox
|
||||
You can optionally also specify sandbox with a value of 1 to
|
||||
redirect all requests to the sandbox API instead:
|
||||
{% highlight json %}
|
||||
{
|
||||
"inwx":{
|
||||
"username": "yourUsername",
|
||||
"password": "yourPassword",
|
||||
"sandbox": "1"
|
||||
}
|
||||
}
|
||||
{% endhighlight %}
|
||||
|
||||
If sandbox is omitted or set to any other value the production
|
||||
API will be used.
|
||||
|
||||
|
||||
## Metadata
|
||||
This provider does not recognize any special metadata fields unique to
|
||||
INWX.
|
||||
|
||||
## Usage
|
||||
Example Javascript for `example.tld` registered with INWX
|
||||
and delegated to CloudFlare:
|
||||
|
||||
{% highlight js %}
|
||||
var regInwx = NewRegistrar('inwx', 'INWX')
|
||||
var dnsCF = NewDnsProvider('cloudflare', 'CLOUDFLAREAPI')
|
||||
|
||||
D("example.tld", regInwx, DnsProvider(dnsCF),
|
||||
A("test","1.2.3.4")
|
||||
);
|
||||
|
||||
{%endhighlight%}
|
||||
|
||||
|
||||
|
|
@ -80,6 +80,7 @@ Maintainers of contributed providers:
|
|||
* `GANDI_V5` @TomOnTime
|
||||
* `HEXONET` @papakai
|
||||
* `INTERNETBS` @pragmaton
|
||||
* `INWX` @svenpeter42
|
||||
* `LINODE` @koesie10
|
||||
* `NAMECHEAP` @captncraig
|
||||
* `NETCUP` @kordianbruck
|
||||
|
|
4
go.mod
4
go.mod
|
@ -30,9 +30,11 @@ require (
|
|||
github.com/mittwald/go-powerdns v0.4.0
|
||||
github.com/mjibson/esc v0.2.0
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04
|
||||
github.com/nrdcg/goinwx v0.8.1
|
||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014
|
||||
github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pquerna/otp v1.2.0
|
||||
github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 // indirect
|
||||
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
|
@ -48,7 +50,7 @@ require (
|
|||
golang.org/x/mod v0.3.0 // indirect
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/tools v0.0.0-20200626032829-bcbc01e07a20 // indirect
|
||||
golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207 // indirect
|
||||
google.golang.org/api v0.28.0
|
||||
google.golang.org/appengine v1.6.6 // indirect
|
||||
gopkg.in/ini.v1 v1.42.0 // indirect
|
||||
|
|
17
go.sum
17
go.sum
|
@ -61,6 +61,8 @@ github.com/aws/aws-sdk-go v1.32.10/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZve
|
|||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/billputer/go-namecheap v0.0.0-20170915210158-0c7adb0710f8 h1:sIv3xbwhhAG94a62Q/rrSBtrWcXiYgldNOeqifyKSgo=
|
||||
github.com/billputer/go-namecheap v0.0.0-20170915210158-0c7adb0710f8/go.mod h1:bqqNsI2akL+lLWyApkYY0cxquWPKwEBU0Wd3chi3TEg=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY=
|
||||
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
|
@ -92,6 +94,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
|||
github.com/exoscale/egoscale v0.23.0 h1:hoUDzrO8yNoobNdnrRvlRFjfg3Ng0vQTrv6bXRJu6z0=
|
||||
github.com/exoscale/egoscale v0.23.0/go.mod h1:hRo78jkjkCDKpivQdRBEpNYF5+cVpCJCPDg2/r45KaY=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/go-acme/lego v2.7.2+incompatible h1:ThhpPBgf6oa9X/vRd0kEmWOsX7+vmYdckmGZSb+FEp0=
|
||||
github.com/go-acme/lego v2.7.2+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M=
|
||||
|
@ -190,6 +193,8 @@ github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+
|
|||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/vault/api v1.0.4 h1:j08Or/wryXT4AcHj1oCbMd7IijXcKzYUGw59LGu9onU=
|
||||
github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q=
|
||||
github.com/hashicorp/vault/sdk v0.1.13 h1:mOEPeOhT7jl0J4AMl1E705+BcmeRs1VmKNb9F0sMLy8=
|
||||
|
@ -208,6 +213,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
|
|||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b h1:DzHy0GlWeF0KAglaTMY7Q+khIFoG8toHP+wLFBVBQJc=
|
||||
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
|
@ -226,6 +233,8 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI
|
|||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
|
||||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mittwald/go-powerdns v0.4.0 h1:vEl2+4JINusy5NF8weObVRCuvHv8wqNBVMPZSQWq9zo=
|
||||
github.com/mittwald/go-powerdns v0.4.0/go.mod h1:bI/sZBAWyTViDknOTp19VfDxVEnh1U7rWPx2aRKtlzg=
|
||||
|
@ -235,6 +244,8 @@ github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAA
|
|||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||
github.com/nrdcg/goinwx v0.8.1 h1:20EQ/JaGFnSKwiDH2JzjIpicffl3cPk6imJBDqVBVtU=
|
||||
github.com/nrdcg/goinwx v0.8.1/go.mod h1:tILVc10gieBp/5PMvbcYeXM6pVQ+c9jxDZnpaR1UW7c=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 h1:37VE5TYj2m/FLA9SNr4z0+A0JefvTmR60Zwf8XSEV7c=
|
||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
|
||||
|
@ -249,6 +260,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok=
|
||||
github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 h1:Wdi9nwnhFNAlseAOekn6B5G/+GMtks9UKbvRU/CMM/o=
|
||||
github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU=
|
||||
|
@ -295,6 +308,7 @@ github.com/vultr/govultr v0.2.0 h1:CZSNNCk+PHz9hzmfH2PFGkDgc3qNetwZqtcaqL8shlg=
|
|||
github.com/vultr/govultr v0.2.0/go.mod h1:glSLa57Jdj5s860EEc6+DEBbb/t3aUOKnB4gVPmDVlQ=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
|
@ -382,6 +396,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4
|
|||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -455,6 +470,8 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
|
|||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200626032829-bcbc01e07a20 h1:q+ysxVHVQNTVHgzwjuk4ApAILRbfOLARfnEaqCIBR6A=
|
||||
golang.org/x/tools v0.0.0-20200626032829-bcbc01e07a20/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207 h1:8Kg+JssU1jBZs8GIrL5pl4nVyaqyyhdmHAR4D1zGErg=
|
||||
golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
@ -623,7 +623,7 @@ func makeTests(t *testing.T) []*TestGroup {
|
|||
),
|
||||
|
||||
testgroup("Null MX",
|
||||
not("AZURE_DNS", "GANDI_V5", "NAMEDOTCOM", "DIGITALOCEAN", "NETCUP", "DNSIMPLE"), // These providers don't support RFC 7505
|
||||
not("AZURE_DNS", "GANDI_V5", "INWX", "NAMEDOTCOM", "DIGITALOCEAN", "NETCUP", "DNSIMPLE"), // These providers don't support RFC 7505
|
||||
tc("Null MX", mx("@", 0, ".")),
|
||||
),
|
||||
|
||||
|
@ -656,14 +656,14 @@ func makeTests(t *testing.T) []*TestGroup {
|
|||
),
|
||||
|
||||
testgroup("ws TXT",
|
||||
not("CLOUDFLAREAPI", "NAMEDOTCOM"),
|
||||
not("CLOUDFLAREAPI", "INWX", "NAMEDOTCOM"),
|
||||
// These providers strip whitespace at the end of TXT records.
|
||||
// TODO(tal): Add a check for this in normalize/validate.go
|
||||
tc("Change a TXT with ws at end", txt("foo", "with space at end ")),
|
||||
),
|
||||
|
||||
testgroup("empty TXT",
|
||||
not("CLOUDFLAREAPI", "NETCUP"),
|
||||
not("CLOUDFLAREAPI", "INWX", "NETCUP"),
|
||||
tc("TXT with empty str", txt("foo1", "")),
|
||||
// https://github.com/StackExchange/dnscontrol/issues/598
|
||||
// We decided that permitting the TXT target to be an empty
|
||||
|
@ -786,7 +786,7 @@ func makeTests(t *testing.T) []*TestGroup {
|
|||
tc("Change Weight", srv("_sip._tcp", 52, 62, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")),
|
||||
tc("Change Port", srv("_sip._tcp", 52, 62, 72, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")),
|
||||
),
|
||||
testgroup("SRV w/ null target", requires(providers.CanUseSRV), not("EXOSCALE", "HEXONET", "NAMEDOTCOM"),
|
||||
testgroup("SRV w/ null target", requires(providers.CanUseSRV), not("EXOSCALE", "HEXONET", "INWX", "NAMEDOTCOM"),
|
||||
tc("Null Target", srv("_sip._tcp", 52, 62, 72, "foo.com."), srv("_sip._tcp", 15, 65, 75, ".")),
|
||||
),
|
||||
|
||||
|
|
|
@ -123,5 +123,11 @@
|
|||
"VULTR": {
|
||||
"domain": "$VULTR_DOMAIN",
|
||||
"token": "$VULTR_TOKEN"
|
||||
},
|
||||
"INWX": {
|
||||
"username": "$INWX_USER",
|
||||
"password": "$INWX_PASSWORD",
|
||||
"domain": "$INWX_DOMAIN",
|
||||
"sandbox": "1",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
_ "github.com/StackExchange/dnscontrol/v3/providers/gcloud"
|
||||
_ "github.com/StackExchange/dnscontrol/v3/providers/hexonet"
|
||||
_ "github.com/StackExchange/dnscontrol/v3/providers/internetbs"
|
||||
_ "github.com/StackExchange/dnscontrol/v3/providers/inwx"
|
||||
_ "github.com/StackExchange/dnscontrol/v3/providers/linode"
|
||||
_ "github.com/StackExchange/dnscontrol/v3/providers/namecheap"
|
||||
_ "github.com/StackExchange/dnscontrol/v3/providers/namedotcom"
|
||||
|
|
|
@ -29,7 +29,7 @@ const (
|
|||
// CanUsePTR indicates the provider can handle PTR records
|
||||
CanUsePTR
|
||||
|
||||
// CanUseNAPTR indicates the provider can handle PTR records
|
||||
// CanUseNAPTR indicates the provider can handle NAPTR records
|
||||
CanUseNAPTR
|
||||
|
||||
// CanUseSRV indicates the provider can handle SRV records
|
||||
|
|
345
providers/inwx/inwxProvider.go
Normal file
345
providers/inwx/inwxProvider.go
Normal file
|
@ -0,0 +1,345 @@
|
|||
package inwx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v3/models"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/diff"
|
||||
"github.com/StackExchange/dnscontrol/v3/providers"
|
||||
|
||||
"github.com/nrdcg/goinwx"
|
||||
"github.com/pquerna/otp/totp"
|
||||
)
|
||||
|
||||
/*
|
||||
INWX Registrar and DNS provider
|
||||
|
||||
Info required in `creds.json`:
|
||||
- username
|
||||
- password
|
||||
|
||||
Either of the following settings is required when two factor authentication is enabled:
|
||||
- totp (TOTP code if 2FA is enabled; best specified as an env variable)
|
||||
- totp-key (shared TOTP secret used to generate a valid TOTP code; not recommended since
|
||||
this effectively defeats the purpose of two factor authentication by storing
|
||||
both factors at the same place)
|
||||
|
||||
Additional settings available in `creds.json`:
|
||||
- sandbox (set to 1 to use the sandbox API from INWX)
|
||||
|
||||
*/
|
||||
|
||||
// InwxApi is a thin wrapper around goinwx.Client.
|
||||
type InwxApi struct {
|
||||
client *goinwx.Client
|
||||
sandbox bool
|
||||
}
|
||||
|
||||
// InwxDefaultNs contains the default INWX nameservers.
|
||||
var InwxDefaultNs = []string{"ns.inwx.de", "ns2.inwx.de", "ns3.inwx.eu", "ns4.inwx.com", "ns5.inwx.net"}
|
||||
|
||||
// InwxSandboxDefaultNs contains the default INWX nameservers in the sandbox / OTE.
|
||||
var InwxSandboxDefaultNs = []string{"ns.ote.inwx.de", "ns2.ote.inwx.de"}
|
||||
|
||||
// features is used to let dnscontrol know which features are supported by INWX.
|
||||
var features = providers.DocumentationNotes{
|
||||
providers.CanUseAlias: providers.Cannot("INWX does not support the ALIAS or ANAME record type."),
|
||||
providers.CanUseCAA: providers.Can(),
|
||||
providers.CanUseDS: providers.Unimplemented("DS records are only supported at the apex and require a different API call that hasn't been implemented yet."),
|
||||
providers.CanUsePTR: providers.Can("PTR records with empty targets are not supported"),
|
||||
providers.CanUseNAPTR: providers.Can(),
|
||||
providers.CanUseSRV: providers.Can("SRV records with empty targets are not supported."),
|
||||
providers.CanUseSSHFP: providers.Can(),
|
||||
providers.CanUseTLSA: providers.Can(),
|
||||
providers.CanUseTXTMulti: providers.Cannot("INWX only supports a single entry for TXT records"),
|
||||
providers.CanAutoDNSSEC: providers.Unimplemented("Supported by INWX but not implemented yet."),
|
||||
providers.DocOfficiallySupported: providers.Cannot(),
|
||||
providers.DocDualHost: providers.Can(),
|
||||
providers.DocCreateDomains: providers.Unimplemented("Supported by INWX but not implemented yet."),
|
||||
providers.CanGetZones: providers.Can(),
|
||||
providers.CanUseAzureAlias: providers.Cannot(),
|
||||
}
|
||||
|
||||
// init registers the registrar and the domain service provider with dnscontrol.
|
||||
func init() {
|
||||
providers.RegisterRegistrarType("INWX", newInwxReg)
|
||||
providers.RegisterDomainServiceProviderType("INWX", newInwxDsp, features)
|
||||
}
|
||||
|
||||
// getOTP either returns the TOTPValue or uses TOTPKey and the current time to generate a valid TOTPValue.
|
||||
func getOTP(TOTPValue string, TOTPKey string) (string, error) {
|
||||
if TOTPValue != "" {
|
||||
return TOTPValue, nil
|
||||
} else if TOTPKey != "" {
|
||||
tan, err := totp.GenerateCode(TOTPKey, time.Now())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("INWX: Unable to generate TOTP from totp-key: %v", err)
|
||||
}
|
||||
return tan, nil
|
||||
} else {
|
||||
return "", fmt.Errorf("INWX: two factor authentication required but no TOTP configured.")
|
||||
}
|
||||
}
|
||||
|
||||
// loginHelper tries to login and then unlocks the account using two factor authentication if required.
|
||||
func (api *InwxApi) loginHelper(TOTPValue string, TOTPKey string) error {
|
||||
resp, err := api.client.Account.Login()
|
||||
if err != nil {
|
||||
return fmt.Errorf("INWX: Unable to login")
|
||||
}
|
||||
|
||||
switch TFA := resp.TFA; TFA {
|
||||
case "0":
|
||||
if TOTPKey != "" || TOTPValue != "" {
|
||||
fmt.Printf("INWX: Warning: no TOTP requested by INWX but totp/totp-key is present in `creds.json`\n")
|
||||
}
|
||||
case "GOOGLE-AUTH":
|
||||
tan, err := getOTP(TOTPValue, TOTPKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = api.client.Account.Unlock(tan)
|
||||
if err != nil {
|
||||
return fmt.Errorf("INWX: Could not unlock account: %w.", err)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("INWX: Unknown two factor authentication mode `%s` has been requested.", resp.TFA)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// newInwx initializes InwxApi and create a session.
|
||||
func newInwx(m map[string]string) (*InwxApi, error) {
|
||||
username, password := m["username"], m["password"]
|
||||
TOTPValue, TOTPKey := m["totp"], m["totp-key"]
|
||||
sandbox := m["sandbox"] == "1"
|
||||
|
||||
if username == "" {
|
||||
return nil, fmt.Errorf("INWX: username must be provided.")
|
||||
}
|
||||
if password == "" {
|
||||
return nil, fmt.Errorf("INWX: password must be provided.")
|
||||
}
|
||||
if TOTPValue != "" && TOTPKey != "" {
|
||||
return nil, fmt.Errorf("INWX: totp and totp-key must not be specified at the same time.")
|
||||
}
|
||||
|
||||
opts := &goinwx.ClientOptions{Sandbox: sandbox}
|
||||
client := goinwx.NewClient(username, password, opts)
|
||||
api := &InwxApi{client: client, sandbox: sandbox}
|
||||
|
||||
err := api.loginHelper(TOTPValue, TOTPKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return api, nil
|
||||
}
|
||||
|
||||
// newInwxReg is called to initialize the INWX registrar provider.
|
||||
func newInwxReg(m map[string]string) (providers.Registrar, error) {
|
||||
return newInwx(m)
|
||||
}
|
||||
|
||||
// new InwxDsp is called to initialize the INWX domain service provider.
|
||||
func newInwxDsp(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
return newInwx(m)
|
||||
}
|
||||
|
||||
// makeNameserverRecordRequest is a helper function used to convert a RecordConfig to an INWX NS Record Request.
|
||||
func makeNameserverRecordRequest(domain string, rec *models.RecordConfig) *goinwx.NameserverRecordRequest {
|
||||
content := rec.GetTargetField()
|
||||
|
||||
req := &goinwx.NameserverRecordRequest{
|
||||
Domain: domain,
|
||||
Type: rec.Type,
|
||||
Content: content,
|
||||
Name: rec.GetLabel(),
|
||||
TTL: int(rec.TTL),
|
||||
}
|
||||
|
||||
switch rType := rec.Type; rType {
|
||||
/* INWX is a little bit special for CNAME,NS,MX and SRV records:
|
||||
The API will not accept any target with a final dot but will
|
||||
instead always add this final dot internally.
|
||||
Records with empty targets (i.e. records with target ".")
|
||||
are not allowed.
|
||||
*/
|
||||
case "CNAME", "NS":
|
||||
req.Content = content[:len(content)-1]
|
||||
case "MX":
|
||||
req.Priority = int(rec.MxPreference)
|
||||
req.Content = content[:len(content)-1]
|
||||
case "SRV":
|
||||
req.Priority = int(rec.SrvPriority)
|
||||
req.Content = fmt.Sprintf("%d %d %v", rec.SrvWeight, rec.SrvPort, content[:len(content)-1])
|
||||
default:
|
||||
req.Content = rec.GetTargetCombined()
|
||||
}
|
||||
|
||||
return req
|
||||
}
|
||||
|
||||
// createRecord is used by GetDomainCorrections to create a new record.
|
||||
func (api *InwxApi) createRecord(domain string, rec *models.RecordConfig) error {
|
||||
req := makeNameserverRecordRequest(domain, rec)
|
||||
_, err := api.client.Nameservers.CreateRecord(req)
|
||||
return err
|
||||
}
|
||||
|
||||
// updateRecord is used by GetDomainCorrections to update an existing record.
|
||||
func (api *InwxApi) updateRecord(RecordID int, rec *models.RecordConfig) error {
|
||||
req := makeNameserverRecordRequest("", rec)
|
||||
err := api.client.Nameservers.UpdateRecord(RecordID, req)
|
||||
return err
|
||||
}
|
||||
|
||||
// deleteRecord is used by GetDomainCorrections to delete a record.
|
||||
func (api *InwxApi) deleteRecord(RecordID int) error {
|
||||
return api.client.Nameservers.DeleteRecord(RecordID)
|
||||
}
|
||||
|
||||
// GetDomainCorrections finds the currently existing records and returns the corrections required to update them.
|
||||
func (api *InwxApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
|
||||
foundRecords, err := api.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
models.PostProcessRecords(foundRecords)
|
||||
|
||||
differ := diff.New(dc)
|
||||
_, create, del, mod := differ.IncrementalDiff(foundRecords)
|
||||
corrections := []*models.Correction{}
|
||||
|
||||
for _, d := range create {
|
||||
des := d.Desired
|
||||
corrections = append(corrections, &models.Correction{
|
||||
Msg: d.String(),
|
||||
F: func() error { return api.createRecord(dc.Name, des) },
|
||||
})
|
||||
}
|
||||
for _, d := range del {
|
||||
existingID := d.Existing.Original.(goinwx.NameserverRecord).ID
|
||||
corrections = append(corrections, &models.Correction{
|
||||
Msg: d.String(),
|
||||
F: func() error { return api.deleteRecord(existingID) },
|
||||
})
|
||||
}
|
||||
for _, d := range mod {
|
||||
rec := d.Desired
|
||||
existingID := d.Existing.Original.(goinwx.NameserverRecord).ID
|
||||
corrections = append(corrections, &models.Correction{
|
||||
Msg: d.String(),
|
||||
F: func() error { return api.updateRecord(existingID, rec) },
|
||||
})
|
||||
}
|
||||
|
||||
return corrections, nil
|
||||
}
|
||||
|
||||
// GetNameservers returns the default nameservers for INWX.
|
||||
func (api *InwxApi) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
if api.sandbox {
|
||||
return models.ToNameservers(InwxSandboxDefaultNs)
|
||||
} else {
|
||||
return models.ToNameservers(InwxDefaultNs)
|
||||
}
|
||||
}
|
||||
|
||||
// GetZoneRecords receives the current records from Inwx and converts them to models.RecordConfig.
|
||||
func (api *InwxApi) GetZoneRecords(domain string) (models.Records, error) {
|
||||
info, err := api.client.Nameservers.Info(&goinwx.NameserverInfoRequest{Domain: domain})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var records = []*models.RecordConfig{}
|
||||
|
||||
for _, record := range info.Records {
|
||||
if record.Type == "SOA" {
|
||||
continue
|
||||
}
|
||||
|
||||
/* INWX is a little bit special for CNAME,NS,MX and SRV records:
|
||||
The API will not accept any target with a final dot but will
|
||||
instead always add this final dot internally.
|
||||
Records with empty targets (i.e. records with target ".")
|
||||
are not allowed.
|
||||
*/
|
||||
if record.Type == "CNAME" || record.Type == "MX" || record.Type == "NS" || record.Type == "SRV" {
|
||||
record.Content = record.Content + "."
|
||||
}
|
||||
|
||||
rc := &models.RecordConfig{
|
||||
TTL: uint32(record.TTL),
|
||||
Original: record,
|
||||
}
|
||||
rc.SetLabelFromFQDN(record.Name, domain)
|
||||
|
||||
switch rType := record.Type; rType {
|
||||
case "MX":
|
||||
err = rc.SetTargetMX(uint16(record.Priority), record.Content)
|
||||
case "SRV":
|
||||
err = rc.SetTargetSRVPriorityString(uint16(record.Priority), record.Content)
|
||||
default:
|
||||
err = rc.PopulateFromString(rType, record.Content, domain)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("INWX: unparsable record received: %w", err))
|
||||
}
|
||||
|
||||
records = append(records, rc)
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// updateNameservers is used by GetRegistrarCorrections to update the domain's nameservers.
|
||||
func (api *InwxApi) updateNameservers(ns []string, domain string) func() error {
|
||||
return func() error {
|
||||
request := &goinwx.DomainUpdateRequest{
|
||||
Domain: domain,
|
||||
Nameservers: ns,
|
||||
}
|
||||
|
||||
_, err := api.client.Domains.Update(request)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// GetRegistrarCorrections is part of the registrar provider and determines if the nameservers have to be updated.
|
||||
func (api *InwxApi) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
info, err := api.client.Domains.Info(dc.Name, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sort.Strings(info.Nameservers)
|
||||
foundNameservers := strings.Join(info.Nameservers, ",")
|
||||
expected := []string{}
|
||||
for _, ns := range dc.Nameservers {
|
||||
expected = append(expected, ns.Name)
|
||||
}
|
||||
sort.Strings(expected)
|
||||
expectedNameservers := strings.Join(expected, ",")
|
||||
|
||||
if foundNameservers != expectedNameservers {
|
||||
return []*models.Correction{
|
||||
{
|
||||
Msg: fmt.Sprintf("Update nameservers %s -> %s", foundNameservers, expectedNameservers),
|
||||
F: api.updateNameservers(expected, dc.Name),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
Loading…
Reference in a new issue