forked from TrueCloudLab/lego
Change Aurora DNS client (#683)
This commit is contained in:
parent
5511373184
commit
a68cb214d3
16 changed files with 434 additions and 392 deletions
27
Gopkg.lock
generated
27
Gopkg.lock
generated
|
@ -174,21 +174,6 @@
|
|||
pruneopts = "NUT"
|
||||
revision = "35bcc6b47c20ec9bf3a53adcb7fa9665a75f0e7b"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:82127d77b40b617d650e64dc287cfc190f31d1030bd01cae5110780dd1e5bbb3"
|
||||
name = "github.com/edeckers/auroradnsclient"
|
||||
packages = [
|
||||
".",
|
||||
"records",
|
||||
"requests",
|
||||
"requests/errors",
|
||||
"tokens",
|
||||
"zones",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "1563e622aaca0a8bb895a448f31d4a430ab97586"
|
||||
version = "v1.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e096f1857eedd49e2bd0885d05105d1d4af1bfcf8b1d07fa5710718e6641fd48"
|
||||
name = "github.com/exoscale/egoscale"
|
||||
|
@ -271,6 +256,14 @@
|
|||
revision = "59fac5042749a5afb9af70e813da1dd5474f0167"
|
||||
version = "1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:417193ba917954c4837c6fc48c6ac241b3fefd13fc0889367b4a7e43b69d582c"
|
||||
name = "github.com/ldez/go-auroradns"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "b40dfcae7c417f8129579362695dc1f3cfe5928d"
|
||||
version = "v2.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:111ff5a09a32895248270bfaef9b8b6ac163a8cde9cdd603fed64b3e4b59e8ab"
|
||||
name = "github.com/linode/linodego"
|
||||
|
@ -604,12 +597,10 @@
|
|||
"github.com/cpu/goacmedns",
|
||||
"github.com/decker502/dnspod-go",
|
||||
"github.com/dnsimple/dnsimple-go/dnsimple",
|
||||
"github.com/edeckers/auroradnsclient",
|
||||
"github.com/edeckers/auroradnsclient/records",
|
||||
"github.com/edeckers/auroradnsclient/zones",
|
||||
"github.com/exoscale/egoscale",
|
||||
"github.com/iij/doapi",
|
||||
"github.com/iij/doapi/protocol",
|
||||
"github.com/ldez/go-auroradns",
|
||||
"github.com/linode/linodego",
|
||||
"github.com/miekg/dns",
|
||||
"github.com/namedotcom/go/namecom",
|
||||
|
|
|
@ -7,9 +7,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/edeckers/auroradnsclient"
|
||||
"github.com/edeckers/auroradnsclient/records"
|
||||
"github.com/edeckers/auroradnsclient/zones"
|
||||
"github.com/ldez/go-auroradns"
|
||||
"github.com/xenolf/lego/acme"
|
||||
"github.com/xenolf/lego/platform/config/env"
|
||||
)
|
||||
|
@ -40,7 +38,7 @@ type DNSProvider struct {
|
|||
recordIDs map[string]string
|
||||
recordIDsMu sync.Mutex
|
||||
config *Config
|
||||
client *auroradnsclient.AuroraDNSClient
|
||||
client *auroradns.Client
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a DNSProvider instance configured for AuroraDNS.
|
||||
|
@ -86,7 +84,12 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
config.BaseURL = defaultBaseURL
|
||||
}
|
||||
|
||||
client, err := auroradnsclient.NewAuroraDNSClient(config.BaseURL, config.UserID, config.Key)
|
||||
tr, err := auroradns.NewTokenTransport(config.UserID, config.Key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aurora: %v", err)
|
||||
}
|
||||
|
||||
client, err := auroradns.NewClient(tr.Client(), auroradns.WithBaseURL(config.BaseURL))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aurora: %v", err)
|
||||
}
|
||||
|
@ -118,26 +121,25 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
|
||||
authZone = acme.UnFqdn(authZone)
|
||||
|
||||
zoneRecord, err := d.getZoneInformationByName(authZone)
|
||||
zone, err := d.getZoneInformationByName(authZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("aurora: could not create record: %v", err)
|
||||
}
|
||||
|
||||
reqData :=
|
||||
records.CreateRecordRequest{
|
||||
RecordType: "TXT",
|
||||
Name: subdomain,
|
||||
Content: value,
|
||||
TTL: d.config.TTL,
|
||||
}
|
||||
record := auroradns.Record{
|
||||
RecordType: "TXT",
|
||||
Name: subdomain,
|
||||
Content: value,
|
||||
TTL: d.config.TTL,
|
||||
}
|
||||
|
||||
respData, err := d.client.CreateRecord(zoneRecord.ID, reqData)
|
||||
newRecord, _, err := d.client.CreateRecord(zone.ID, record)
|
||||
if err != nil {
|
||||
return fmt.Errorf("aurora: could not create record: %v", err)
|
||||
}
|
||||
|
||||
d.recordIDsMu.Lock()
|
||||
d.recordIDs[fqdn] = respData.ID
|
||||
d.recordIDs[fqdn] = newRecord.ID
|
||||
d.recordIDsMu.Unlock()
|
||||
|
||||
return nil
|
||||
|
@ -162,12 +164,12 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
|
||||
authZone = acme.UnFqdn(authZone)
|
||||
|
||||
zoneRecord, err := d.getZoneInformationByName(authZone)
|
||||
zone, err := d.getZoneInformationByName(authZone)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = d.client.RemoveRecord(zoneRecord.ID, recordID)
|
||||
_, _, err = d.client.DeleteRecord(zone.ID, recordID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -185,10 +187,10 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
|
||||
func (d *DNSProvider) getZoneInformationByName(name string) (zones.ZoneRecord, error) {
|
||||
zs, err := d.client.GetZones()
|
||||
func (d *DNSProvider) getZoneInformationByName(name string) (auroradns.Zone, error) {
|
||||
zs, _, err := d.client.ListZones()
|
||||
if err != nil {
|
||||
return zones.ZoneRecord{}, err
|
||||
return auroradns.Zone{}, err
|
||||
}
|
||||
|
||||
for _, element := range zs {
|
||||
|
@ -197,5 +199,5 @@ func (d *DNSProvider) getZoneInformationByName(name string) (zones.ZoneRecord, e
|
|||
}
|
||||
}
|
||||
|
||||
return zones.ZoneRecord{}, fmt.Errorf("could not find Zone record")
|
||||
return auroradns.Zone{}, fmt.Errorf("could not find Zone record")
|
||||
}
|
||||
|
|
22
vendor/github.com/edeckers/auroradnsclient/client.go
generated
vendored
22
vendor/github.com/edeckers/auroradnsclient/client.go
generated
vendored
|
@ -1,22 +0,0 @@
|
|||
package auroradnsclient
|
||||
|
||||
import (
|
||||
"github.com/edeckers/auroradnsclient/requests"
|
||||
)
|
||||
|
||||
// AuroraDNSClient is a client for accessing the Aurora DNS API
|
||||
type AuroraDNSClient struct {
|
||||
requestor *requests.AuroraRequestor
|
||||
}
|
||||
|
||||
// NewAuroraDNSClient instantiates a new client
|
||||
func NewAuroraDNSClient(endpoint string, userID string, key string) (*AuroraDNSClient, error) {
|
||||
requestor, err := requests.NewAuroraRequestor(endpoint, userID, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &AuroraDNSClient{
|
||||
requestor: requestor,
|
||||
}, nil
|
||||
}
|
11
vendor/github.com/edeckers/auroradnsclient/errors.go
generated
vendored
11
vendor/github.com/edeckers/auroradnsclient/errors.go
generated
vendored
|
@ -1,11 +0,0 @@
|
|||
package auroradnsclient
|
||||
|
||||
// AuroraDNSError describes the format of a generic AuroraDNS API error
|
||||
type AuroraDNSError struct {
|
||||
ErrorCode string `json:"error"`
|
||||
Message string `json:"errormsg"`
|
||||
}
|
||||
|
||||
func (e AuroraDNSError) Error() string {
|
||||
return e.Message
|
||||
}
|
75
vendor/github.com/edeckers/auroradnsclient/records.go
generated
vendored
75
vendor/github.com/edeckers/auroradnsclient/records.go
generated
vendored
|
@ -1,75 +0,0 @@
|
|||
package auroradnsclient
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/edeckers/auroradnsclient/records"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// GetRecords returns a list of all records in given zone
|
||||
func (client *AuroraDNSClient) GetRecords(zoneID string) ([]records.GetRecordsResponse, error) {
|
||||
logrus.Debugf("GetRecords(%s)", zoneID)
|
||||
relativeURL := fmt.Sprintf("zones/%s/records", zoneID)
|
||||
|
||||
response, err := client.requestor.Request(relativeURL, "GET", []byte(""))
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to receive records: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var respData []records.GetRecordsResponse
|
||||
err = json.Unmarshal(response, &respData)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to unmarshall response: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return respData, nil
|
||||
}
|
||||
|
||||
// CreateRecord creates a new record in given zone
|
||||
func (client *AuroraDNSClient) CreateRecord(zoneID string, data records.CreateRecordRequest) (*records.CreateRecordResponse, error) {
|
||||
logrus.Debugf("CreateRecord(%s, %+v)", zoneID, data)
|
||||
body, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to marshall request body: %s", err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
relativeURL := fmt.Sprintf("zones/%s/records", zoneID)
|
||||
|
||||
response, err := client.requestor.Request(relativeURL, "POST", body)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to create record: %s", err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var respData *records.CreateRecordResponse
|
||||
err = json.Unmarshal(response, &respData)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to unmarshall response: %s", err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return respData, nil
|
||||
}
|
||||
|
||||
// RemoveRecord removes a record corresponding to a particular id in a given zone
|
||||
func (client *AuroraDNSClient) RemoveRecord(zoneID string, recordID string) (*records.RemoveRecordResponse, error) {
|
||||
logrus.Debugf("RemoveRecord(%s, %s)", zoneID, recordID)
|
||||
relativeURL := fmt.Sprintf("zones/%s/records/%s", zoneID, recordID)
|
||||
|
||||
_, err := client.requestor.Request(relativeURL, "DELETE", nil)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to remove record: %s", err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &records.RemoveRecordResponse{}, nil
|
||||
}
|
31
vendor/github.com/edeckers/auroradnsclient/records/datatypes.go
generated
vendored
31
vendor/github.com/edeckers/auroradnsclient/records/datatypes.go
generated
vendored
|
@ -1,31 +0,0 @@
|
|||
package records
|
||||
|
||||
// CreateRecordRequest describes the json payload for creating a record
|
||||
type CreateRecordRequest struct {
|
||||
RecordType string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content"`
|
||||
TTL int `json:"ttl"`
|
||||
}
|
||||
|
||||
// CreateRecordResponse describes the json response for creating a record
|
||||
type CreateRecordResponse struct {
|
||||
ID string `json:"id"`
|
||||
RecordType string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content"`
|
||||
TTL int `json:"ttl"`
|
||||
}
|
||||
|
||||
// GetRecordsResponse describes the json response of a single record
|
||||
type GetRecordsResponse struct {
|
||||
ID string `json:"id"`
|
||||
RecordType string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content"`
|
||||
TTL int `json:"ttl"`
|
||||
}
|
||||
|
||||
// RemoveRecordResponse describes the json response for removing a record
|
||||
type RemoveRecordResponse struct {
|
||||
}
|
19
vendor/github.com/edeckers/auroradnsclient/requests/errors/errors.go
generated
vendored
19
vendor/github.com/edeckers/auroradnsclient/requests/errors/errors.go
generated
vendored
|
@ -1,19 +0,0 @@
|
|||
package errors
|
||||
|
||||
// BadRequest HTTP error wrapper
|
||||
type BadRequest error
|
||||
|
||||
// Unauthorized HTTP error wrapper
|
||||
type Unauthorized error
|
||||
|
||||
// Forbidden HTTP error wrapper
|
||||
type Forbidden error
|
||||
|
||||
// NotFound HTTP error wrapper
|
||||
type NotFound error
|
||||
|
||||
// ServerError HTTP error wrapper
|
||||
type ServerError error
|
||||
|
||||
// InvalidStatusCodeError is used when none of the other types applies
|
||||
type InvalidStatusCodeError error
|
124
vendor/github.com/edeckers/auroradnsclient/requests/requestor.go
generated
vendored
124
vendor/github.com/edeckers/auroradnsclient/requests/requestor.go
generated
vendored
|
@ -1,124 +0,0 @@
|
|||
package requests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"time"
|
||||
|
||||
request_errors "github.com/edeckers/auroradnsclient/requests/errors"
|
||||
"github.com/edeckers/auroradnsclient/tokens"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// AuroraRequestor performs actual requests to API
|
||||
type AuroraRequestor struct {
|
||||
endpoint string
|
||||
userID string
|
||||
key string
|
||||
}
|
||||
|
||||
// NewAuroraRequestor instantiates a new requestor
|
||||
func NewAuroraRequestor(endpoint string, userID string, key string) (*AuroraRequestor, error) {
|
||||
if endpoint == "" {
|
||||
return nil, fmt.Errorf("Aurora endpoint missing")
|
||||
}
|
||||
|
||||
if userID == "" || key == "" {
|
||||
return nil, fmt.Errorf("Aurora credentials missing")
|
||||
}
|
||||
|
||||
return &AuroraRequestor{endpoint: endpoint, userID: userID, key: key}, nil
|
||||
}
|
||||
|
||||
func (requestor *AuroraRequestor) buildRequest(relativeURL string, method string, body []byte) (*http.Request, error) {
|
||||
url := fmt.Sprintf("%s/%s", requestor.endpoint, relativeURL)
|
||||
|
||||
request, err := http.NewRequest(method, url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to build request: %s", err)
|
||||
|
||||
return request, err
|
||||
}
|
||||
|
||||
timestamp := time.Now().UTC()
|
||||
fmtTime := timestamp.Format("20060102T150405Z")
|
||||
|
||||
token := tokens.NewToken(requestor.userID, requestor.key, method, fmt.Sprintf("/%s", relativeURL), timestamp)
|
||||
|
||||
request.Header.Set("X-AuroraDNS-Date", fmtTime)
|
||||
request.Header.Set("Authorization", fmt.Sprintf("AuroraDNSv1 %s", token))
|
||||
|
||||
request.Header.Set("Content-Type", "application/json")
|
||||
|
||||
rawRequest, err := httputil.DumpRequestOut(request, true)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to dump request: %s", err)
|
||||
}
|
||||
|
||||
logrus.Debugf("Built request:\n%s", rawRequest)
|
||||
|
||||
return request, err
|
||||
}
|
||||
|
||||
func (requestor *AuroraRequestor) testInvalidResponse(resp *http.Response, response []byte) ([]byte, error) {
|
||||
if resp.StatusCode < 400 {
|
||||
return response, nil
|
||||
}
|
||||
|
||||
logrus.Errorf("Received invalid status code %d:\n%s", resp.StatusCode, response)
|
||||
|
||||
content := errors.New(string(response))
|
||||
|
||||
statusCodeErrorMap := map[int]error{
|
||||
400: request_errors.BadRequest(content),
|
||||
401: request_errors.Unauthorized(content),
|
||||
403: request_errors.Forbidden(content),
|
||||
404: request_errors.NotFound(content),
|
||||
500: request_errors.ServerError(content),
|
||||
}
|
||||
|
||||
mappedError := statusCodeErrorMap[resp.StatusCode]
|
||||
|
||||
if mappedError == nil {
|
||||
return nil, request_errors.InvalidStatusCodeError(content)
|
||||
}
|
||||
|
||||
return nil, mappedError
|
||||
}
|
||||
|
||||
// Request builds and executues a request to the API
|
||||
func (requestor *AuroraRequestor) Request(relativeURL string, method string, body []byte) ([]byte, error) {
|
||||
req, err := requestor.buildRequest(relativeURL, method, body)
|
||||
|
||||
client := http.Client{Timeout: 30 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed request: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
rawResponse, err := httputil.DumpResponse(resp, true)
|
||||
logrus.Debugf("Received raw response:\n%s", rawResponse)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to dump response: %s", err)
|
||||
}
|
||||
|
||||
response, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to read response: %s", response)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err = requestor.testInvalidResponse(resp, response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
35
vendor/github.com/edeckers/auroradnsclient/tokens/generator.go
generated
vendored
35
vendor/github.com/edeckers/auroradnsclient/tokens/generator.go
generated
vendored
|
@ -1,35 +0,0 @@
|
|||
package tokens
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// NewToken generates a token for accessing a specific method of the API
|
||||
func NewToken(userID string, key string, method string, action string, timestamp time.Time) string {
|
||||
fmtTime := timestamp.Format("20060102T150405Z")
|
||||
logrus.Debugf("Built timestamp: %s", fmtTime)
|
||||
|
||||
message := strings.Join([]string{method, action, fmtTime}, "")
|
||||
logrus.Debugf("Built message: %s", message)
|
||||
|
||||
signatureHmac := hmac.New(sha256.New, []byte(key))
|
||||
|
||||
signatureHmac.Write([]byte(message))
|
||||
|
||||
signature := base64.StdEncoding.EncodeToString([]byte(signatureHmac.Sum(nil)))
|
||||
logrus.Debugf("Built signature: %s", signature)
|
||||
|
||||
userIDAndSignature := fmt.Sprintf("%s:%s", userID, signature)
|
||||
|
||||
token := base64.StdEncoding.EncodeToString([]byte(userIDAndSignature))
|
||||
logrus.Debugf("Built token: %s", token)
|
||||
|
||||
return token
|
||||
}
|
29
vendor/github.com/edeckers/auroradnsclient/zones.go
generated
vendored
29
vendor/github.com/edeckers/auroradnsclient/zones.go
generated
vendored
|
@ -1,29 +0,0 @@
|
|||
package auroradnsclient
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/edeckers/auroradnsclient/zones"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// GetZones returns a list of all zones
|
||||
func (client *AuroraDNSClient) GetZones() ([]zones.ZoneRecord, error) {
|
||||
logrus.Debugf("GetZones")
|
||||
response, err := client.requestor.Request("zones", "GET", []byte(""))
|
||||
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get zones: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var respData []zones.ZoneRecord
|
||||
err = json.Unmarshal(response, &respData)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to unmarshall response: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logrus.Debugf("Unmarshalled response: %+v", respData)
|
||||
return respData, nil
|
||||
}
|
7
vendor/github.com/edeckers/auroradnsclient/zones/datatypes.go
generated
vendored
7
vendor/github.com/edeckers/auroradnsclient/zones/datatypes.go
generated
vendored
|
@ -1,7 +0,0 @@
|
|||
package zones
|
||||
|
||||
// ZoneRecord describes the json format for a zone
|
||||
type ZoneRecord struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
98
vendor/github.com/ldez/go-auroradns/auth.go
generated
vendored
Normal file
98
vendor/github.com/ldez/go-auroradns/auth.go
generated
vendored
Normal file
|
@ -0,0 +1,98 @@
|
|||
package auroradns
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TokenTransport HTTP transport for API authentication
|
||||
type TokenTransport struct {
|
||||
userID string
|
||||
key string
|
||||
|
||||
// Transport is the underlying HTTP transport to use when making requests.
|
||||
// It will default to http.DefaultTransport if nil.
|
||||
Transport http.RoundTripper
|
||||
}
|
||||
|
||||
// NewTokenTransport Creates a new TokenTransport
|
||||
func NewTokenTransport(userID, key string) (*TokenTransport, error) {
|
||||
if userID == "" || key == "" {
|
||||
return nil, fmt.Errorf("credentials missing")
|
||||
}
|
||||
|
||||
return &TokenTransport{userID: userID, key: key}, nil
|
||||
}
|
||||
|
||||
// RoundTrip executes a single HTTP transaction
|
||||
func (t *TokenTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
enrichedReq := &http.Request{}
|
||||
*enrichedReq = *req
|
||||
|
||||
enrichedReq.Header = make(http.Header, len(req.Header))
|
||||
for k, s := range req.Header {
|
||||
enrichedReq.Header[k] = append([]string(nil), s...)
|
||||
}
|
||||
|
||||
if t.userID != "" && t.key != "" {
|
||||
timestamp := time.Now().UTC()
|
||||
|
||||
fmtTime := timestamp.Format("20060102T150405Z")
|
||||
req.Header.Set("X-AuroraDNS-Date", fmtTime)
|
||||
|
||||
token, err := newToken(t.userID, t.key, req.Method, req.URL.Path, timestamp)
|
||||
if err == nil {
|
||||
req.Header.Set("Authorization", fmt.Sprintf("AuroraDNSv1 %s", token))
|
||||
}
|
||||
}
|
||||
|
||||
return t.transport().RoundTrip(enrichedReq)
|
||||
}
|
||||
|
||||
// Wrap Wrap a HTTP client Transport with the TokenTransport
|
||||
func (t *TokenTransport) Wrap(client *http.Client) *http.Client {
|
||||
backup := client.Transport
|
||||
t.Transport = backup
|
||||
client.Transport = t
|
||||
return client
|
||||
}
|
||||
|
||||
// Client Creates a new HTTP client
|
||||
func (t *TokenTransport) Client() *http.Client {
|
||||
return &http.Client{
|
||||
Transport: t,
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TokenTransport) transport() http.RoundTripper {
|
||||
if t.Transport != nil {
|
||||
return t.Transport
|
||||
}
|
||||
return http.DefaultTransport
|
||||
}
|
||||
|
||||
// newToken generates a token for accessing a specific method of the API
|
||||
func newToken(userID string, key string, method string, action string, timestamp time.Time) (string, error) {
|
||||
fmtTime := timestamp.Format("20060102T150405Z")
|
||||
message := strings.Join([]string{method, action, fmtTime}, "")
|
||||
|
||||
signatureHmac := hmac.New(sha256.New, []byte(key))
|
||||
_, err := signatureHmac.Write([]byte(message))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
signature := base64.StdEncoding.EncodeToString(signatureHmac.Sum(nil))
|
||||
|
||||
userIDAndSignature := fmt.Sprintf("%s:%s", userID, signature)
|
||||
|
||||
token := base64.StdEncoding.EncodeToString([]byte(userIDAndSignature))
|
||||
|
||||
return token, nil
|
||||
}
|
144
vendor/github.com/ldez/go-auroradns/client.go
generated
vendored
Normal file
144
vendor/github.com/ldez/go-auroradns/client.go
generated
vendored
Normal file
|
@ -0,0 +1,144 @@
|
|||
package auroradns
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const defaultBaseURL = "https://api.auroradns.eu"
|
||||
|
||||
const (
|
||||
contentTypeHeader = "Content-Type"
|
||||
contentTypeJSON = "application/json"
|
||||
)
|
||||
|
||||
// ErrorResponse A representation of an API error message.
|
||||
type ErrorResponse struct {
|
||||
ErrorCode string `json:"error"`
|
||||
Message string `json:"errormsg"`
|
||||
}
|
||||
|
||||
func (e *ErrorResponse) Error() string {
|
||||
return fmt.Sprintf("%s - %s", e.ErrorCode, e.Message)
|
||||
}
|
||||
|
||||
// Option Type of a client option
|
||||
type Option func(*Client) error
|
||||
|
||||
// Client The API client
|
||||
type Client struct {
|
||||
baseURL *url.URL
|
||||
UserAgent string
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
// NewClient Creates a new client
|
||||
func NewClient(httpClient *http.Client, opts ...Option) (*Client, error) {
|
||||
if httpClient == nil {
|
||||
httpClient = http.DefaultClient
|
||||
}
|
||||
|
||||
baseURL, _ := url.Parse(defaultBaseURL)
|
||||
|
||||
client := &Client{
|
||||
baseURL: baseURL,
|
||||
httpClient: httpClient,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
err := opt(client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(method, resource string, body io.Reader) (*http.Request, error) {
|
||||
u, err := c.baseURL.Parse(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, u.String(), body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set(contentTypeHeader, contentTypeJSON)
|
||||
|
||||
if c.UserAgent != "" {
|
||||
req.Header.Set("User-Agent", c.UserAgent)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (c *Client) do(req *http.Request, v interface{}) (*http.Response, error) {
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
if err = checkResponse(resp); err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if v == nil {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
raw, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("failed to read body: %v", err)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(raw, v); err != nil {
|
||||
return resp, fmt.Errorf("unmarshaling %T error: %v: %s", err, v, string(raw))
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func checkResponse(resp *http.Response) error {
|
||||
if c := resp.StatusCode; 200 <= c && c <= 299 {
|
||||
return nil
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err == nil && data != nil {
|
||||
errorResponse := new(ErrorResponse)
|
||||
err = json.Unmarshal(data, errorResponse)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshaling ErrorResponse error: %v: %s", err.Error(), string(data))
|
||||
}
|
||||
|
||||
return errorResponse
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithBaseURL Allows to define a custom base URL
|
||||
func WithBaseURL(rawBaseURL string) func(*Client) error {
|
||||
return func(client *Client) error {
|
||||
if len(rawBaseURL) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
baseURL, err := url.Parse(rawBaseURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client.baseURL = baseURL
|
||||
return nil
|
||||
}
|
||||
}
|
91
vendor/github.com/ldez/go-auroradns/records.go
generated
vendored
Normal file
91
vendor/github.com/ldez/go-auroradns/records.go
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
package auroradns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Record types
|
||||
const (
|
||||
RecordTypeA = "A"
|
||||
RecordTypeAAAA = "AAAA"
|
||||
RecordTypeCNAME = "CNAME"
|
||||
RecordTypeMX = "MX"
|
||||
RecordTypeNS = "NS"
|
||||
RecordTypeSOA = "SOA"
|
||||
RecordTypeSRV = "SRV"
|
||||
RecordTypeTXT = "TXT"
|
||||
RecordTypeDS = "DS"
|
||||
RecordTypePTR = "PTR"
|
||||
RecordTypeSSHFP = "SSHFP"
|
||||
RecordTypeTLSA = "TLS"
|
||||
)
|
||||
|
||||
// Record a DNS record
|
||||
type Record struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
RecordType string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content"`
|
||||
TTL int `json:"ttl,omitempty"`
|
||||
}
|
||||
|
||||
// CreateRecord Creates a new record.
|
||||
func (c *Client) CreateRecord(zoneID string, record Record) (*Record, *http.Response, error) {
|
||||
body, err := json.Marshal(record)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to marshall request body: %v", err)
|
||||
}
|
||||
|
||||
resource := fmt.Sprintf("/zones/%s/records", zoneID)
|
||||
|
||||
req, err := c.newRequest(http.MethodPost, resource, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
newRecord := new(Record)
|
||||
resp, err := c.do(req, newRecord)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return newRecord, resp, nil
|
||||
}
|
||||
|
||||
// DeleteRecord Delete a record.
|
||||
func (c *Client) DeleteRecord(zoneID string, recordID string) (bool, *http.Response, error) {
|
||||
resource := fmt.Sprintf("/zones/%s/records/%s", zoneID, recordID)
|
||||
|
||||
req, err := c.newRequest(http.MethodDelete, resource, nil)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
resp, err := c.do(req, nil)
|
||||
if err != nil {
|
||||
return false, resp, err
|
||||
}
|
||||
|
||||
return true, resp, nil
|
||||
}
|
||||
|
||||
// ListRecords returns a list of all records in given zone
|
||||
func (c *Client) ListRecords(zoneID string) ([]Record, *http.Response, error) {
|
||||
resource := fmt.Sprintf("/zones/%s/records", zoneID)
|
||||
|
||||
req, err := c.newRequest(http.MethodGet, resource, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var records []Record
|
||||
resp, err := c.do(req, &records)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return records, resp, nil
|
||||
}
|
69
vendor/github.com/ldez/go-auroradns/zones.go
generated
vendored
Normal file
69
vendor/github.com/ldez/go-auroradns/zones.go
generated
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
package auroradns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Zone a DNS zone
|
||||
type Zone struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// CreateZone Creates a zone.
|
||||
func (c *Client) CreateZone(domain string) (*Zone, *http.Response, error) {
|
||||
body, err := json.Marshal(Zone{Name: domain})
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to marshall request body: %v", err)
|
||||
}
|
||||
|
||||
req, err := c.newRequest(http.MethodPost, "/zones", bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
zone := new(Zone)
|
||||
resp, err := c.do(req, zone)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return zone, resp, nil
|
||||
}
|
||||
|
||||
// DeleteZone Delete a zone.
|
||||
func (c *Client) DeleteZone(zoneID string) (bool, *http.Response, error) {
|
||||
resource := fmt.Sprintf("/zones/%s", zoneID)
|
||||
|
||||
req, err := c.newRequest(http.MethodDelete, resource, nil)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
resp, err := c.do(req, nil)
|
||||
if err != nil {
|
||||
return false, resp, err
|
||||
}
|
||||
|
||||
return true, resp, nil
|
||||
|
||||
}
|
||||
|
||||
// ListZones returns a list of all zones.
|
||||
func (c *Client) ListZones() ([]Zone, *http.Response, error) {
|
||||
req, err := c.newRequest(http.MethodGet, "/zones", nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var zones []Zone
|
||||
resp, err := c.do(req, &zones)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return zones, resp, nil
|
||||
}
|
Loading…
Reference in a new issue