1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00
Files
stackexchange-dnscontrol/vendor/github.com/xlucas/go-ovh/ovh/client.go
Tom Limoncelli e63949e8fa Revert "Remove unused go modules. (#511)"
This reverts commit 8c7e7be403.
2019-06-28 11:27:58 -04:00

158 lines
3.9 KiB
Go

package ovh
import (
"bytes"
"crypto/sha1"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"
"time"
)
// OVH endpoints list
const (
ENDPOINT_CA_OVHCOM = "https://ca.api.ovh.com/1.0"
ENDPOINT_CA_KIMSUFI = "https://ca.api.kimsufi.com/1.0"
ENDPOINT_CA_RUNABOVE = "https://api.runabove.com/1.0"
ENDPOINT_CA_SOYOUSTART = "https://ca.api.soyoustart.com/1.0"
ENDPOINT_EU_OVHCOM = "https://eu.api.ovh.com/1.0"
ENDPOINT_EU_KIMSUFI = "https://eu.api.kimsufi.com/1.0"
ENDPOINT_EU_RUNABOVE = "https://api.runabove.com/1.0"
ENDPOINT_EU_SOYOUSTART = "https://eu.api.soyoustart.com/1.0"
)
// Client helps interacting with OVH API endpoints.
type Client struct {
AppKey string
AppSecret string
ConsumerKey string
Endpoint string
TimeShift time.Duration
Debug bool
}
// NewClient builds up a new client link to the specified endpoint
// with given authentication information and no timeshift.
func NewClient(endpoint, ak, as, ck string, debug bool) *Client {
return &Client{
AppKey: ak,
AppSecret: as,
ConsumerKey: ck,
Endpoint: endpoint,
TimeShift: 0,
Debug: debug,
}
}
func computeSignature(appSecret, consumerKey, method, url string, body []byte, timestamp int64) string {
hasher := sha1.New()
pattern := fmt.Sprintf("%s+%s+%s+%s+%s+%d",
appSecret,
consumerKey,
method,
url,
body,
timestamp)
hasher.Write([]byte(pattern))
return fmt.Sprintf("$1$%x", hasher.Sum(nil))
}
func sendRequest(appKey, consumerKey, signature string, timestamp int64, method, url string, body []byte) ([]byte, error) {
req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Add("X-Ovh-Application", appKey)
req.Header.Add("X-Ovh-Consumer", consumerKey)
req.Header.Add("X-Ovh-Signature", signature)
req.Header.Add("X-Ovh-Timestamp", fmt.Sprintf("%d", timestamp))
httpClient := &http.Client{}
resp, err := httpClient.Do(req)
if err != nil {
return nil, err
}
outBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
return nil, fmt.Errorf("Unexpected HTTP return code (%s : %s).", resp.Status, outBytes)
}
return outBytes, err
}
// PollTimeshift calculates the difference between
// local and remote system time through a call to
// the API. It may be useful to call this function
// to avoid signatures to be rejected due to
// timeshift or network delay.
func (c *Client) PollTimeshift() error {
sysTime := time.Now()
resp, err := http.Get(c.Endpoint + "/auth/time")
if err != nil {
return err
}
outPayload, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
apiTime, err := strconv.ParseInt(string(outPayload), 10, 64)
if err != nil {
return err
}
c.TimeShift = time.Unix(apiTime, 0).Sub(sysTime)
return err
}
// Call sends a request to the OVH API and returns response content.
// Input and output json processing will leverage json
// marshalling/unmarshalling of the specified interfaces.
func (c *Client) Call(method, path string, in interface{}, out interface{}) error {
var (
inBytes, outBytes []byte
err error
)
if in != nil {
inBytes, err = json.Marshal(in)
}
if err != nil {
return err
}
url := c.Endpoint + path
timestamp := time.Now().Add(c.TimeShift).Unix()
signature := computeSignature(c.AppSecret, c.ConsumerKey, method, url, inBytes, timestamp)
if c.Debug {
log.Printf("Method = %s", method)
log.Printf("URL = %s", url)
log.Printf("Timestamp = %d", timestamp)
log.Printf("Signature = %s", signature)
log.Printf("Body = %s", inBytes)
}
outBytes, err = sendRequest(c.AppKey, c.ConsumerKey, signature, timestamp, method, url, inBytes)
if err != nil {
return err
}
err = json.Unmarshal(outBytes, &out)
if err != nil {
return err
}
return nil
}
func (c *Client) SetDebug(debug bool) {
c.Debug = debug
}