cloudflare: use the official go client. (#658)
This commit is contained in:
parent
8a8aa2d81b
commit
18fe57183d
36 changed files with 4592 additions and 451 deletions
17
Gopkg.lock
generated
17
Gopkg.lock
generated
|
@ -126,6 +126,14 @@
|
|||
revision = "8b15f938ed215522a37275106e847f6f0be85fe8"
|
||||
version = "v1.15.23"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:03cfacdc6bfd46007c15786c1ece3fa074f89e5193a292f0f26d9e98c99c7cc2"
|
||||
name = "github.com/cloudflare/cloudflare-go"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "1f9007fbecae20711133c60519338c41cef1ffb4"
|
||||
version = "v0.8.5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2a7013a7e8cfec93dd725f95ea0c4b390d7d71f8a8bc3dbde05cfc9524ba5ea8"
|
||||
|
@ -483,6 +491,14 @@
|
|||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:c9e7a4b4d47c0ed205d257648b0e5b0440880cb728506e318f8ac7cd36270bc4"
|
||||
name = "golang.org/x/time"
|
||||
packages = ["rate"]
|
||||
pruneopts = "NUT"
|
||||
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:90f61cd4297f7f4ce75f142744673ecdafd9023668cd24730f14033f265e394a"
|
||||
|
@ -574,6 +590,7 @@
|
|||
"github.com/aws/aws-sdk-go/aws/session",
|
||||
"github.com/aws/aws-sdk-go/service/lightsail",
|
||||
"github.com/aws/aws-sdk-go/service/route53",
|
||||
"github.com/cloudflare/cloudflare-go",
|
||||
"github.com/cpu/goacmedns",
|
||||
"github.com/decker502/dnspod-go",
|
||||
"github.com/dnsimple/dnsimple-go/dnsimple",
|
||||
|
|
|
@ -53,7 +53,7 @@ func TestPEMCertExpiration(t *testing.T) {
|
|||
|
||||
// Some random string should return an error.
|
||||
ctime, err := GetPEMCertExpiration(buf.Bytes())
|
||||
assert.Errorf(t, err, "Expected getCertExpiration to return an error for garbage string but returned %v", ctime)
|
||||
require.Errorf(t, err, "Expected getCertExpiration to return an error for garbage string but returned %v", ctime)
|
||||
|
||||
// A DER encoded certificate should return an error.
|
||||
_, err = GetPEMCertExpiration(certBytes)
|
||||
|
|
|
@ -1,212 +0,0 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/xenolf/lego/acme"
|
||||
)
|
||||
|
||||
// defaultBaseURL represents the API endpoint to call.
|
||||
const defaultBaseURL = "https://api.cloudflare.com/client/v4"
|
||||
|
||||
// APIError contains error details for failed requests
|
||||
type APIError struct {
|
||||
Code int `json:"code,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
ErrorChain []APIError `json:"error_chain,omitempty"`
|
||||
}
|
||||
|
||||
// APIResponse represents a response from Cloudflare API
|
||||
type APIResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []*APIError `json:"errors"`
|
||||
Result json.RawMessage `json:"result"`
|
||||
}
|
||||
|
||||
// TxtRecord represents a Cloudflare DNS record
|
||||
type TxtRecord struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Content string `json:"content"`
|
||||
ID string `json:"id,omitempty"`
|
||||
TTL int `json:"ttl,omitempty"`
|
||||
ZoneID string `json:"zone_id,omitempty"`
|
||||
}
|
||||
|
||||
// HostedZone represents a Cloudflare DNS zone
|
||||
type HostedZone struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Client Cloudflare API client
|
||||
type Client struct {
|
||||
authEmail string
|
||||
authKey string
|
||||
BaseURL string
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// NewClient create a Cloudflare API client
|
||||
func NewClient(authEmail string, authKey string) (*Client, error) {
|
||||
if authEmail == "" {
|
||||
return nil, errors.New("cloudflare: some credentials information are missing: email")
|
||||
}
|
||||
|
||||
if authKey == "" {
|
||||
return nil, errors.New("cloudflare: some credentials information are missing: key")
|
||||
}
|
||||
|
||||
return &Client{
|
||||
authEmail: authEmail,
|
||||
authKey: authKey,
|
||||
BaseURL: defaultBaseURL,
|
||||
HTTPClient: http.DefaultClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetHostedZoneID get hosted zone
|
||||
func (c *Client) GetHostedZoneID(fqdn string) (string, error) {
|
||||
authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
result, err := c.doRequest(http.MethodGet, "/zones?name="+acme.UnFqdn(authZone), nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var hostedZone []HostedZone
|
||||
err = json.Unmarshal(result, &hostedZone)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cloudflare: HostedZone unmarshaling error: %v", err)
|
||||
}
|
||||
|
||||
count := len(hostedZone)
|
||||
if count == 0 {
|
||||
return "", fmt.Errorf("cloudflare: zone %s not found for domain %s", authZone, fqdn)
|
||||
} else if count > 1 {
|
||||
return "", fmt.Errorf("cloudflare: zone %s cannot be find for domain %s: too many hostedZone: %v", authZone, fqdn, hostedZone)
|
||||
}
|
||||
|
||||
return hostedZone[0].ID, nil
|
||||
}
|
||||
|
||||
// FindTxtRecord Find a TXT record
|
||||
func (c *Client) FindTxtRecord(zoneID, fqdn string) (*TxtRecord, error) {
|
||||
result, err := c.doRequest(
|
||||
http.MethodGet,
|
||||
fmt.Sprintf("/zones/%s/dns_records?per_page=1000&type=TXT&name=%s", zoneID, acme.UnFqdn(fqdn)),
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var records []TxtRecord
|
||||
err = json.Unmarshal(result, &records)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cloudflare: record unmarshaling error: %v", err)
|
||||
}
|
||||
|
||||
for _, rec := range records {
|
||||
fmt.Println(rec.Name, acme.UnFqdn(fqdn))
|
||||
if rec.Name == acme.UnFqdn(fqdn) {
|
||||
return &rec, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("cloudflare: no existing record found for %s", fqdn)
|
||||
}
|
||||
|
||||
// AddTxtRecord add a TXT record
|
||||
func (c *Client) AddTxtRecord(fqdn string, record TxtRecord) error {
|
||||
zoneID, err := c.GetHostedZoneID(fqdn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
body, err := json.Marshal(record)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: record marshaling error: %v", err)
|
||||
}
|
||||
|
||||
_, err = c.doRequest(http.MethodPost, fmt.Sprintf("/zones/%s/dns_records", zoneID), bytes.NewReader(body))
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveTxtRecord Remove a TXT record
|
||||
func (c *Client) RemoveTxtRecord(fqdn string) error {
|
||||
zoneID, err := c.GetHostedZoneID(fqdn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
record, err := c.FindTxtRecord(zoneID, fqdn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = c.doRequest(http.MethodDelete, fmt.Sprintf("/zones/%s/dns_records/%s", record.ZoneID, record.ID), nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) doRequest(method, uri string, body io.Reader) (json.RawMessage, error) {
|
||||
req, err := http.NewRequest(method, fmt.Sprintf("%s%s", c.BaseURL, uri), body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("X-Auth-Email", c.authEmail)
|
||||
req.Header.Set("X-Auth-Key", c.authKey)
|
||||
|
||||
resp, err := c.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cloudflare: error querying API: %v", err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cloudflare: %s", toUnreadableBodyMessage(req, content))
|
||||
}
|
||||
|
||||
var r APIResponse
|
||||
err = json.Unmarshal(content, &r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cloudflare: APIResponse unmarshaling error: %v: %s", err, toUnreadableBodyMessage(req, content))
|
||||
}
|
||||
|
||||
if !r.Success {
|
||||
if len(r.Errors) > 0 {
|
||||
return nil, fmt.Errorf("cloudflare: error \n%s", toError(r))
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("cloudflare: %s", toUnreadableBodyMessage(req, content))
|
||||
}
|
||||
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
func toUnreadableBodyMessage(req *http.Request, rawBody []byte) string {
|
||||
return fmt.Sprintf("the request %s sent a response with a body which is an invalid format: %q", req.URL, string(rawBody))
|
||||
}
|
||||
|
||||
func toError(r APIResponse) error {
|
||||
errStr := ""
|
||||
for _, apiErr := range r.Errors {
|
||||
errStr += fmt.Sprintf("\t Error: %d: %s", apiErr.Code, apiErr.Message)
|
||||
for _, chainErr := range apiErr.ErrorChain {
|
||||
errStr += fmt.Sprintf("<- %d: %s", chainErr.Code, chainErr.Message)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("cloudflare: error \n%s", errStr)
|
||||
}
|
|
@ -1,192 +0,0 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func handlerMock(method string, response *APIResponse, data interface{}) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != method {
|
||||
content, err := json.Marshal(APIResponse{
|
||||
Success: false,
|
||||
Errors: []*APIError{
|
||||
{
|
||||
Code: 666,
|
||||
Message: fmt.Sprintf("invalid method: got %s want %s", req.Method, method),
|
||||
ErrorChain: nil,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Error(rw, string(content), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
response.Result = jsonData
|
||||
|
||||
content, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = rw.Write(content)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestClient_GetHostedZoneID(t *testing.T) {
|
||||
type result struct {
|
||||
zoneID string
|
||||
error bool
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
fqdn string
|
||||
response *APIResponse
|
||||
data []HostedZone
|
||||
expected result
|
||||
}{
|
||||
{
|
||||
desc: "zone found",
|
||||
fqdn: "_acme-challenge.foo.com.",
|
||||
response: &APIResponse{Success: true},
|
||||
data: []HostedZone{
|
||||
{
|
||||
ID: "A",
|
||||
Name: "ZONE_A",
|
||||
},
|
||||
},
|
||||
expected: result{zoneID: "A"},
|
||||
},
|
||||
{
|
||||
desc: "no many zones",
|
||||
fqdn: "_acme-challenge.foo.com.",
|
||||
response: &APIResponse{Success: true},
|
||||
data: []HostedZone{
|
||||
{
|
||||
ID: "A",
|
||||
Name: "ZONE_A",
|
||||
},
|
||||
{
|
||||
ID: "B",
|
||||
Name: "ZONE_B",
|
||||
},
|
||||
},
|
||||
expected: result{error: true},
|
||||
},
|
||||
{
|
||||
desc: "no zone found",
|
||||
fqdn: "_acme-challenge.foo.com.",
|
||||
response: &APIResponse{Success: true},
|
||||
expected: result{error: true},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
server := httptest.NewServer(handlerMock(http.MethodGet, test.response, test.data))
|
||||
|
||||
client, _ := NewClient("authEmail", "authKey")
|
||||
client.BaseURL = server.URL
|
||||
|
||||
zoneID, err := client.GetHostedZoneID(test.fqdn)
|
||||
|
||||
if test.expected.error {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.expected.zoneID, zoneID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_FindTxtRecord(t *testing.T) {
|
||||
type result struct {
|
||||
txtRecord *TxtRecord
|
||||
error bool
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
fqdn string
|
||||
zoneID string
|
||||
response *APIResponse
|
||||
data []TxtRecord
|
||||
expected result
|
||||
}{
|
||||
{
|
||||
desc: "TXT record found",
|
||||
fqdn: "_acme-challenge.foo.com.",
|
||||
zoneID: "ZONE_A",
|
||||
response: &APIResponse{Success: true},
|
||||
data: []TxtRecord{
|
||||
{
|
||||
Name: "_acme-challenge.foo.com",
|
||||
Type: "TXT",
|
||||
Content: "txtTXTtxtTXTtxtTXTtxtTXT",
|
||||
ID: "A",
|
||||
TTL: 50,
|
||||
ZoneID: "ZONE_A",
|
||||
},
|
||||
},
|
||||
expected: result{
|
||||
txtRecord: &TxtRecord{
|
||||
Name: "_acme-challenge.foo.com",
|
||||
Type: "TXT",
|
||||
Content: "txtTXTtxtTXTtxtTXTtxtTXT",
|
||||
ID: "A",
|
||||
TTL: 50,
|
||||
ZoneID: "ZONE_A",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TXT record not found",
|
||||
fqdn: "_acme-challenge.foo.com.",
|
||||
zoneID: "ZONE_A",
|
||||
response: &APIResponse{Success: true},
|
||||
expected: result{error: true},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
server := httptest.NewServer(handlerMock(http.MethodGet, test.response, test.data))
|
||||
|
||||
client, _ := NewClient("authEmail", "authKey")
|
||||
client.BaseURL = server.URL
|
||||
|
||||
txtRecord, err := client.FindTxtRecord(test.zoneID, test.fqdn)
|
||||
|
||||
if test.expected.error {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.expected.txtRecord, txtRecord)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -8,12 +8,18 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflare-go"
|
||||
"github.com/xenolf/lego/acme"
|
||||
"github.com/xenolf/lego/log"
|
||||
"github.com/xenolf/lego/platform/config/env"
|
||||
)
|
||||
|
||||
// CloudFlareAPIURL represents the API endpoint to call.
|
||||
const CloudFlareAPIURL = defaultBaseURL // Deprecated
|
||||
const CloudFlareAPIURL = "https://api.cloudflare.com/client/v4" // Deprecated
|
||||
|
||||
const (
|
||||
minTTL = 120
|
||||
)
|
||||
|
||||
// Config is used to configure the creation of the DNSProvider
|
||||
type Config struct {
|
||||
|
@ -28,7 +34,7 @@ type Config struct {
|
|||
// NewDefaultConfig returns a default configuration for the DNSProvider
|
||||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
TTL: env.GetOrDefaultInt("CLOUDFLARE_TTL", 120),
|
||||
TTL: env.GetOrDefaultInt("CLOUDFLARE_TTL", minTTL),
|
||||
PropagationTimeout: env.GetOrDefaultSecond("CLOUDFLARE_PROPAGATION_TIMEOUT", 2*time.Minute),
|
||||
PollingInterval: env.GetOrDefaultSecond("CLOUDFLARE_POLLING_INTERVAL", 2*time.Second),
|
||||
HTTPClient: &http.Client{
|
||||
|
@ -39,7 +45,7 @@ func NewDefaultConfig() *Config {
|
|||
|
||||
// DNSProvider is an implementation of the acme.ChallengeProvider interface
|
||||
type DNSProvider struct {
|
||||
client *Client
|
||||
client *cloudflare.API
|
||||
config *Config
|
||||
}
|
||||
|
||||
|
@ -78,20 +84,19 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, errors.New("cloudflare: the configuration of the DNS provider is nil")
|
||||
}
|
||||
|
||||
client, err := NewClient(config.AuthEmail, config.AuthKey)
|
||||
if config.TTL < minTTL {
|
||||
config.TTL = minTTL
|
||||
}
|
||||
|
||||
client, err := cloudflare.New(config.AuthKey, config.AuthEmail, cloudflare.HTTPClient(config.HTTPClient))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.HTTPClient = config.HTTPClient
|
||||
|
||||
// TODO: must be remove. keep only for compatibility reason.
|
||||
client.BaseURL = CloudFlareAPIURL
|
||||
|
||||
return &DNSProvider{
|
||||
client: client,
|
||||
config: config,
|
||||
}, nil
|
||||
return &DNSProvider{client: client, config: config}, nil
|
||||
}
|
||||
|
||||
// Timeout returns the timeout and interval to use when checking for DNS propagation.
|
||||
|
@ -104,19 +109,67 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
|||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
rec := TxtRecord{
|
||||
authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: %v", err)
|
||||
}
|
||||
|
||||
zoneID, err := d.client.ZoneIDByName(authZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: failed to find zone %s: %v", authZone, err)
|
||||
}
|
||||
|
||||
dnsRecord := cloudflare.DNSRecord{
|
||||
Type: "TXT",
|
||||
Name: acme.UnFqdn(fqdn),
|
||||
Content: value,
|
||||
TTL: d.config.TTL,
|
||||
}
|
||||
|
||||
return d.client.AddTxtRecord(fqdn, rec)
|
||||
response, _ := d.client.CreateDNSRecord(zoneID, dnsRecord)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: failed to create TXT record: %v", err)
|
||||
}
|
||||
|
||||
if !response.Success {
|
||||
return fmt.Errorf("cloudflare: failed to create TXT record: %+v %+v", response.Errors, response.Messages)
|
||||
}
|
||||
|
||||
log.Infof("cloudflare: new record for %s, ID %s", domain, response.Result.ID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CleanUp removes the TXT record matching the specified parameters
|
||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
|
||||
|
||||
return d.client.RemoveTxtRecord(fqdn)
|
||||
authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: %v", err)
|
||||
}
|
||||
|
||||
zoneID, err := d.client.ZoneIDByName(authZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: failed to find zone %s: %v", authZone, err)
|
||||
}
|
||||
|
||||
dnsRecord := cloudflare.DNSRecord{
|
||||
Type: "TXT",
|
||||
Name: acme.UnFqdn(fqdn),
|
||||
}
|
||||
|
||||
records, err := d.client.DNSRecords(zoneID, dnsRecord)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cloudflare: failed to find TXT records: %v", err)
|
||||
}
|
||||
|
||||
for _, record := range records {
|
||||
err = d.client.DeleteDNSRecord(zoneID, record.ID)
|
||||
if err != nil {
|
||||
log.Printf("cloudflare: failed to delete TXT record: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -29,44 +30,116 @@ func restoreEnv() {
|
|||
os.Setenv("CLOUDFLARE_API_KEY", cflareAPIKey)
|
||||
}
|
||||
|
||||
func TestNewDNSProviderValid(t *testing.T) {
|
||||
os.Setenv("CLOUDFLARE_EMAIL", "")
|
||||
os.Setenv("CLOUDFLARE_API_KEY", "")
|
||||
defer restoreEnv()
|
||||
func TestNewDNSProvider(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
envVars map[string]string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "success",
|
||||
envVars: map[string]string{
|
||||
"CLOUDFLARE_EMAIL": "test@example.com",
|
||||
"CLOUDFLARE_API_KEY": "123",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "missing credentials",
|
||||
envVars: map[string]string{
|
||||
"CLOUDFLARE_EMAIL": "",
|
||||
"CLOUDFLARE_API_KEY": "",
|
||||
},
|
||||
expected: "cloudflare: some credentials information are missing: CLOUDFLARE_EMAIL,CLOUDFLARE_API_KEY",
|
||||
},
|
||||
{
|
||||
desc: "missing email",
|
||||
envVars: map[string]string{
|
||||
"CLOUDFLARE_EMAIL": "",
|
||||
"CLOUDFLARE_API_KEY": "key",
|
||||
},
|
||||
expected: "cloudflare: some credentials information are missing: CLOUDFLARE_EMAIL",
|
||||
},
|
||||
{
|
||||
desc: "missing api key",
|
||||
envVars: map[string]string{
|
||||
"CLOUDFLARE_EMAIL": "awesome@possum.com",
|
||||
"CLOUDFLARE_API_KEY": "",
|
||||
},
|
||||
expected: "cloudflare: some credentials information are missing: CLOUDFLARE_API_KEY",
|
||||
},
|
||||
}
|
||||
|
||||
config := NewDefaultConfig()
|
||||
config.AuthEmail = "123"
|
||||
config.AuthKey = "123"
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer restoreEnv()
|
||||
for key, value := range test.envVars {
|
||||
if len(value) == 0 {
|
||||
os.Unsetenv(key)
|
||||
} else {
|
||||
os.Setenv(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := NewDNSProviderConfig(config)
|
||||
p, err := NewDNSProvider()
|
||||
|
||||
assert.NoError(t, err)
|
||||
if len(test.expected) == 0 {
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, p)
|
||||
} else {
|
||||
require.EqualError(t, err, test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDNSProviderValidEnv(t *testing.T) {
|
||||
defer restoreEnv()
|
||||
os.Setenv("CLOUDFLARE_EMAIL", "test@example.com")
|
||||
os.Setenv("CLOUDFLARE_API_KEY", "123")
|
||||
func TestNewDNSProviderConfig(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
authEmail string
|
||||
authKey string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "success",
|
||||
authEmail: "test@example.com",
|
||||
authKey: "123",
|
||||
},
|
||||
{
|
||||
desc: "missing credentials",
|
||||
expected: "invalid credentials: key & email must not be empty",
|
||||
},
|
||||
{
|
||||
desc: "missing email",
|
||||
authKey: "123",
|
||||
expected: "invalid credentials: key & email must not be empty",
|
||||
},
|
||||
{
|
||||
desc: "missing api key",
|
||||
authEmail: "test@example.com",
|
||||
expected: "invalid credentials: key & email must not be empty",
|
||||
},
|
||||
}
|
||||
|
||||
_, err := NewDNSProvider()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer restoreEnv()
|
||||
os.Unsetenv("CLOUDFLARE_EMAIL")
|
||||
os.Unsetenv("CLOUDFLARE_API_KEY")
|
||||
|
||||
func TestNewDNSProviderMissingCredErr(t *testing.T) {
|
||||
defer restoreEnv()
|
||||
os.Setenv("CLOUDFLARE_EMAIL", "")
|
||||
os.Setenv("CLOUDFLARE_API_KEY", "")
|
||||
config := NewDefaultConfig()
|
||||
config.AuthEmail = test.authEmail
|
||||
config.AuthKey = test.authKey
|
||||
|
||||
_, err := NewDNSProvider()
|
||||
assert.EqualError(t, err, "cloudflare: some credentials information are missing: CLOUDFLARE_EMAIL,CLOUDFLARE_API_KEY")
|
||||
}
|
||||
p, err := NewDNSProviderConfig(config)
|
||||
|
||||
func TestNewDNSProviderMissingCredErrSingle(t *testing.T) {
|
||||
defer restoreEnv()
|
||||
os.Setenv("CLOUDFLARE_EMAIL", "awesome@possum.com")
|
||||
|
||||
_, err := NewDNSProvider()
|
||||
assert.EqualError(t, err, "cloudflare: some credentials information are missing: CLOUDFLARE_API_KEY")
|
||||
if len(test.expected) == 0 {
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, p)
|
||||
} else {
|
||||
require.EqualError(t, err, test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudFlarePresent(t *testing.T) {
|
||||
|
@ -79,10 +152,10 @@ func TestCloudFlarePresent(t *testing.T) {
|
|||
config.AuthKey = cflareAPIKey
|
||||
|
||||
provider, err := NewDNSProviderConfig(config)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = provider.Present(cflareDomain, "", "123d==")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCloudFlareCleanUp(t *testing.T) {
|
||||
|
@ -97,8 +170,8 @@ func TestCloudFlareCleanUp(t *testing.T) {
|
|||
config.AuthKey = cflareAPIKey
|
||||
|
||||
provider, err := NewDNSProviderConfig(config)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = provider.CleanUp(cflareDomain, "", "123d==")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
26
vendor/github.com/cloudflare/cloudflare-go/LICENSE
generated
vendored
Normal file
26
vendor/github.com/cloudflare/cloudflare-go/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
Copyright (c) 2015-2016, Cloudflare. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. 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.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
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.
|
318
vendor/github.com/cloudflare/cloudflare-go/cloudflare.go
generated
vendored
Normal file
318
vendor/github.com/cloudflare/cloudflare-go/cloudflare.go
generated
vendored
Normal file
|
@ -0,0 +1,318 @@
|
|||
// Package cloudflare implements the Cloudflare v4 API.
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
const apiURL = "https://api.cloudflare.com/client/v4"
|
||||
const (
|
||||
// AuthKeyEmail specifies that we should authenticate with API key and email address
|
||||
AuthKeyEmail = 1 << iota
|
||||
// AuthUserService specifies that we should authenticate with a User-Service key
|
||||
AuthUserService
|
||||
)
|
||||
|
||||
// API holds the configuration for the current API client. A client should not
|
||||
// be modified concurrently.
|
||||
type API struct {
|
||||
APIKey string
|
||||
APIEmail string
|
||||
APIUserServiceKey string
|
||||
BaseURL string
|
||||
organizationID string
|
||||
headers http.Header
|
||||
httpClient *http.Client
|
||||
authType int
|
||||
rateLimiter *rate.Limiter
|
||||
retryPolicy RetryPolicy
|
||||
logger Logger
|
||||
}
|
||||
|
||||
// New creates a new Cloudflare v4 API client.
|
||||
func New(key, email string, opts ...Option) (*API, error) {
|
||||
if key == "" || email == "" {
|
||||
return nil, errors.New(errEmptyCredentials)
|
||||
}
|
||||
|
||||
silentLogger := log.New(ioutil.Discard, "", log.LstdFlags)
|
||||
|
||||
api := &API{
|
||||
APIKey: key,
|
||||
APIEmail: email,
|
||||
BaseURL: apiURL,
|
||||
headers: make(http.Header),
|
||||
authType: AuthKeyEmail,
|
||||
rateLimiter: rate.NewLimiter(rate.Limit(4), 1), // 4rps equates to default api limit (1200 req/5 min)
|
||||
retryPolicy: RetryPolicy{
|
||||
MaxRetries: 3,
|
||||
MinRetryDelay: time.Duration(1) * time.Second,
|
||||
MaxRetryDelay: time.Duration(30) * time.Second,
|
||||
},
|
||||
logger: silentLogger,
|
||||
}
|
||||
|
||||
err := api.parseOptions(opts...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "options parsing failed")
|
||||
}
|
||||
|
||||
// Fall back to http.DefaultClient if the package user does not provide
|
||||
// their own.
|
||||
if api.httpClient == nil {
|
||||
api.httpClient = http.DefaultClient
|
||||
}
|
||||
|
||||
return api, nil
|
||||
}
|
||||
|
||||
// SetAuthType sets the authentication method (AuthyKeyEmail or AuthUserService).
|
||||
func (api *API) SetAuthType(authType int) {
|
||||
api.authType = authType
|
||||
}
|
||||
|
||||
// ZoneIDByName retrieves a zone's ID from the name.
|
||||
func (api *API) ZoneIDByName(zoneName string) (string, error) {
|
||||
res, err := api.ListZones(zoneName)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "ListZones command failed")
|
||||
}
|
||||
for _, zone := range res {
|
||||
if zone.Name == zoneName {
|
||||
return zone.ID, nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("Zone could not be found")
|
||||
}
|
||||
|
||||
// makeRequest makes a HTTP request and returns the body as a byte slice,
|
||||
// closing it before returnng. params will be serialized to JSON.
|
||||
func (api *API) makeRequest(method, uri string, params interface{}) ([]byte, error) {
|
||||
return api.makeRequestWithAuthType(method, uri, params, api.authType)
|
||||
}
|
||||
|
||||
func (api *API) makeRequestWithAuthType(method, uri string, params interface{}, authType int) ([]byte, error) {
|
||||
// Replace nil with a JSON object if needed
|
||||
var jsonBody []byte
|
||||
var err error
|
||||
if params != nil {
|
||||
jsonBody, err = json.Marshal(params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error marshalling params to JSON")
|
||||
}
|
||||
} else {
|
||||
jsonBody = nil
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
var respErr error
|
||||
var reqBody io.Reader
|
||||
var respBody []byte
|
||||
for i := 0; i <= api.retryPolicy.MaxRetries; i++ {
|
||||
if jsonBody != nil {
|
||||
reqBody = bytes.NewReader(jsonBody)
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
// expect the backoff introduced here on errored requests to dominate the effect of rate limiting
|
||||
// dont need a random component here as the rate limiter should do something similar
|
||||
// nb time duration could truncate an arbitrary float. Since our inputs are all ints, we should be ok
|
||||
sleepDuration := time.Duration(math.Pow(2, float64(i-1)) * float64(api.retryPolicy.MinRetryDelay))
|
||||
|
||||
if sleepDuration > api.retryPolicy.MaxRetryDelay {
|
||||
sleepDuration = api.retryPolicy.MaxRetryDelay
|
||||
}
|
||||
// useful to do some simple logging here, maybe introduce levels later
|
||||
api.logger.Printf("Sleeping %s before retry attempt number %d for request %s %s", sleepDuration.String(), i, method, uri)
|
||||
time.Sleep(sleepDuration)
|
||||
}
|
||||
api.rateLimiter.Wait(context.TODO())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error caused by request rate limiting")
|
||||
}
|
||||
resp, respErr = api.request(method, uri, reqBody, authType)
|
||||
|
||||
// retry if the server is rate limiting us or if it failed
|
||||
// assumes server operations are rolled back on failure
|
||||
if respErr != nil || resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode >= 500 {
|
||||
// if we got a valid http response, try to read body so we can reuse the connection
|
||||
// see https://golang.org/pkg/net/http/#Client.Do
|
||||
if respErr == nil {
|
||||
respBody, err = ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
|
||||
respErr = errors.Wrap(err, "could not read response body")
|
||||
|
||||
api.logger.Printf("Request: %s %s got an error response %d: %s\n", method, uri, resp.StatusCode,
|
||||
strings.Replace(strings.Replace(string(respBody), "\n", "", -1), "\t", "", -1))
|
||||
} else {
|
||||
api.logger.Printf("Error performing request: %s %s : %s \n", method, uri, respErr.Error())
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
respBody, err = ioutil.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read response body")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if respErr != nil {
|
||||
return nil, respErr
|
||||
}
|
||||
|
||||
switch {
|
||||
case resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices:
|
||||
case resp.StatusCode == http.StatusUnauthorized:
|
||||
return nil, errors.Errorf("HTTP status %d: invalid credentials", resp.StatusCode)
|
||||
case resp.StatusCode == http.StatusForbidden:
|
||||
return nil, errors.Errorf("HTTP status %d: insufficient permissions", resp.StatusCode)
|
||||
case resp.StatusCode == http.StatusServiceUnavailable,
|
||||
resp.StatusCode == http.StatusBadGateway,
|
||||
resp.StatusCode == http.StatusGatewayTimeout,
|
||||
resp.StatusCode == 522,
|
||||
resp.StatusCode == 523,
|
||||
resp.StatusCode == 524:
|
||||
return nil, errors.Errorf("HTTP status %d: service failure", resp.StatusCode)
|
||||
default:
|
||||
var s string
|
||||
if respBody != nil {
|
||||
s = string(respBody)
|
||||
}
|
||||
return nil, errors.Errorf("HTTP status %d: content %q", resp.StatusCode, s)
|
||||
}
|
||||
|
||||
return respBody, nil
|
||||
}
|
||||
|
||||
// request makes a HTTP request to the given API endpoint, returning the raw
|
||||
// *http.Response, or an error if one occurred. The caller is responsible for
|
||||
// closing the response body.
|
||||
func (api *API) request(method, uri string, reqBody io.Reader, authType int) (*http.Response, error) {
|
||||
req, err := http.NewRequest(method, api.BaseURL+uri, reqBody)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "HTTP request creation failed")
|
||||
}
|
||||
|
||||
// Apply any user-defined headers first.
|
||||
req.Header = cloneHeader(api.headers)
|
||||
if authType&AuthKeyEmail != 0 {
|
||||
req.Header.Set("X-Auth-Key", api.APIKey)
|
||||
req.Header.Set("X-Auth-Email", api.APIEmail)
|
||||
}
|
||||
if authType&AuthUserService != 0 {
|
||||
req.Header.Set("X-Auth-User-Service-Key", api.APIUserServiceKey)
|
||||
}
|
||||
|
||||
if req.Header.Get("Content-Type") == "" {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
resp, err := api.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "HTTP request failed")
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Returns the base URL to use for API endpoints that exist for both accounts and organizations.
|
||||
// If an Organization option was used when creating the API instance, returns the org URL.
|
||||
//
|
||||
// accountBase is the base URL for endpoints referring to the current user. It exists as a
|
||||
// parameter because it is not consistent across APIs.
|
||||
func (api *API) userBaseURL(accountBase string) string {
|
||||
if api.organizationID != "" {
|
||||
return "/organizations/" + api.organizationID
|
||||
}
|
||||
return accountBase
|
||||
}
|
||||
|
||||
// cloneHeader returns a shallow copy of the header.
|
||||
// copied from https://godoc.org/github.com/golang/gddo/httputil/header#Copy
|
||||
func cloneHeader(header http.Header) http.Header {
|
||||
h := make(http.Header)
|
||||
for k, vs := range header {
|
||||
h[k] = vs
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// ResponseInfo contains a code and message returned by the API as errors or
|
||||
// informational messages inside the response.
|
||||
type ResponseInfo struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Response is a template. There will also be a result struct. There will be a
|
||||
// unique response type for each response, which will include this type.
|
||||
type Response struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []ResponseInfo `json:"errors"`
|
||||
Messages []ResponseInfo `json:"messages"`
|
||||
}
|
||||
|
||||
// ResultInfo contains metadata about the Response.
|
||||
type ResultInfo struct {
|
||||
Page int `json:"page"`
|
||||
PerPage int `json:"per_page"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
Count int `json:"count"`
|
||||
Total int `json:"total_count"`
|
||||
}
|
||||
|
||||
// RawResponse keeps the result as JSON form
|
||||
type RawResponse struct {
|
||||
Response
|
||||
Result json.RawMessage `json:"result"`
|
||||
}
|
||||
|
||||
// Raw makes a HTTP request with user provided params and returns the
|
||||
// result as untouched JSON.
|
||||
func (api *API) Raw(method, endpoint string, data interface{}) (json.RawMessage, error) {
|
||||
res, err := api.makeRequest(method, endpoint, data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
var r RawResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// PaginationOptions can be passed to a list request to configure paging
|
||||
// These values will be defaulted if omitted, and PerPage has min/max limits set by resource
|
||||
type PaginationOptions struct {
|
||||
Page int `json:"page,omitempty"`
|
||||
PerPage int `json:"per_page,omitempty"`
|
||||
}
|
||||
|
||||
// RetryPolicy specifies number of retries and min/max retry delays
|
||||
// This config is used when the client exponentially backs off after errored requests
|
||||
type RetryPolicy struct {
|
||||
MaxRetries int
|
||||
MinRetryDelay time.Duration
|
||||
MaxRetryDelay time.Duration
|
||||
}
|
||||
|
||||
// Logger defines the interface this library needs to use logging
|
||||
// This is a subset of the methods implemented in the log package
|
||||
type Logger interface {
|
||||
Printf(format string, v ...interface{})
|
||||
}
|
29
vendor/github.com/cloudflare/cloudflare-go/cpage.go
generated
vendored
Normal file
29
vendor/github.com/cloudflare/cloudflare-go/cpage.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
package cloudflare
|
||||
|
||||
import "time"
|
||||
|
||||
// CustomPage represents a custom page configuration.
|
||||
type CustomPage struct {
|
||||
CreatedOn string `json:"created_on"`
|
||||
ModifiedOn time.Time `json:"modified_on"`
|
||||
URL string `json:"url"`
|
||||
State string `json:"state"`
|
||||
RequiredTokens []string `json:"required_tokens"`
|
||||
PreviewTarget string `json:"preview_target"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// CustomPageResponse represents the response from the custom pages endpoint.
|
||||
type CustomPageResponse struct {
|
||||
Response
|
||||
Result []CustomPage `json:"result"`
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#custom-pages-for-a-zone-available-custom-pages
|
||||
// GET /zones/:zone_identifier/custom_pages
|
||||
|
||||
// https://api.cloudflare.com/#custom-pages-for-a-zone-custom-page-details
|
||||
// GET /zones/:zone_identifier/custom_pages/:identifier
|
||||
|
||||
// https://api.cloudflare.com/#custom-pages-for-a-zone-update-custom-page-url
|
||||
// PUT /zones/:zone_identifier/custom_pages/:identifier
|
149
vendor/github.com/cloudflare/cloudflare-go/custom_hostname.go
generated
vendored
Normal file
149
vendor/github.com/cloudflare/cloudflare-go/custom_hostname.go
generated
vendored
Normal file
|
@ -0,0 +1,149 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// CustomHostnameSSL represents the SSL section in a given custom hostname.
|
||||
type CustomHostnameSSL struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
Method string `json:"method,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
CnameTarget string `json:"cname_target,omitempty"`
|
||||
CnameName string `json:"cname_name,omitempty"`
|
||||
}
|
||||
|
||||
// CustomMetadata defines custom metadata for the hostname. This requires logic to be implemented by Cloudflare to act on the data provided.
|
||||
type CustomMetadata map[string]interface{}
|
||||
|
||||
// CustomHostname represents a custom hostname in a zone.
|
||||
type CustomHostname struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Hostname string `json:"hostname,omitempty"`
|
||||
SSL CustomHostnameSSL `json:"ssl,omitempty"`
|
||||
CustomMetadata CustomMetadata `json:"custom_metadata,omitempty"`
|
||||
}
|
||||
|
||||
// CustomHostNameResponse represents a response from the Custom Hostnames endpoints.
|
||||
type CustomHostnameResponse struct {
|
||||
Result CustomHostname `json:"result"`
|
||||
Response
|
||||
}
|
||||
|
||||
// CustomHostnameListResponse represents a response from the Custom Hostnames endpoints.
|
||||
type CustomHostnameListResponse struct {
|
||||
Result []CustomHostname `json:"result"`
|
||||
Response
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// Modify SSL configuration for the given custom hostname in the given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#custom-hostname-for-a-zone-update-custom-hostname-configuration
|
||||
func (api *API) UpdateCustomHostnameSSL(zoneID string, customHostnameID string, ssl CustomHostnameSSL) (CustomHostname, error) {
|
||||
return CustomHostname{}, errors.New("Not implemented")
|
||||
}
|
||||
|
||||
// Delete a custom hostname (and any issued SSL certificates)
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#custom-hostname-for-a-zone-delete-a-custom-hostname-and-any-issued-ssl-certificates-
|
||||
func (api *API) DeleteCustomHostname(zoneID string, customHostnameID string) error {
|
||||
uri := "/zones/" + zoneID + "/custom_hostnames/" + customHostnameID
|
||||
res, err := api.makeRequest("DELETE", uri, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
var response *CustomHostnameResponse
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateCustomHostname creates a new custom hostname and requests that an SSL certificate be issued for it.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#custom-hostname-for-a-zone-create-custom-hostname
|
||||
func (api *API) CreateCustomHostname(zoneID string, ch CustomHostname) (*CustomHostnameResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/custom_hostnames"
|
||||
res, err := api.makeRequest("POST", uri, ch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
var response *CustomHostnameResponse
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// CustomHostnames fetches custom hostnames for the given zone,
|
||||
// by applying filter.Hostname if not empty and scoping the result to page'th 50 items.
|
||||
//
|
||||
// The returned ResultInfo can be used to implement pagination.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#custom-hostname-for-a-zone-list-custom-hostnames
|
||||
func (api *API) CustomHostnames(zoneID string, page int, filter CustomHostname) ([]CustomHostname, ResultInfo, error) {
|
||||
v := url.Values{}
|
||||
v.Set("per_page", "50")
|
||||
v.Set("page", strconv.Itoa(page))
|
||||
if filter.Hostname != "" {
|
||||
v.Set("hostname", filter.Hostname)
|
||||
}
|
||||
query := "?" + v.Encode()
|
||||
|
||||
uri := "/zones/" + zoneID + "/custom_hostnames" + query
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return []CustomHostname{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var customHostnameListResponse CustomHostnameListResponse
|
||||
err = json.Unmarshal(res, &customHostnameListResponse)
|
||||
if err != nil {
|
||||
return []CustomHostname{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
return customHostnameListResponse.Result, customHostnameListResponse.ResultInfo, nil
|
||||
}
|
||||
|
||||
// CustomHostname inspects the given custom hostname in the given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#custom-hostname-for-a-zone-custom-hostname-configuration-details
|
||||
func (api *API) CustomHostname(zoneID string, customHostnameID string) (CustomHostname, error) {
|
||||
uri := "/zones/" + zoneID + "/custom_hostnames/" + customHostnameID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return CustomHostname{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
var response CustomHostnameResponse
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return CustomHostname{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response.Result, nil
|
||||
}
|
||||
|
||||
// CustomHostnameIDByName retrieves the ID for the given hostname in the given zone.
|
||||
func (api *API) CustomHostnameIDByName(zoneID string, hostname string) (string, error) {
|
||||
customHostnames, _, err := api.CustomHostnames(zoneID, 1, CustomHostname{Hostname: hostname})
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "CustomHostnames command failed")
|
||||
}
|
||||
for _, ch := range customHostnames {
|
||||
if ch.Hostname == hostname {
|
||||
return ch.ID, nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("CustomHostname could not be found")
|
||||
}
|
174
vendor/github.com/cloudflare/cloudflare-go/dns.go
generated
vendored
Normal file
174
vendor/github.com/cloudflare/cloudflare-go/dns.go
generated
vendored
Normal file
|
@ -0,0 +1,174 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// DNSRecord represents a DNS record in a zone.
|
||||
type DNSRecord struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Proxiable bool `json:"proxiable,omitempty"`
|
||||
Proxied bool `json:"proxied,omitempty"`
|
||||
TTL int `json:"ttl,omitempty"`
|
||||
Locked bool `json:"locked,omitempty"`
|
||||
ZoneID string `json:"zone_id,omitempty"`
|
||||
ZoneName string `json:"zone_name,omitempty"`
|
||||
CreatedOn time.Time `json:"created_on,omitempty"`
|
||||
ModifiedOn time.Time `json:"modified_on,omitempty"`
|
||||
Data interface{} `json:"data,omitempty"` // data returned by: SRV, LOC
|
||||
Meta interface{} `json:"meta,omitempty"`
|
||||
Priority int `json:"priority,omitempty"`
|
||||
}
|
||||
|
||||
// DNSRecordResponse represents the response from the DNS endpoint.
|
||||
type DNSRecordResponse struct {
|
||||
Result DNSRecord `json:"result"`
|
||||
Response
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// DNSListResponse represents the response from the list DNS records endpoint.
|
||||
type DNSListResponse struct {
|
||||
Result []DNSRecord `json:"result"`
|
||||
Response
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// CreateDNSRecord creates a DNS record for the zone identifier.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record
|
||||
func (api *API) CreateDNSRecord(zoneID string, rr DNSRecord) (*DNSRecordResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/dns_records"
|
||||
res, err := api.makeRequest("POST", uri, rr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
var recordResp *DNSRecordResponse
|
||||
err = json.Unmarshal(res, &recordResp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return recordResp, nil
|
||||
}
|
||||
|
||||
// DNSRecords returns a slice of DNS records for the given zone identifier.
|
||||
//
|
||||
// This takes a DNSRecord to allow filtering of the results returned.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records
|
||||
func (api *API) DNSRecords(zoneID string, rr DNSRecord) ([]DNSRecord, error) {
|
||||
// Construct a query string
|
||||
v := url.Values{}
|
||||
// Request as many records as possible per page - API max is 50
|
||||
v.Set("per_page", "50")
|
||||
if rr.Name != "" {
|
||||
v.Set("name", rr.Name)
|
||||
}
|
||||
if rr.Type != "" {
|
||||
v.Set("type", rr.Type)
|
||||
}
|
||||
if rr.Content != "" {
|
||||
v.Set("content", rr.Content)
|
||||
}
|
||||
|
||||
var query string
|
||||
var records []DNSRecord
|
||||
page := 1
|
||||
|
||||
// Loop over makeRequest until what we've fetched all records
|
||||
for {
|
||||
v.Set("page", strconv.Itoa(page))
|
||||
query = "?" + v.Encode()
|
||||
uri := "/zones/" + zoneID + "/dns_records" + query
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return []DNSRecord{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r DNSListResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return []DNSRecord{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
records = append(records, r.Result...)
|
||||
if r.ResultInfo.Page >= r.ResultInfo.TotalPages {
|
||||
break
|
||||
}
|
||||
// Loop around and fetch the next page
|
||||
page++
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// DNSRecord returns a single DNS record for the given zone & record
|
||||
// identifiers.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-dns-record-details
|
||||
func (api *API) DNSRecord(zoneID, recordID string) (DNSRecord, error) {
|
||||
uri := "/zones/" + zoneID + "/dns_records/" + recordID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return DNSRecord{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r DNSRecordResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return DNSRecord{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// UpdateDNSRecord updates a single DNS record for the given zone & record
|
||||
// identifiers.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record
|
||||
func (api *API) UpdateDNSRecord(zoneID, recordID string, rr DNSRecord) error {
|
||||
rec, err := api.DNSRecord(zoneID, recordID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Populate the record name from the existing one if the update didn't
|
||||
// specify it.
|
||||
if rr.Name == "" {
|
||||
rr.Name = rec.Name
|
||||
}
|
||||
rr.Type = rec.Type
|
||||
uri := "/zones/" + zoneID + "/dns_records/" + recordID
|
||||
res, err := api.makeRequest("PUT", uri, rr)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r DNSRecordResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteDNSRecord deletes a single DNS record for the given zone & record
|
||||
// identifiers.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-delete-dns-record
|
||||
func (api *API) DeleteDNSRecord(zoneID, recordID string) error {
|
||||
uri := "/zones/" + zoneID + "/dns_records/" + recordID
|
||||
res, err := api.makeRequest("DELETE", uri, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r DNSRecordResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return nil
|
||||
}
|
48
vendor/github.com/cloudflare/cloudflare-go/errors.go
generated
vendored
Normal file
48
vendor/github.com/cloudflare/cloudflare-go/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
package cloudflare
|
||||
|
||||
// Error messages
|
||||
const (
|
||||
errEmptyCredentials = "invalid credentials: key & email must not be empty"
|
||||
errMakeRequestError = "error from makeRequest"
|
||||
errUnmarshalError = "error unmarshalling the JSON response"
|
||||
errRequestNotSuccessful = "error reported by API"
|
||||
)
|
||||
|
||||
var _ Error = &UserError{}
|
||||
|
||||
// Error represents an error returned from this library.
|
||||
type Error interface {
|
||||
error
|
||||
// Raised when user credentials or configuration is invalid.
|
||||
User() bool
|
||||
// Raised when a parsing error (e.g. JSON) occurs.
|
||||
Parse() bool
|
||||
// Raised when a network error occurs.
|
||||
Network() bool
|
||||
// Contains the most recent error.
|
||||
}
|
||||
|
||||
// UserError represents a user-generated error.
|
||||
type UserError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// User is a user-caused error.
|
||||
func (e *UserError) User() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Network error.
|
||||
func (e *UserError) Network() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Parse error.
|
||||
func (e *UserError) Parse() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Error wraps the underlying error.
|
||||
func (e *UserError) Error() string {
|
||||
return e.Err.Error()
|
||||
}
|
241
vendor/github.com/cloudflare/cloudflare-go/firewall.go
generated
vendored
Normal file
241
vendor/github.com/cloudflare/cloudflare-go/firewall.go
generated
vendored
Normal file
|
@ -0,0 +1,241 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// AccessRule represents a firewall access rule.
|
||||
type AccessRule struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
AllowedModes []string `json:"allowed_modes,omitempty"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
Configuration AccessRuleConfiguration `json:"configuration,omitempty"`
|
||||
Scope AccessRuleScope `json:"scope,omitempty"`
|
||||
CreatedOn time.Time `json:"created_on,omitempty"`
|
||||
ModifiedOn time.Time `json:"modified_on,omitempty"`
|
||||
}
|
||||
|
||||
// AccessRuleConfiguration represents the configuration of a firewall
|
||||
// access rule.
|
||||
type AccessRuleConfiguration struct {
|
||||
Target string `json:"target,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// AccessRuleScope represents the scope of a firewall access rule.
|
||||
type AccessRuleScope struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// AccessRuleResponse represents the response from the firewall access
|
||||
// rule endpoint.
|
||||
type AccessRuleResponse struct {
|
||||
Result AccessRule `json:"result"`
|
||||
Response
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// AccessRuleListResponse represents the response from the list access rules
|
||||
// endpoint.
|
||||
type AccessRuleListResponse struct {
|
||||
Result []AccessRule `json:"result"`
|
||||
Response
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// ListUserAccessRules returns a slice of access rules for the logged-in user.
|
||||
//
|
||||
// This takes an AccessRule to allow filtering of the results returned.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-level-firewall-access-rule-list-access-rules
|
||||
func (api *API) ListUserAccessRules(accessRule AccessRule, page int) (*AccessRuleListResponse, error) {
|
||||
return api.listAccessRules("/user", accessRule, page)
|
||||
}
|
||||
|
||||
// CreateUserAccessRule creates a firewall access rule for the logged-in user.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-level-firewall-access-rule-create-access-rule
|
||||
func (api *API) CreateUserAccessRule(accessRule AccessRule) (*AccessRuleResponse, error) {
|
||||
return api.createAccessRule("/user", accessRule)
|
||||
}
|
||||
|
||||
// UpdateUserAccessRule updates a single access rule for the logged-in user &
|
||||
// given access rule identifier.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-level-firewall-access-rule-update-access-rule
|
||||
func (api *API) UpdateUserAccessRule(accessRuleID string, accessRule AccessRule) (*AccessRuleResponse, error) {
|
||||
return api.updateAccessRule("/user", accessRuleID, accessRule)
|
||||
}
|
||||
|
||||
// DeleteUserAccessRule deletes a single access rule for the logged-in user and
|
||||
// access rule identifiers.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-level-firewall-access-rule-update-access-rule
|
||||
func (api *API) DeleteUserAccessRule(accessRuleID string) (*AccessRuleResponse, error) {
|
||||
return api.deleteAccessRule("/user", accessRuleID)
|
||||
}
|
||||
|
||||
// ListZoneAccessRules returns a slice of access rules for the given zone
|
||||
// identifier.
|
||||
//
|
||||
// This takes an AccessRule to allow filtering of the results returned.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#firewall-access-rule-for-a-zone-list-access-rules
|
||||
func (api *API) ListZoneAccessRules(zoneID string, accessRule AccessRule, page int) (*AccessRuleListResponse, error) {
|
||||
return api.listAccessRules("/zones/"+zoneID, accessRule, page)
|
||||
}
|
||||
|
||||
// CreateZoneAccessRule creates a firewall access rule for the given zone
|
||||
// identifier.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#firewall-access-rule-for-a-zone-create-access-rule
|
||||
func (api *API) CreateZoneAccessRule(zoneID string, accessRule AccessRule) (*AccessRuleResponse, error) {
|
||||
return api.createAccessRule("/zones/"+zoneID, accessRule)
|
||||
}
|
||||
|
||||
// UpdateZoneAccessRule updates a single access rule for the given zone &
|
||||
// access rule identifiers.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#firewall-access-rule-for-a-zone-update-access-rule
|
||||
func (api *API) UpdateZoneAccessRule(zoneID, accessRuleID string, accessRule AccessRule) (*AccessRuleResponse, error) {
|
||||
return api.updateAccessRule("/zones/"+zoneID, accessRuleID, accessRule)
|
||||
}
|
||||
|
||||
// DeleteZoneAccessRule deletes a single access rule for the given zone and
|
||||
// access rule identifiers.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#firewall-access-rule-for-a-zone-delete-access-rule
|
||||
func (api *API) DeleteZoneAccessRule(zoneID, accessRuleID string) (*AccessRuleResponse, error) {
|
||||
return api.deleteAccessRule("/zones/"+zoneID, accessRuleID)
|
||||
}
|
||||
|
||||
// ListOrganizationAccessRules returns a slice of access rules for the given
|
||||
// organization identifier.
|
||||
//
|
||||
// This takes an AccessRule to allow filtering of the results returned.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#organization-level-firewall-access-rule-list-access-rules
|
||||
func (api *API) ListOrganizationAccessRules(organizationID string, accessRule AccessRule, page int) (*AccessRuleListResponse, error) {
|
||||
return api.listAccessRules("/organizations/"+organizationID, accessRule, page)
|
||||
}
|
||||
|
||||
// CreateOrganizationAccessRule creates a firewall access rule for the given
|
||||
// organization identifier.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#organization-level-firewall-access-rule-create-access-rule
|
||||
func (api *API) CreateOrganizationAccessRule(organizationID string, accessRule AccessRule) (*AccessRuleResponse, error) {
|
||||
return api.createAccessRule("/organizations/"+organizationID, accessRule)
|
||||
}
|
||||
|
||||
// UpdateOrganizationAccessRule updates a single access rule for the given
|
||||
// organization & access rule identifiers.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#organization-level-firewall-access-rule-update-access-rule
|
||||
func (api *API) UpdateOrganizationAccessRule(organizationID, accessRuleID string, accessRule AccessRule) (*AccessRuleResponse, error) {
|
||||
return api.updateAccessRule("/organizations/"+organizationID, accessRuleID, accessRule)
|
||||
}
|
||||
|
||||
// DeleteOrganizationAccessRule deletes a single access rule for the given
|
||||
// organization and access rule identifiers.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#organization-level-firewall-access-rule-delete-access-rule
|
||||
func (api *API) DeleteOrganizationAccessRule(organizationID, accessRuleID string) (*AccessRuleResponse, error) {
|
||||
return api.deleteAccessRule("/organizations/"+organizationID, accessRuleID)
|
||||
}
|
||||
|
||||
func (api *API) listAccessRules(prefix string, accessRule AccessRule, page int) (*AccessRuleListResponse, error) {
|
||||
// Construct a query string
|
||||
v := url.Values{}
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
v.Set("page", strconv.Itoa(page))
|
||||
// Request as many rules as possible per page - API max is 100
|
||||
v.Set("per_page", "100")
|
||||
if accessRule.Notes != "" {
|
||||
v.Set("notes", accessRule.Notes)
|
||||
}
|
||||
if accessRule.Mode != "" {
|
||||
v.Set("mode", accessRule.Mode)
|
||||
}
|
||||
if accessRule.Scope.Type != "" {
|
||||
v.Set("scope_type", accessRule.Scope.Type)
|
||||
}
|
||||
if accessRule.Configuration.Value != "" {
|
||||
v.Set("configuration_value", accessRule.Configuration.Value)
|
||||
}
|
||||
if accessRule.Configuration.Target != "" {
|
||||
v.Set("configuration_target", accessRule.Configuration.Target)
|
||||
}
|
||||
v.Set("page", strconv.Itoa(page))
|
||||
query := "?" + v.Encode()
|
||||
|
||||
uri := prefix + "/firewall/access_rules/rules" + query
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &AccessRuleListResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *API) createAccessRule(prefix string, accessRule AccessRule) (*AccessRuleResponse, error) {
|
||||
uri := prefix + "/firewall/access_rules/rules"
|
||||
res, err := api.makeRequest("POST", uri, accessRule)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &AccessRuleResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *API) updateAccessRule(prefix, accessRuleID string, accessRule AccessRule) (*AccessRuleResponse, error) {
|
||||
uri := prefix + "/firewall/access_rules/rules/" + accessRuleID
|
||||
res, err := api.makeRequest("PATCH", uri, accessRule)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &AccessRuleResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *API) deleteAccessRule(prefix, accessRuleID string) (*AccessRuleResponse, error) {
|
||||
uri := prefix + "/firewall/access_rules/rules/" + accessRuleID
|
||||
res, err := api.makeRequest("DELETE", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &AccessRuleResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
44
vendor/github.com/cloudflare/cloudflare-go/ips.go
generated
vendored
Normal file
44
vendor/github.com/cloudflare/cloudflare-go/ips.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// IPRanges contains lists of IPv4 and IPv6 CIDRs.
|
||||
type IPRanges struct {
|
||||
IPv4CIDRs []string `json:"ipv4_cidrs"`
|
||||
IPv6CIDRs []string `json:"ipv6_cidrs"`
|
||||
}
|
||||
|
||||
// IPsResponse is the API response containing a list of IPs.
|
||||
type IPsResponse struct {
|
||||
Response
|
||||
Result IPRanges `json:"result"`
|
||||
}
|
||||
|
||||
// IPs gets a list of Cloudflare's IP ranges.
|
||||
//
|
||||
// This does not require logging in to the API.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#cloudflare-ips
|
||||
func IPs() (IPRanges, error) {
|
||||
resp, err := http.Get(apiURL + "/ips")
|
||||
if err != nil {
|
||||
return IPRanges{}, errors.Wrap(err, "HTTP request failed")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return IPRanges{}, errors.Wrap(err, "Response body could not be read")
|
||||
}
|
||||
var r IPsResponse
|
||||
err = json.Unmarshal(body, &r)
|
||||
if err != nil {
|
||||
return IPRanges{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
52
vendor/github.com/cloudflare/cloudflare-go/keyless.go
generated
vendored
Normal file
52
vendor/github.com/cloudflare/cloudflare-go/keyless.go
generated
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
package cloudflare
|
||||
|
||||
import "time"
|
||||
|
||||
// KeylessSSL represents Keyless SSL configuration.
|
||||
type KeylessSSL struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Status string `json:"success"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Permissions []string `json:"permissions"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
ModifiedOn time.Time `json:"modifed_on"`
|
||||
}
|
||||
|
||||
// KeylessSSLResponse represents the response from the Keyless SSL endpoint.
|
||||
type KeylessSSLResponse struct {
|
||||
Response
|
||||
Result []KeylessSSL `json:"result"`
|
||||
}
|
||||
|
||||
// CreateKeyless creates a new Keyless SSL configuration for the zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#keyless-ssl-for-a-zone-create-a-keyless-ssl-configuration
|
||||
func (api *API) CreateKeyless() {
|
||||
}
|
||||
|
||||
// ListKeyless lists Keyless SSL configurations for a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#keyless-ssl-for-a-zone-list-keyless-ssls
|
||||
func (api *API) ListKeyless() {
|
||||
}
|
||||
|
||||
// Keyless provides the configuration for a given Keyless SSL identifier.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#keyless-ssl-for-a-zone-keyless-ssl-details
|
||||
func (api *API) Keyless() {
|
||||
}
|
||||
|
||||
// UpdateKeyless updates an existing Keyless SSL configuration.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#keyless-ssl-for-a-zone-update-keyless-configuration
|
||||
func (api *API) UpdateKeyless() {
|
||||
}
|
||||
|
||||
// DeleteKeyless deletes an existing Keyless SSL configuration.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#keyless-ssl-for-a-zone-delete-keyless-configuration
|
||||
func (api *API) DeleteKeyless() {
|
||||
}
|
330
vendor/github.com/cloudflare/cloudflare-go/load_balancing.go
generated
vendored
Normal file
330
vendor/github.com/cloudflare/cloudflare-go/load_balancing.go
generated
vendored
Normal file
|
@ -0,0 +1,330 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// LoadBalancerPool represents a load balancer pool's properties.
|
||||
type LoadBalancerPool struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
CreatedOn *time.Time `json:"created_on,omitempty"`
|
||||
ModifiedOn *time.Time `json:"modified_on,omitempty"`
|
||||
Description string `json:"description"`
|
||||
Name string `json:"name"`
|
||||
Enabled bool `json:"enabled"`
|
||||
MinimumOrigins int `json:"minimum_origins,omitempty"`
|
||||
Monitor string `json:"monitor,omitempty"`
|
||||
Origins []LoadBalancerOrigin `json:"origins"`
|
||||
NotificationEmail string `json:"notification_email,omitempty"`
|
||||
|
||||
// CheckRegions defines the geographic region(s) from where to run health-checks from - e.g. "WNAM", "WEU", "SAF", "SAM".
|
||||
// Providing a null/empty value means "all regions", which may not be available to all plan types.
|
||||
CheckRegions []string `json:"check_regions"`
|
||||
}
|
||||
|
||||
type LoadBalancerOrigin struct {
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Weight float64 `json:"weight"`
|
||||
}
|
||||
|
||||
// LoadBalancerMonitor represents a load balancer monitor's properties.
|
||||
type LoadBalancerMonitor struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
CreatedOn *time.Time `json:"created_on,omitempty"`
|
||||
ModifiedOn *time.Time `json:"modified_on,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Description string `json:"description"`
|
||||
Method string `json:"method"`
|
||||
Path string `json:"path"`
|
||||
Header map[string][]string `json:"header"`
|
||||
Timeout int `json:"timeout"`
|
||||
Retries int `json:"retries"`
|
||||
Interval int `json:"interval"`
|
||||
ExpectedBody string `json:"expected_body"`
|
||||
ExpectedCodes string `json:"expected_codes"`
|
||||
}
|
||||
|
||||
// LoadBalancer represents a load balancer's properties.
|
||||
type LoadBalancer struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
CreatedOn *time.Time `json:"created_on,omitempty"`
|
||||
ModifiedOn *time.Time `json:"modified_on,omitempty"`
|
||||
Description string `json:"description"`
|
||||
Name string `json:"name"`
|
||||
TTL int `json:"ttl,omitempty"`
|
||||
FallbackPool string `json:"fallback_pool"`
|
||||
DefaultPools []string `json:"default_pools"`
|
||||
RegionPools map[string][]string `json:"region_pools"`
|
||||
PopPools map[string][]string `json:"pop_pools"`
|
||||
Proxied bool `json:"proxied"`
|
||||
Persistence string `json:"session_affinity,omitempty"`
|
||||
}
|
||||
|
||||
// loadBalancerPoolResponse represents the response from the load balancer pool endpoints.
|
||||
type loadBalancerPoolResponse struct {
|
||||
Response
|
||||
Result LoadBalancerPool `json:"result"`
|
||||
}
|
||||
|
||||
// loadBalancerPoolListResponse represents the response from the List Pools endpoint.
|
||||
type loadBalancerPoolListResponse struct {
|
||||
Response
|
||||
Result []LoadBalancerPool `json:"result"`
|
||||
ResultInfo ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// loadBalancerMonitorResponse represents the response from the load balancer monitor endpoints.
|
||||
type loadBalancerMonitorResponse struct {
|
||||
Response
|
||||
Result LoadBalancerMonitor `json:"result"`
|
||||
}
|
||||
|
||||
// loadBalancerMonitorListResponse represents the response from the List Monitors endpoint.
|
||||
type loadBalancerMonitorListResponse struct {
|
||||
Response
|
||||
Result []LoadBalancerMonitor `json:"result"`
|
||||
ResultInfo ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// loadBalancerResponse represents the response from the load balancer endpoints.
|
||||
type loadBalancerResponse struct {
|
||||
Response
|
||||
Result LoadBalancer `json:"result"`
|
||||
}
|
||||
|
||||
// loadBalancerListResponse represents the response from the List Load Balancers endpoint.
|
||||
type loadBalancerListResponse struct {
|
||||
Response
|
||||
Result []LoadBalancer `json:"result"`
|
||||
ResultInfo ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// CreateLoadBalancerPool creates a new load balancer pool.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancer-pools-create-a-pool
|
||||
func (api *API) CreateLoadBalancerPool(pool LoadBalancerPool) (LoadBalancerPool, error) {
|
||||
uri := api.userBaseURL("/user") + "/load_balancers/pools"
|
||||
res, err := api.makeRequest("POST", uri, pool)
|
||||
if err != nil {
|
||||
return LoadBalancerPool{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r loadBalancerPoolResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return LoadBalancerPool{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ListLoadBalancerPools lists load balancer pools connected to an account.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancer-pools-list-pools
|
||||
func (api *API) ListLoadBalancerPools() ([]LoadBalancerPool, error) {
|
||||
uri := api.userBaseURL("/user") + "/load_balancers/pools"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r loadBalancerPoolListResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// LoadBalancerPoolDetails returns the details for a load balancer pool.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancer-pools-pool-details
|
||||
func (api *API) LoadBalancerPoolDetails(poolID string) (LoadBalancerPool, error) {
|
||||
uri := api.userBaseURL("/user") + "/load_balancers/pools/" + poolID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return LoadBalancerPool{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r loadBalancerPoolResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return LoadBalancerPool{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// DeleteLoadBalancerPool disables and deletes a load balancer pool.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancer-pools-delete-a-pool
|
||||
func (api *API) DeleteLoadBalancerPool(poolID string) error {
|
||||
uri := api.userBaseURL("/user") + "/load_balancers/pools/" + poolID
|
||||
if _, err := api.makeRequest("DELETE", uri, nil); err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ModifyLoadBalancerPool modifies a configured load balancer pool.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancer-pools-modify-a-pool
|
||||
func (api *API) ModifyLoadBalancerPool(pool LoadBalancerPool) (LoadBalancerPool, error) {
|
||||
uri := api.userBaseURL("/user") + "/load_balancers/pools/" + pool.ID
|
||||
res, err := api.makeRequest("PUT", uri, pool)
|
||||
if err != nil {
|
||||
return LoadBalancerPool{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r loadBalancerPoolResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return LoadBalancerPool{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// CreateLoadBalancerMonitor creates a new load balancer monitor.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancer-monitors-create-a-monitor
|
||||
func (api *API) CreateLoadBalancerMonitor(monitor LoadBalancerMonitor) (LoadBalancerMonitor, error) {
|
||||
uri := api.userBaseURL("/user") + "/load_balancers/monitors"
|
||||
res, err := api.makeRequest("POST", uri, monitor)
|
||||
if err != nil {
|
||||
return LoadBalancerMonitor{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r loadBalancerMonitorResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return LoadBalancerMonitor{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ListLoadBalancerMonitors lists load balancer monitors connected to an account.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancer-monitors-list-monitors
|
||||
func (api *API) ListLoadBalancerMonitors() ([]LoadBalancerMonitor, error) {
|
||||
uri := api.userBaseURL("/user") + "/load_balancers/monitors"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r loadBalancerMonitorListResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// LoadBalancerMonitorDetails returns the details for a load balancer monitor.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancer-monitors-monitor-details
|
||||
func (api *API) LoadBalancerMonitorDetails(monitorID string) (LoadBalancerMonitor, error) {
|
||||
uri := api.userBaseURL("/user") + "/load_balancers/monitors/" + monitorID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return LoadBalancerMonitor{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r loadBalancerMonitorResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return LoadBalancerMonitor{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// DeleteLoadBalancerMonitor disables and deletes a load balancer monitor.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancer-monitors-delete-a-monitor
|
||||
func (api *API) DeleteLoadBalancerMonitor(monitorID string) error {
|
||||
uri := api.userBaseURL("/user") + "/load_balancers/monitors/" + monitorID
|
||||
if _, err := api.makeRequest("DELETE", uri, nil); err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ModifyLoadBalancerMonitor modifies a configured load balancer monitor.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancer-monitors-modify-a-monitor
|
||||
func (api *API) ModifyLoadBalancerMonitor(monitor LoadBalancerMonitor) (LoadBalancerMonitor, error) {
|
||||
uri := api.userBaseURL("/user") + "/load_balancers/monitors/" + monitor.ID
|
||||
res, err := api.makeRequest("PUT", uri, monitor)
|
||||
if err != nil {
|
||||
return LoadBalancerMonitor{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r loadBalancerMonitorResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return LoadBalancerMonitor{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// CreateLoadBalancer creates a new load balancer.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancers-create-a-load-balancer
|
||||
func (api *API) CreateLoadBalancer(zoneID string, lb LoadBalancer) (LoadBalancer, error) {
|
||||
uri := "/zones/" + zoneID + "/load_balancers"
|
||||
res, err := api.makeRequest("POST", uri, lb)
|
||||
if err != nil {
|
||||
return LoadBalancer{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r loadBalancerResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return LoadBalancer{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ListLoadBalancers lists load balancers configured on a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancers-list-load-balancers
|
||||
func (api *API) ListLoadBalancers(zoneID string) ([]LoadBalancer, error) {
|
||||
uri := "/zones/" + zoneID + "/load_balancers"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r loadBalancerListResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// LoadBalancerDetails returns the details for a load balancer.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancers-load-balancer-details
|
||||
func (api *API) LoadBalancerDetails(zoneID, lbID string) (LoadBalancer, error) {
|
||||
uri := "/zones/" + zoneID + "/load_balancers/" + lbID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return LoadBalancer{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r loadBalancerResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return LoadBalancer{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// DeleteLoadBalancer disables and deletes a load balancer.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancers-delete-a-load-balancer
|
||||
func (api *API) DeleteLoadBalancer(zoneID, lbID string) error {
|
||||
uri := "/zones/" + zoneID + "/load_balancers/" + lbID
|
||||
if _, err := api.makeRequest("DELETE", uri, nil); err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ModifyLoadBalancer modifies a configured load balancer.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#load-balancers-modify-a-load-balancer
|
||||
func (api *API) ModifyLoadBalancer(zoneID string, lb LoadBalancer) (LoadBalancer, error) {
|
||||
uri := "/zones/" + zoneID + "/load_balancers/" + lb.ID
|
||||
res, err := api.makeRequest("PUT", uri, lb)
|
||||
if err != nil {
|
||||
return LoadBalancer{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r loadBalancerResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return LoadBalancer{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
150
vendor/github.com/cloudflare/cloudflare-go/lockdown.go
generated
vendored
Normal file
150
vendor/github.com/cloudflare/cloudflare-go/lockdown.go
generated
vendored
Normal file
|
@ -0,0 +1,150 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ZoneLockdown represents a Zone Lockdown rule. A rule only permits access to
|
||||
// the provided URL pattern(s) from the given IP address(es) or subnet(s).
|
||||
type ZoneLockdown struct {
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description"`
|
||||
URLs []string `json:"urls"`
|
||||
Configurations []ZoneLockdownConfig `json:"configurations"`
|
||||
Paused bool `json:"paused"`
|
||||
}
|
||||
|
||||
// ZoneLockdownConfig represents a Zone Lockdown config, which comprises
|
||||
// a Target ("ip" or "ip_range") and a Value (an IP address or IP+mask,
|
||||
// respectively.)
|
||||
type ZoneLockdownConfig struct {
|
||||
Target string `json:"target"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// ZoneLockdownResponse represents a response from the Zone Lockdown endpoint.
|
||||
type ZoneLockdownResponse struct {
|
||||
Result ZoneLockdown `json:"result"`
|
||||
Response
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// ZoneLockdownListResponse represents a response from the List Zone Lockdown
|
||||
// endpoint.
|
||||
type ZoneLockdownListResponse struct {
|
||||
Result []ZoneLockdown `json:"result"`
|
||||
Response
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// CreateZoneLockdown creates a Zone ZoneLockdown rule for the given zone ID.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-ZoneLockdown-create-a-ZoneLockdown-rule
|
||||
func (api *API) CreateZoneLockdown(zoneID string, ld ZoneLockdown) (*ZoneLockdownResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/firewall/lockdowns"
|
||||
res, err := api.makeRequest("POST", uri, ld)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &ZoneLockdownResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// UpdateZoneLockdown updates a Zone ZoneLockdown rule (based on the ID) for the
|
||||
// given zone ID.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-ZoneLockdown-update-ZoneLockdown-rule
|
||||
func (api *API) UpdateZoneLockdown(zoneID string, id string, ld ZoneLockdown) (*ZoneLockdownResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/firewall/lockdowns"
|
||||
res, err := api.makeRequest("PUT", uri, ld)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &ZoneLockdownResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// DeleteZoneLockdown deletes a Zone ZoneLockdown rule (based on the ID) for the
|
||||
// given zone ID.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-ZoneLockdown-delete-ZoneLockdown-rule
|
||||
func (api *API) DeleteZoneLockdown(zoneID string, id string) (*ZoneLockdownResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/firewall/lockdowns/" + id
|
||||
res, err := api.makeRequest("DELETE", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &ZoneLockdownResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ZoneLockdown retrieves a Zone ZoneLockdown rule (based on the ID) for the
|
||||
// given zone ID.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-ZoneLockdown-ZoneLockdown-rule-details
|
||||
func (api *API) ZoneLockdown(zoneID string, id string) (*ZoneLockdownResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/firewall/lockdowns/" + id
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &ZoneLockdownResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ListZoneLockdowns retrieves a list of Zone ZoneLockdown rules for a given
|
||||
// zone ID by page number.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-ZoneLockdown-list-ZoneLockdown-rules
|
||||
func (api *API) ListZoneLockdowns(zoneID string, page int) (*ZoneLockdownListResponse, error) {
|
||||
v := url.Values{}
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
v.Set("page", strconv.Itoa(page))
|
||||
v.Set("per_page", strconv.Itoa(100))
|
||||
query := "?" + v.Encode()
|
||||
|
||||
uri := "/zones/" + zoneID + "/firewall/lockdowns" + query
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &ZoneLockdownListResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
90
vendor/github.com/cloudflare/cloudflare-go/options.go
generated
vendored
Normal file
90
vendor/github.com/cloudflare/cloudflare-go/options.go
generated
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"time"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
// Option is a functional option for configuring the API client.
|
||||
type Option func(*API) error
|
||||
|
||||
// HTTPClient accepts a custom *http.Client for making API calls.
|
||||
func HTTPClient(client *http.Client) Option {
|
||||
return func(api *API) error {
|
||||
api.httpClient = client
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Headers allows you to set custom HTTP headers when making API calls (e.g. for
|
||||
// satisfying HTTP proxies, or for debugging).
|
||||
func Headers(headers http.Header) Option {
|
||||
return func(api *API) error {
|
||||
api.headers = headers
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Organization allows you to apply account-level changes (Load Balancing, Railguns)
|
||||
// to an organization instead.
|
||||
func UsingOrganization(orgID string) Option {
|
||||
return func(api *API) error {
|
||||
api.organizationID = orgID
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// UsingRateLimit applies a non-default rate limit to client API requests
|
||||
// If not specified the default of 4rps will be applied
|
||||
func UsingRateLimit(rps float64) Option {
|
||||
return func(api *API) error {
|
||||
// because ratelimiter doesnt do any windowing
|
||||
// setting burst makes it difficult to enforce a fixed rate
|
||||
// so setting it equal to 1 this effectively disables bursting
|
||||
// this doesn't check for sensible values, ultimately the api will enforce that the value is ok
|
||||
api.rateLimiter = rate.NewLimiter(rate.Limit(rps), 1)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// UsingRetryPolicy applies a non-default number of retries and min/max retry delays
|
||||
// This will be used when the client exponentially backs off after errored requests
|
||||
func UsingRetryPolicy(maxRetries int, minRetryDelaySecs int, maxRetryDelaySecs int) Option {
|
||||
// seconds is very granular for a minimum delay - but this is only in case of failure
|
||||
return func(api *API) error {
|
||||
api.retryPolicy = RetryPolicy{
|
||||
MaxRetries: maxRetries,
|
||||
MinRetryDelay: time.Duration(minRetryDelaySecs) * time.Second,
|
||||
MaxRetryDelay: time.Duration(maxRetryDelaySecs) * time.Second,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// UsingLogger can be set if you want to get log output from this API instance
|
||||
// By default no log output is emitted
|
||||
func UsingLogger(logger Logger) Option {
|
||||
return func(api *API) error {
|
||||
api.logger = logger
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// parseOptions parses the supplied options functions and returns a configured
|
||||
// *API instance.
|
||||
func (api *API) parseOptions(opts ...Option) error {
|
||||
// Range over each options function and apply it to our API type to
|
||||
// configure it. Options functions are applied in order, with any
|
||||
// conflicting options overriding earlier calls.
|
||||
for _, option := range opts {
|
||||
err := option(api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
185
vendor/github.com/cloudflare/cloudflare-go/organizations.go
generated
vendored
Normal file
185
vendor/github.com/cloudflare/cloudflare-go/organizations.go
generated
vendored
Normal file
|
@ -0,0 +1,185 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Organization represents a multi-user organization.
|
||||
type Organization struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
}
|
||||
|
||||
// organizationResponse represents the response from the Organization endpoint.
|
||||
type organizationResponse struct {
|
||||
Response
|
||||
Result []Organization `json:"result"`
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// OrganizationMember has details on a member.
|
||||
type OrganizationMember struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Roles []OrganizationRole `json:"roles,omitempty"`
|
||||
}
|
||||
|
||||
// OrganizationInvite has details on an invite.
|
||||
type OrganizationInvite struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
InvitedMemberID string `json:"invited_member_id,omitempty"`
|
||||
InvitedMemberEmail string `json:"invited_member_email,omitempty"`
|
||||
OrganizationID string `json:"organization_id,omitempty"`
|
||||
OrganizationName string `json:"organization_name,omitempty"`
|
||||
Roles []OrganizationRole `json:"roles,omitempty"`
|
||||
InvitedBy string `json:"invited_by,omitempty"`
|
||||
InvitedOn *time.Time `json:"invited_on,omitempty"`
|
||||
ExpiresOn *time.Time `json:"expires_on,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// OrganizationRole has details on a role.
|
||||
type OrganizationRole struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
// OrganizationDetails represents details of an organization.
|
||||
type OrganizationDetails struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Members []OrganizationMember `json:"members"`
|
||||
Invites []OrganizationInvite `json:"invites"`
|
||||
Roles []OrganizationRole `json:"roles,omitempty"`
|
||||
}
|
||||
|
||||
// organizationDetailsResponse represents the response from the OrganizationDetails endpoint.
|
||||
type organizationDetailsResponse struct {
|
||||
Response
|
||||
Result OrganizationDetails `json:"result"`
|
||||
}
|
||||
|
||||
// ListOrganizations lists organizations of the logged-in user.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-s-organizations-list-organizations
|
||||
func (api *API) ListOrganizations() ([]Organization, ResultInfo, error) {
|
||||
var r organizationResponse
|
||||
res, err := api.makeRequest("GET", "/user/organizations", nil)
|
||||
if err != nil {
|
||||
return []Organization{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return []Organization{}, ResultInfo{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return r.Result, r.ResultInfo, nil
|
||||
}
|
||||
|
||||
// OrganizationDetails returns details for the specified organization of the logged-in user.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#organizations-organization-details
|
||||
func (api *API) OrganizationDetails(organizationID string) (OrganizationDetails, error) {
|
||||
var r organizationDetailsResponse
|
||||
uri := "/organizations/" + organizationID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return OrganizationDetails{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return OrganizationDetails{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// organizationMembersResponse represents the response from the Organization members endpoint.
|
||||
type organizationMembersResponse struct {
|
||||
Response
|
||||
Result []OrganizationMember `json:"result"`
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// OrganizationMembers returns list of members for specified organization of the logged-in user.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#organization-members-list-members
|
||||
func (api *API) OrganizationMembers(organizationID string) ([]OrganizationMember, ResultInfo, error) {
|
||||
var r organizationMembersResponse
|
||||
uri := "/organizations/" + organizationID + "/members"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return []OrganizationMember{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return []OrganizationMember{}, ResultInfo{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return r.Result, r.ResultInfo, nil
|
||||
}
|
||||
|
||||
// organizationInvitesResponse represents the response from the Organization invites endpoint.
|
||||
type organizationInvitesResponse struct {
|
||||
Response
|
||||
Result []OrganizationInvite `json:"result"`
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// OrganizationMembers returns list of invites for specified organization of the logged-in user.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#organization-invites
|
||||
func (api *API) OrganizationInvites(organizationID string) ([]OrganizationInvite, ResultInfo, error) {
|
||||
var r organizationInvitesResponse
|
||||
uri := "/organizations/" + organizationID + "/invites"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return []OrganizationInvite{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return []OrganizationInvite{}, ResultInfo{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return r.Result, r.ResultInfo, nil
|
||||
}
|
||||
|
||||
// organizationRolesResponse represents the response from the Organization roles endpoint.
|
||||
type organizationRolesResponse struct {
|
||||
Response
|
||||
Result []OrganizationRole `json:"result"`
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// OrganizationRoles returns list of roles for specified organization of the logged-in user.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#organization-roles-list-roles
|
||||
func (api *API) OrganizationRoles(organizationID string) ([]OrganizationRole, ResultInfo, error) {
|
||||
var r organizationRolesResponse
|
||||
uri := "/organizations/" + organizationID + "/roles"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return []OrganizationRole{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return []OrganizationRole{}, ResultInfo{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return r.Result, r.ResultInfo, nil
|
||||
}
|
168
vendor/github.com/cloudflare/cloudflare-go/origin_ca.go
generated
vendored
Normal file
168
vendor/github.com/cloudflare/cloudflare-go/origin_ca.go
generated
vendored
Normal file
|
@ -0,0 +1,168 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// OriginCACertificate represents a Cloudflare-issued certificate.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#cloudflare-ca
|
||||
type OriginCACertificate struct {
|
||||
ID string `json:"id"`
|
||||
Certificate string `json:"certificate"`
|
||||
Hostnames []string `json:"hostnames"`
|
||||
ExpiresOn time.Time `json:"expires_on"`
|
||||
RequestType string `json:"request_type"`
|
||||
RequestValidity int `json:"requested_validity"`
|
||||
CSR string `json:"csr"`
|
||||
}
|
||||
|
||||
// OriginCACertificateListOptions represents the parameters used to list Cloudflare-issued certificates.
|
||||
type OriginCACertificateListOptions struct {
|
||||
ZoneID string
|
||||
}
|
||||
|
||||
// OriginCACertificateID represents the ID of the revoked certificate from the Revoke Certificate endpoint.
|
||||
type OriginCACertificateID struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
// originCACertificateResponse represents the response from the Create Certificate and the Certificate Details endpoints.
|
||||
type originCACertificateResponse struct {
|
||||
Response
|
||||
Result OriginCACertificate `json:"result"`
|
||||
}
|
||||
|
||||
// originCACertificateResponseList represents the response from the List Certificates endpoint.
|
||||
type originCACertificateResponseList struct {
|
||||
Response
|
||||
Result []OriginCACertificate `json:"result"`
|
||||
ResultInfo ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// originCACertificateResponseRevoke represents the response from the Revoke Certificate endpoint.
|
||||
type originCACertificateResponseRevoke struct {
|
||||
Response
|
||||
Result OriginCACertificateID `json:"result"`
|
||||
}
|
||||
|
||||
// CreateOriginCertificate creates a Cloudflare-signed certificate.
|
||||
//
|
||||
// This function requires api.APIUserServiceKey be set to your Certificates API key.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#cloudflare-ca-create-certificate
|
||||
func (api *API) CreateOriginCertificate(certificate OriginCACertificate) (*OriginCACertificate, error) {
|
||||
uri := "/certificates"
|
||||
res, err := api.makeRequestWithAuthType("POST", uri, certificate, AuthUserService)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
var originResponse *originCACertificateResponse
|
||||
|
||||
err = json.Unmarshal(res, &originResponse)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
if !originResponse.Success {
|
||||
return nil, errors.New(errRequestNotSuccessful)
|
||||
}
|
||||
|
||||
return &originResponse.Result, nil
|
||||
}
|
||||
|
||||
// OriginCertificates lists all Cloudflare-issued certificates.
|
||||
//
|
||||
// This function requires api.APIUserServiceKey be set to your Certificates API key.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#cloudflare-ca-list-certificates
|
||||
func (api *API) OriginCertificates(options OriginCACertificateListOptions) ([]OriginCACertificate, error) {
|
||||
v := url.Values{}
|
||||
if options.ZoneID != "" {
|
||||
v.Set("zone_id", options.ZoneID)
|
||||
}
|
||||
uri := "/certificates" + "?" + v.Encode()
|
||||
res, err := api.makeRequestWithAuthType("GET", uri, nil, AuthUserService)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
var originResponse *originCACertificateResponseList
|
||||
|
||||
err = json.Unmarshal(res, &originResponse)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
if !originResponse.Success {
|
||||
return nil, errors.New(errRequestNotSuccessful)
|
||||
}
|
||||
|
||||
return originResponse.Result, nil
|
||||
}
|
||||
|
||||
// OriginCertificate returns the details for a Cloudflare-issued certificate.
|
||||
//
|
||||
// This function requires api.APIUserServiceKey be set to your Certificates API key.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#cloudflare-ca-certificate-details
|
||||
func (api *API) OriginCertificate(certificateID string) (*OriginCACertificate, error) {
|
||||
uri := "/certificates/" + certificateID
|
||||
res, err := api.makeRequestWithAuthType("GET", uri, nil, AuthUserService)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
var originResponse *originCACertificateResponse
|
||||
|
||||
err = json.Unmarshal(res, &originResponse)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
if !originResponse.Success {
|
||||
return nil, errors.New(errRequestNotSuccessful)
|
||||
}
|
||||
|
||||
return &originResponse.Result, nil
|
||||
}
|
||||
|
||||
// RevokeOriginCertificate revokes a created certificate for a zone.
|
||||
//
|
||||
// This function requires api.APIUserServiceKey be set to your Certificates API key.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#cloudflare-ca-revoke-certificate
|
||||
func (api *API) RevokeOriginCertificate(certificateID string) (*OriginCACertificateID, error) {
|
||||
uri := "/certificates/" + certificateID
|
||||
res, err := api.makeRequestWithAuthType("DELETE", uri, nil, AuthUserService)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
var originResponse *originCACertificateResponseRevoke
|
||||
|
||||
err = json.Unmarshal(res, &originResponse)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
if !originResponse.Success {
|
||||
return nil, errors.New(errRequestNotSuccessful)
|
||||
}
|
||||
|
||||
return &originResponse.Result, nil
|
||||
|
||||
}
|
206
vendor/github.com/cloudflare/cloudflare-go/page_rules.go
generated
vendored
Normal file
206
vendor/github.com/cloudflare/cloudflare-go/page_rules.go
generated
vendored
Normal file
|
@ -0,0 +1,206 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// PageRuleTarget is the target to evaluate on a request.
|
||||
//
|
||||
// Currently Target must always be "url" and Operator must be "matches". Value
|
||||
// is the URL pattern to match against.
|
||||
type PageRuleTarget struct {
|
||||
Target string `json:"target"`
|
||||
Constraint struct {
|
||||
Operator string `json:"operator"`
|
||||
Value string `json:"value"`
|
||||
} `json:"constraint"`
|
||||
}
|
||||
|
||||
/*
|
||||
PageRuleAction is the action to take when the target is matched.
|
||||
|
||||
Valid IDs are:
|
||||
|
||||
always_online
|
||||
always_use_https
|
||||
browser_cache_ttl
|
||||
browser_check
|
||||
cache_level
|
||||
disable_apps
|
||||
disable_performance
|
||||
disable_railgun
|
||||
disable_security
|
||||
edge_cache_ttl
|
||||
email_obfuscation
|
||||
forwarding_url
|
||||
ip_geolocation
|
||||
mirage
|
||||
rocket_loader
|
||||
security_level
|
||||
server_side_exclude
|
||||
smart_errors
|
||||
ssl
|
||||
waf
|
||||
*/
|
||||
type PageRuleAction struct {
|
||||
ID string `json:"id"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
||||
|
||||
// PageRuleActions maps API action IDs to human-readable strings.
|
||||
var PageRuleActions = map[string]string{
|
||||
"always_online": "Always Online", // Value of type string
|
||||
"always_use_https": "Always Use HTTPS", // Value of type interface{}
|
||||
"browser_cache_ttl": "Browser Cache TTL", // Value of type int
|
||||
"browser_check": "Browser Integrity Check", // Value of type string
|
||||
"cache_level": "Cache Level", // Value of type string
|
||||
"disable_apps": "Disable Apps", // Value of type interface{}
|
||||
"disable_performance": "Disable Performance", // Value of type interface{}
|
||||
"disable_railgun": "Disable Railgun", // Value of type string
|
||||
"disable_security": "Disable Security", // Value of type interface{}
|
||||
"edge_cache_ttl": "Edge Cache TTL", // Value of type int
|
||||
"email_obfuscation": "Email Obfuscation", // Value of type string
|
||||
"forwarding_url": "Forwarding URL", // Value of type map[string]interface
|
||||
"ip_geolocation": "IP Geolocation Header", // Value of type string
|
||||
"mirage": "Mirage", // Value of type string
|
||||
"rocket_loader": "Rocker Loader", // Value of type string
|
||||
"security_level": "Security Level", // Value of type string
|
||||
"server_side_exclude": "Server Side Excludes", // Value of type string
|
||||
"smart_errors": "Smart Errors", // Value of type string
|
||||
"ssl": "SSL", // Value of type string
|
||||
"waf": "Web Application Firewall", // Value of type string
|
||||
}
|
||||
|
||||
// PageRule describes a Page Rule.
|
||||
type PageRule struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Targets []PageRuleTarget `json:"targets"`
|
||||
Actions []PageRuleAction `json:"actions"`
|
||||
Priority int `json:"priority"`
|
||||
Status string `json:"status"` // can be: active, paused
|
||||
ModifiedOn time.Time `json:"modified_on,omitempty"`
|
||||
CreatedOn time.Time `json:"created_on,omitempty"`
|
||||
}
|
||||
|
||||
// PageRuleDetailResponse is the API response, containing a single PageRule.
|
||||
type PageRuleDetailResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result PageRule `json:"result"`
|
||||
}
|
||||
|
||||
// PageRulesResponse is the API response, containing an array of PageRules.
|
||||
type PageRulesResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result []PageRule `json:"result"`
|
||||
}
|
||||
|
||||
// CreatePageRule creates a new Page Rule for a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#page-rules-for-a-zone-create-a-page-rule
|
||||
func (api *API) CreatePageRule(zoneID string, rule PageRule) (*PageRule, error) {
|
||||
uri := "/zones/" + zoneID + "/pagerules"
|
||||
res, err := api.makeRequest("POST", uri, rule)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r PageRuleDetailResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return &r.Result, nil
|
||||
}
|
||||
|
||||
// ListPageRules returns all Page Rules for a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#page-rules-for-a-zone-list-page-rules
|
||||
func (api *API) ListPageRules(zoneID string) ([]PageRule, error) {
|
||||
uri := "/zones/" + zoneID + "/pagerules"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return []PageRule{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r PageRulesResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return []PageRule{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// PageRule fetches detail about one Page Rule for a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#page-rules-for-a-zone-page-rule-details
|
||||
func (api *API) PageRule(zoneID, ruleID string) (PageRule, error) {
|
||||
uri := "/zones/" + zoneID + "/pagerules/" + ruleID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return PageRule{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r PageRuleDetailResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return PageRule{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ChangePageRule lets you change individual settings for a Page Rule. This is
|
||||
// in contrast to UpdatePageRule which replaces the entire Page Rule.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#page-rules-for-a-zone-change-a-page-rule
|
||||
func (api *API) ChangePageRule(zoneID, ruleID string, rule PageRule) error {
|
||||
uri := "/zones/" + zoneID + "/pagerules/" + ruleID
|
||||
res, err := api.makeRequest("PATCH", uri, rule)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r PageRuleDetailResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdatePageRule lets you replace a Page Rule. This is in contrast to
|
||||
// ChangePageRule which lets you change individual settings.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#page-rules-for-a-zone-update-a-page-rule
|
||||
func (api *API) UpdatePageRule(zoneID, ruleID string, rule PageRule) error {
|
||||
uri := "/zones/" + zoneID + "/pagerules/" + ruleID
|
||||
res, err := api.makeRequest("PUT", uri, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r PageRuleDetailResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeletePageRule deletes a Page Rule for a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#page-rules-for-a-zone-delete-a-page-rule
|
||||
func (api *API) DeletePageRule(zoneID, ruleID string) error {
|
||||
uri := "/zones/" + zoneID + "/pagerules/" + ruleID
|
||||
res, err := api.makeRequest("DELETE", uri, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r PageRuleDetailResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return nil
|
||||
}
|
297
vendor/github.com/cloudflare/cloudflare-go/railgun.go
generated
vendored
Normal file
297
vendor/github.com/cloudflare/cloudflare-go/railgun.go
generated
vendored
Normal file
|
@ -0,0 +1,297 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Railgun represents a Railgun's properties.
|
||||
type Railgun struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Enabled bool `json:"enabled"`
|
||||
ZonesConnected int `json:"zones_connected"`
|
||||
Build string `json:"build"`
|
||||
Version string `json:"version"`
|
||||
Revision string `json:"revision"`
|
||||
ActivationKey string `json:"activation_key"`
|
||||
ActivatedOn time.Time `json:"activated_on"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
ModifiedOn time.Time `json:"modified_on"`
|
||||
UpgradeInfo struct {
|
||||
LatestVersion string `json:"latest_version"`
|
||||
DownloadLink string `json:"download_link"`
|
||||
} `json:"upgrade_info"`
|
||||
}
|
||||
|
||||
// RailgunListOptions represents the parameters used to list railguns.
|
||||
type RailgunListOptions struct {
|
||||
Direction string
|
||||
}
|
||||
|
||||
// railgunResponse represents the response from the Create Railgun and the Railgun Details endpoints.
|
||||
type railgunResponse struct {
|
||||
Response
|
||||
Result Railgun `json:"result"`
|
||||
}
|
||||
|
||||
// railgunsResponse represents the response from the List Railguns endpoint.
|
||||
type railgunsResponse struct {
|
||||
Response
|
||||
Result []Railgun `json:"result"`
|
||||
}
|
||||
|
||||
// CreateRailgun creates a new Railgun.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railgun-create-railgun
|
||||
func (api *API) CreateRailgun(name string) (Railgun, error) {
|
||||
uri := api.userBaseURL("") + "/railguns"
|
||||
params := struct {
|
||||
Name string `json:"name"`
|
||||
}{
|
||||
Name: name,
|
||||
}
|
||||
res, err := api.makeRequest("POST", uri, params)
|
||||
if err != nil {
|
||||
return Railgun{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r railgunResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return Railgun{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ListRailguns lists Railguns connected to an account.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railgun-list-railguns
|
||||
func (api *API) ListRailguns(options RailgunListOptions) ([]Railgun, error) {
|
||||
v := url.Values{}
|
||||
if options.Direction != "" {
|
||||
v.Set("direction", options.Direction)
|
||||
}
|
||||
uri := api.userBaseURL("") + "/railguns" + "?" + v.Encode()
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r railgunsResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// RailgunDetails returns the details for a Railgun.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railgun-railgun-details
|
||||
func (api *API) RailgunDetails(railgunID string) (Railgun, error) {
|
||||
uri := api.userBaseURL("") + "/railguns/" + railgunID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return Railgun{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r railgunResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return Railgun{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// RailgunZones returns the zones that are currently using a Railgun.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railgun-get-zones-connected-to-a-railgun
|
||||
func (api *API) RailgunZones(railgunID string) ([]Zone, error) {
|
||||
uri := api.userBaseURL("") + "/railguns/" + railgunID + "/zones"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r ZonesResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// enableRailgun enables (true) or disables (false) a Railgun for all zones connected to it.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railgun-enable-or-disable-a-railgun
|
||||
func (api *API) enableRailgun(railgunID string, enable bool) (Railgun, error) {
|
||||
uri := api.userBaseURL("") + "/railguns/" + railgunID
|
||||
params := struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}{
|
||||
Enabled: enable,
|
||||
}
|
||||
res, err := api.makeRequest("PATCH", uri, params)
|
||||
if err != nil {
|
||||
return Railgun{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r railgunResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return Railgun{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// EnableRailgun enables a Railgun for all zones connected to it.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railgun-enable-or-disable-a-railgun
|
||||
func (api *API) EnableRailgun(railgunID string) (Railgun, error) {
|
||||
return api.enableRailgun(railgunID, true)
|
||||
}
|
||||
|
||||
// DisableRailgun enables a Railgun for all zones connected to it.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railgun-enable-or-disable-a-railgun
|
||||
func (api *API) DisableRailgun(railgunID string) (Railgun, error) {
|
||||
return api.enableRailgun(railgunID, false)
|
||||
}
|
||||
|
||||
// DeleteRailgun disables and deletes a Railgun.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railgun-delete-railgun
|
||||
func (api *API) DeleteRailgun(railgunID string) error {
|
||||
uri := api.userBaseURL("") + "/railguns/" + railgunID
|
||||
if _, err := api.makeRequest("DELETE", uri, nil); err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ZoneRailgun represents the status of a Railgun on a zone.
|
||||
type ZoneRailgun struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Connected bool `json:"connected"`
|
||||
}
|
||||
|
||||
// zoneRailgunResponse represents the response from the Zone Railgun Details endpoint.
|
||||
type zoneRailgunResponse struct {
|
||||
Response
|
||||
Result ZoneRailgun `json:"result"`
|
||||
}
|
||||
|
||||
// zoneRailgunsResponse represents the response from the Zone Railgun endpoint.
|
||||
type zoneRailgunsResponse struct {
|
||||
Response
|
||||
Result []ZoneRailgun `json:"result"`
|
||||
}
|
||||
|
||||
// RailgunDiagnosis represents the test results from testing railgun connections
|
||||
// to a zone.
|
||||
type RailgunDiagnosis struct {
|
||||
Method string `json:"method"`
|
||||
HostName string `json:"host_name"`
|
||||
HTTPStatus int `json:"http_status"`
|
||||
Railgun string `json:"railgun"`
|
||||
URL string `json:"url"`
|
||||
ResponseStatus string `json:"response_status"`
|
||||
Protocol string `json:"protocol"`
|
||||
ElapsedTime string `json:"elapsed_time"`
|
||||
BodySize string `json:"body_size"`
|
||||
BodyHash string `json:"body_hash"`
|
||||
MissingHeaders string `json:"missing_headers"`
|
||||
ConnectionClose bool `json:"connection_close"`
|
||||
Cloudflare string `json:"cloudflare"`
|
||||
CFRay string `json:"cf-ray"`
|
||||
// NOTE: Cloudflare's online API documentation does not yet have definitions
|
||||
// for the following fields. See: https://api.cloudflare.com/#railgun-connections-for-a-zone-test-railgun-connection/
|
||||
CFWANError string `json:"cf-wan-error"`
|
||||
CFCacheStatus string `json:"cf-cache-status"`
|
||||
}
|
||||
|
||||
// railgunDiagnosisResponse represents the response from the Test Railgun Connection enpoint.
|
||||
type railgunDiagnosisResponse struct {
|
||||
Response
|
||||
Result RailgunDiagnosis `json:"result"`
|
||||
}
|
||||
|
||||
// ZoneRailguns returns the available Railguns for a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railguns-for-a-zone-get-available-railguns
|
||||
func (api *API) ZoneRailguns(zoneID string) ([]ZoneRailgun, error) {
|
||||
uri := "/zones/" + zoneID + "/railguns"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r zoneRailgunsResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ZoneRailgunDetails returns the configuration for a given Railgun.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railguns-for-a-zone-get-railgun-details
|
||||
func (api *API) ZoneRailgunDetails(zoneID, railgunID string) (ZoneRailgun, error) {
|
||||
uri := "/zones/" + zoneID + "/railguns/" + railgunID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return ZoneRailgun{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r zoneRailgunResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return ZoneRailgun{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// TestRailgunConnection tests a Railgun connection for a given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railgun-connections-for-a-zone-test-railgun-connection
|
||||
func (api *API) TestRailgunConnection(zoneID, railgunID string) (RailgunDiagnosis, error) {
|
||||
uri := "/zones/" + zoneID + "/railguns/" + railgunID + "/diagnose"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return RailgunDiagnosis{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r railgunDiagnosisResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return RailgunDiagnosis{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// connectZoneRailgun connects (true) or disconnects (false) a Railgun for a given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
|
||||
func (api *API) connectZoneRailgun(zoneID, railgunID string, connect bool) (ZoneRailgun, error) {
|
||||
uri := "/zones/" + zoneID + "/railguns/" + railgunID
|
||||
params := struct {
|
||||
Connected bool `json:"connected"`
|
||||
}{
|
||||
Connected: connect,
|
||||
}
|
||||
res, err := api.makeRequest("PATCH", uri, params)
|
||||
if err != nil {
|
||||
return ZoneRailgun{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r zoneRailgunResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return ZoneRailgun{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ConnectZoneRailgun connects a Railgun for a given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
|
||||
func (api *API) ConnectZoneRailgun(zoneID, railgunID string) (ZoneRailgun, error) {
|
||||
return api.connectZoneRailgun(zoneID, railgunID, true)
|
||||
}
|
||||
|
||||
// DisconnectZoneRailgun disconnects a Railgun for a given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
|
||||
func (api *API) DisconnectZoneRailgun(zoneID, railgunID string) (ZoneRailgun, error) {
|
||||
return api.connectZoneRailgun(zoneID, railgunID, false)
|
||||
}
|
195
vendor/github.com/cloudflare/cloudflare-go/rate_limiting.go
generated
vendored
Normal file
195
vendor/github.com/cloudflare/cloudflare-go/rate_limiting.go
generated
vendored
Normal file
|
@ -0,0 +1,195 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// RateLimit is a policy than can be applied to limit traffic within a customer domain
|
||||
type RateLimit struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Disabled bool `json:"disabled,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Match RateLimitTrafficMatcher `json:"match"`
|
||||
Bypass []RateLimitKeyValue `json:"bypass,omitempty"`
|
||||
Threshold int `json:"threshold"`
|
||||
Period int `json:"period"`
|
||||
Action RateLimitAction `json:"action"`
|
||||
}
|
||||
|
||||
// RateLimitTrafficMatcher contains the rules that will be used to apply a rate limit to traffic
|
||||
type RateLimitTrafficMatcher struct {
|
||||
Request RateLimitRequestMatcher `json:"request"`
|
||||
Response RateLimitResponseMatcher `json:"response"`
|
||||
}
|
||||
|
||||
// RateLimitRequestMatcher contains the matching rules pertaining to requests
|
||||
type RateLimitRequestMatcher struct {
|
||||
Methods []string `json:"methods,omitempty"`
|
||||
Schemes []string `json:"schemes,omitempty"`
|
||||
URLPattern string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// RateLimitResponseMatcher contains the matching rules pertaining to responses
|
||||
type RateLimitResponseMatcher struct {
|
||||
Statuses []int `json:"status,omitempty"`
|
||||
OriginTraffic *bool `json:"origin_traffic,omitempty"` // api defaults to true so we need an explicit empty value
|
||||
}
|
||||
|
||||
// RateLimitKeyValue is k-v formatted as expected in the rate limit description
|
||||
type RateLimitKeyValue struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// RateLimitAction is the action that will be taken when the rate limit threshold is reached
|
||||
type RateLimitAction struct {
|
||||
Mode string `json:"mode"`
|
||||
Timeout int `json:"timeout"`
|
||||
Response *RateLimitActionResponse `json:"response"`
|
||||
}
|
||||
|
||||
// RateLimitActionResponse is the response that will be returned when rate limit action is triggered
|
||||
type RateLimitActionResponse struct {
|
||||
ContentType string `json:"content_type"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
type rateLimitResponse struct {
|
||||
Response
|
||||
Result RateLimit `json:"result"`
|
||||
}
|
||||
|
||||
type rateLimitListResponse struct {
|
||||
Response
|
||||
Result []RateLimit `json:"result"`
|
||||
ResultInfo ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// CreateRateLimit creates a new rate limit for a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#rate-limits-for-a-zone-create-a-ratelimit
|
||||
func (api *API) CreateRateLimit(zoneID string, limit RateLimit) (RateLimit, error) {
|
||||
uri := "/zones/" + zoneID + "/rate_limits"
|
||||
res, err := api.makeRequest("POST", uri, limit)
|
||||
if err != nil {
|
||||
return RateLimit{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r rateLimitResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return RateLimit{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ListRateLimits returns Rate Limits for a zone, paginated according to the provided options
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#rate-limits-for-a-zone-list-rate-limits
|
||||
func (api *API) ListRateLimits(zoneID string, pageOpts PaginationOptions) ([]RateLimit, ResultInfo, error) {
|
||||
v := url.Values{}
|
||||
if pageOpts.PerPage > 0 {
|
||||
v.Set("per_page", strconv.Itoa(pageOpts.PerPage))
|
||||
}
|
||||
if pageOpts.Page > 0 {
|
||||
v.Set("page", strconv.Itoa(pageOpts.Page))
|
||||
}
|
||||
|
||||
uri := "/zones/" + zoneID + "/rate_limits"
|
||||
if len(v) > 0 {
|
||||
uri = uri + "?" + v.Encode()
|
||||
}
|
||||
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return []RateLimit{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
var r rateLimitListResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return []RateLimit{}, ResultInfo{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, r.ResultInfo, nil
|
||||
}
|
||||
|
||||
// ListAllRateLimits returns all Rate Limits for a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#rate-limits-for-a-zone-list-rate-limits
|
||||
func (api *API) ListAllRateLimits(zoneID string) ([]RateLimit, error) {
|
||||
pageOpts := PaginationOptions{
|
||||
PerPage: 100, // this is the max page size allowed
|
||||
Page: 1,
|
||||
}
|
||||
|
||||
allRateLimits := make([]RateLimit, 0)
|
||||
for {
|
||||
rateLimits, resultInfo, err := api.ListRateLimits(zoneID, pageOpts)
|
||||
if err != nil {
|
||||
return []RateLimit{}, err
|
||||
}
|
||||
allRateLimits = append(allRateLimits, rateLimits...)
|
||||
// total pages is not returned on this call
|
||||
// if number of records is less than the max, this must be the last page
|
||||
// in case TotalCount % PerPage = 0, the last request will return an empty list
|
||||
if resultInfo.Count < resultInfo.PerPage {
|
||||
break
|
||||
}
|
||||
// continue with the next page
|
||||
pageOpts.Page = pageOpts.Page + 1
|
||||
}
|
||||
|
||||
return allRateLimits, nil
|
||||
}
|
||||
|
||||
// RateLimit fetches detail about one Rate Limit for a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#rate-limits-for-a-zone-rate-limit-details
|
||||
func (api *API) RateLimit(zoneID, limitID string) (RateLimit, error) {
|
||||
uri := "/zones/" + zoneID + "/rate_limits/" + limitID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return RateLimit{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r rateLimitResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return RateLimit{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// UpdateRateLimit lets you replace a Rate Limit for a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#rate-limits-for-a-zone-update-rate-limit
|
||||
func (api *API) UpdateRateLimit(zoneID, limitID string, limit RateLimit) (RateLimit, error) {
|
||||
uri := "/zones/" + zoneID + "/rate_limits/" + limitID
|
||||
res, err := api.makeRequest("PUT", uri, limit)
|
||||
if err != nil {
|
||||
return RateLimit{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r rateLimitResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return RateLimit{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// DeleteRateLimit deletes a Rate Limit for a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#rate-limits-for-a-zone-delete-rate-limit
|
||||
func (api *API) DeleteRateLimit(zoneID, limitID string) error {
|
||||
uri := "/zones/" + zoneID + "/rate_limits/" + limitID
|
||||
res, err := api.makeRequest("DELETE", uri, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r rateLimitResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return nil
|
||||
}
|
148
vendor/github.com/cloudflare/cloudflare-go/ssl.go
generated
vendored
Normal file
148
vendor/github.com/cloudflare/cloudflare-go/ssl.go
generated
vendored
Normal file
|
@ -0,0 +1,148 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ZoneCustomSSL represents custom SSL certificate metadata.
|
||||
type ZoneCustomSSL struct {
|
||||
ID string `json:"id"`
|
||||
Hosts []string `json:"hosts"`
|
||||
Issuer string `json:"issuer"`
|
||||
Signature string `json:"signature"`
|
||||
Status string `json:"status"`
|
||||
BundleMethod string `json:"bundle_method"`
|
||||
ZoneID string `json:"zone_id"`
|
||||
UploadedOn time.Time `json:"uploaded_on"`
|
||||
ModifiedOn time.Time `json:"modified_on"`
|
||||
ExpiresOn time.Time `json:"expires_on"`
|
||||
Priority int `json:"priority"`
|
||||
KeylessServer KeylessSSL `json:"keyless_server"`
|
||||
}
|
||||
|
||||
// zoneCustomSSLResponse represents the response from the zone SSL details endpoint.
|
||||
type zoneCustomSSLResponse struct {
|
||||
Response
|
||||
Result ZoneCustomSSL `json:"result"`
|
||||
}
|
||||
|
||||
// zoneCustomSSLsResponse represents the response from the zone SSL list endpoint.
|
||||
type zoneCustomSSLsResponse struct {
|
||||
Response
|
||||
Result []ZoneCustomSSL `json:"result"`
|
||||
}
|
||||
|
||||
// ZoneCustomSSLOptions represents the parameters to create or update an existing
|
||||
// custom SSL configuration.
|
||||
type ZoneCustomSSLOptions struct {
|
||||
Certificate string `json:"certificate"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
BundleMethod string `json:"bundle_method,omitempty"`
|
||||
}
|
||||
|
||||
// ZoneCustomSSLPriority represents a certificate's ID and priority. It is a
|
||||
// subset of ZoneCustomSSL used for patch requests.
|
||||
type ZoneCustomSSLPriority struct {
|
||||
ID string `json:"ID"`
|
||||
Priority int `json:"priority"`
|
||||
}
|
||||
|
||||
// CreateSSL allows you to add a custom SSL certificate to the given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#custom-ssl-for-a-zone-create-ssl-configuration
|
||||
func (api *API) CreateSSL(zoneID string, options ZoneCustomSSLOptions) (ZoneCustomSSL, error) {
|
||||
uri := "/zones/" + zoneID + "/custom_certificates"
|
||||
res, err := api.makeRequest("POST", uri, options)
|
||||
if err != nil {
|
||||
return ZoneCustomSSL{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r zoneCustomSSLResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return ZoneCustomSSL{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ListSSL lists the custom certificates for the given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#custom-ssl-for-a-zone-list-ssl-configurations
|
||||
func (api *API) ListSSL(zoneID string) ([]ZoneCustomSSL, error) {
|
||||
uri := "/zones/" + zoneID + "/custom_certificates"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r zoneCustomSSLsResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// SSLDetails returns the configuration details for a custom SSL certificate.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#custom-ssl-for-a-zone-ssl-configuration-details
|
||||
func (api *API) SSLDetails(zoneID, certificateID string) (ZoneCustomSSL, error) {
|
||||
uri := "/zones/" + zoneID + "/custom_certificates/" + certificateID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return ZoneCustomSSL{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r zoneCustomSSLResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return ZoneCustomSSL{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// UpdateSSL updates (replaces) a custom SSL certificate.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#custom-ssl-for-a-zone-update-ssl-configuration
|
||||
func (api *API) UpdateSSL(zoneID, certificateID string, options ZoneCustomSSLOptions) (ZoneCustomSSL, error) {
|
||||
uri := "/zones/" + zoneID + "/custom_certificates/" + certificateID
|
||||
res, err := api.makeRequest("PATCH", uri, options)
|
||||
if err != nil {
|
||||
return ZoneCustomSSL{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r zoneCustomSSLResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return ZoneCustomSSL{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ReprioritizeSSL allows you to change the priority (which is served for a given
|
||||
// request) of custom SSL certificates associated with the given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#custom-ssl-for-a-zone-re-prioritize-ssl-certificates
|
||||
func (api *API) ReprioritizeSSL(zoneID string, p []ZoneCustomSSLPriority) ([]ZoneCustomSSL, error) {
|
||||
uri := "/zones/" + zoneID + "/custom_certificates/prioritize"
|
||||
params := struct {
|
||||
Certificates []ZoneCustomSSLPriority `json:"certificates"`
|
||||
}{
|
||||
Certificates: p,
|
||||
}
|
||||
res, err := api.makeRequest("PUT", uri, params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r zoneCustomSSLsResponse
|
||||
if err := json.Unmarshal(res, &r); err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// DeleteSSL deletes a custom SSL certificate from the given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#custom-ssl-for-a-zone-delete-an-ssl-certificate
|
||||
func (api *API) DeleteSSL(zoneID, certificateID string) error {
|
||||
uri := "/zones/" + zoneID + "/custom_certificates/" + certificateID
|
||||
if _, err := api.makeRequest("DELETE", uri, nil); err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
return nil
|
||||
}
|
113
vendor/github.com/cloudflare/cloudflare-go/user.go
generated
vendored
Normal file
113
vendor/github.com/cloudflare/cloudflare-go/user.go
generated
vendored
Normal file
|
@ -0,0 +1,113 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// User describes a user account.
|
||||
type User struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
FirstName string `json:"first_name,omitempty"`
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Telephone string `json:"telephone,omitempty"`
|
||||
Country string `json:"country,omitempty"`
|
||||
Zipcode string `json:"zipcode,omitempty"`
|
||||
CreatedOn *time.Time `json:"created_on,omitempty"`
|
||||
ModifiedOn *time.Time `json:"modified_on,omitempty"`
|
||||
APIKey string `json:"api_key,omitempty"`
|
||||
TwoFA bool `json:"two_factor_authentication_enabled,omitempty"`
|
||||
Betas []string `json:"betas,omitempty"`
|
||||
Organizations []Organization `json:"organizations,omitempty"`
|
||||
}
|
||||
|
||||
// UserResponse wraps a response containing User accounts.
|
||||
type UserResponse struct {
|
||||
Response
|
||||
Result User `json:"result"`
|
||||
}
|
||||
|
||||
// userBillingProfileResponse wraps a response containing Billing Profile information.
|
||||
type userBillingProfileResponse struct {
|
||||
Response
|
||||
Result UserBillingProfile
|
||||
}
|
||||
|
||||
// UserBillingProfile contains Billing Profile information.
|
||||
type UserBillingProfile struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
FirstName string `json:"first_name,omitempty"`
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Address2 string `json:"address2,omitempty"`
|
||||
Company string `json:"company,omitempty"`
|
||||
City string `json:"city,omitempty"`
|
||||
State string `json:"state,omitempty"`
|
||||
ZipCode string `json:"zipcode,omitempty"`
|
||||
Country string `json:"country,omitempty"`
|
||||
Telephone string `json:"telephone,omitempty"`
|
||||
CardNumber string `json:"card_number,omitempty"`
|
||||
CardExpiryYear int `json:"card_expiry_year,omitempty"`
|
||||
CardExpiryMonth int `json:"card_expiry_month,omitempty"`
|
||||
VAT string `json:"vat,omitempty"`
|
||||
CreatedOn *time.Time `json:"created_on,omitempty"`
|
||||
EditedOn *time.Time `json:"edited_on,omitempty"`
|
||||
}
|
||||
|
||||
// UserDetails provides information about the logged-in user.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-user-details
|
||||
func (api *API) UserDetails() (User, error) {
|
||||
var r UserResponse
|
||||
res, err := api.makeRequest("GET", "/user", nil)
|
||||
if err != nil {
|
||||
return User{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return User{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// UpdateUser updates the properties of the given user.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-update-user
|
||||
func (api *API) UpdateUser(user *User) (User, error) {
|
||||
var r UserResponse
|
||||
res, err := api.makeRequest("PATCH", "/user", user)
|
||||
if err != nil {
|
||||
return User{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return User{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// UserBillingProfile returns the billing profile of the user.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-billing-profile
|
||||
func (api *API) UserBillingProfile() (UserBillingProfile, error) {
|
||||
var r userBillingProfileResponse
|
||||
res, err := api.makeRequest("GET", "/user/billing/profile", nil)
|
||||
if err != nil {
|
||||
return UserBillingProfile{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return UserBillingProfile{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return r.Result, nil
|
||||
}
|
149
vendor/github.com/cloudflare/cloudflare-go/user_agent.go
generated
vendored
Normal file
149
vendor/github.com/cloudflare/cloudflare-go/user_agent.go
generated
vendored
Normal file
|
@ -0,0 +1,149 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// UserAgentRule represents a User-Agent Block. These rules can be used to
|
||||
// challenge, block or whitelist specific User-Agents for a given zone.
|
||||
type UserAgentRule struct {
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description"`
|
||||
Mode string `json:"mode"`
|
||||
Configuration UserAgentRuleConfig `json:"configuration"`
|
||||
Paused bool `json:"paused"`
|
||||
}
|
||||
|
||||
// UserAgentRuleConfig represents a Zone Lockdown config, which comprises
|
||||
// a Target ("ip" or "ip_range") and a Value (an IP address or IP+mask,
|
||||
// respectively.)
|
||||
type UserAgentRuleConfig ZoneLockdownConfig
|
||||
|
||||
// UserAgentRuleResponse represents a response from the Zone Lockdown endpoint.
|
||||
type UserAgentRuleResponse struct {
|
||||
Result UserAgentRule `json:"result"`
|
||||
Response
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// UserAgentRuleListResponse represents a response from the List Zone Lockdown endpoint.
|
||||
type UserAgentRuleListResponse struct {
|
||||
Result []UserAgentRule `json:"result"`
|
||||
Response
|
||||
ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// CreateUserAgentRule creates a User-Agent Block rule for the given zone ID.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-agent-blocking-rules-create-a-useragent-rule
|
||||
func (api *API) CreateUserAgentRule(zoneID string, ld UserAgentRule) (*UserAgentRuleResponse, error) {
|
||||
switch ld.Mode {
|
||||
case "block", "challenge", "js_challenge", "whitelist":
|
||||
break
|
||||
default:
|
||||
return nil, errors.New(`the User-Agent Block rule mode must be one of "block", "challenge", "js_challenge", "whitelist"`)
|
||||
}
|
||||
|
||||
uri := "/zones/" + zoneID + "/firewall/ua_rules"
|
||||
res, err := api.makeRequest("POST", uri, ld)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &UserAgentRuleResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// UpdateUserAgentRule updates a User-Agent Block rule (based on the ID) for the given zone ID.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-agent-blocking-rules-update-useragent-rule
|
||||
func (api *API) UpdateUserAgentRule(zoneID string, id string, ld UserAgentRule) (*UserAgentRuleResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/firewall/ua_rules/" + id
|
||||
res, err := api.makeRequest("PUT", uri, ld)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &UserAgentRuleResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// DeleteUserAgentRule deletes a User-Agent Block rule (based on the ID) for the given zone ID.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-agent-blocking-rules-delete-useragent-rule
|
||||
func (api *API) DeleteUserAgentRule(zoneID string, id string) (*UserAgentRuleResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/firewall/ua_rules/" + id
|
||||
res, err := api.makeRequest("DELETE", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &UserAgentRuleResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// UserAgentRule retrieves a User-Agent Block rule (based on the ID) for the given zone ID.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-agent-blocking-rules-useragent-rule-details
|
||||
func (api *API) UserAgentRule(zoneID string, id string) (*UserAgentRuleResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/firewall/ua_rules/" + id
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &UserAgentRuleResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ListUserAgentRules retrieves a list of User-Agent Block rules for a given zone ID by page number.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#user-agent-blocking-rules-list-useragent-rules
|
||||
func (api *API) ListUserAgentRules(zoneID string, page int) (*UserAgentRuleListResponse, error) {
|
||||
v := url.Values{}
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
v.Set("page", strconv.Itoa(page))
|
||||
v.Set("per_page", strconv.Itoa(100))
|
||||
query := "?" + v.Encode()
|
||||
|
||||
uri := "/zones/" + zoneID + "/firewall/ua_rules" + query
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &UserAgentRuleListResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
125
vendor/github.com/cloudflare/cloudflare-go/virtualdns.go
generated
vendored
Normal file
125
vendor/github.com/cloudflare/cloudflare-go/virtualdns.go
generated
vendored
Normal file
|
@ -0,0 +1,125 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// VirtualDNS represents a Virtual DNS configuration.
|
||||
type VirtualDNS struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
OriginIPs []string `json:"origin_ips"`
|
||||
VirtualDNSIPs []string `json:"virtual_dns_ips"`
|
||||
MinimumCacheTTL uint `json:"minimum_cache_ttl"`
|
||||
MaximumCacheTTL uint `json:"maximum_cache_ttl"`
|
||||
DeprecateAnyRequests bool `json:"deprecate_any_requests"`
|
||||
ModifiedOn string `json:"modified_on"`
|
||||
}
|
||||
|
||||
// VirtualDNSResponse represents a Virtual DNS response.
|
||||
type VirtualDNSResponse struct {
|
||||
Response
|
||||
Result *VirtualDNS `json:"result"`
|
||||
}
|
||||
|
||||
// VirtualDNSListResponse represents an array of Virtual DNS responses.
|
||||
type VirtualDNSListResponse struct {
|
||||
Response
|
||||
Result []*VirtualDNS `json:"result"`
|
||||
}
|
||||
|
||||
// CreateVirtualDNS creates a new Virtual DNS cluster.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#virtual-dns-users--create-a-virtual-dns-cluster
|
||||
func (api *API) CreateVirtualDNS(v *VirtualDNS) (*VirtualDNS, error) {
|
||||
res, err := api.makeRequest("POST", "/user/virtual_dns", v)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &VirtualDNSResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response.Result, nil
|
||||
}
|
||||
|
||||
// VirtualDNS fetches a single virtual DNS cluster.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#virtual-dns-users--get-a-virtual-dns-cluster
|
||||
func (api *API) VirtualDNS(virtualDNSID string) (*VirtualDNS, error) {
|
||||
uri := "/user/virtual_dns/" + virtualDNSID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &VirtualDNSResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response.Result, nil
|
||||
}
|
||||
|
||||
// ListVirtualDNS lists the virtual DNS clusters associated with an account.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#virtual-dns-users--get-virtual-dns-clusters
|
||||
func (api *API) ListVirtualDNS() ([]*VirtualDNS, error) {
|
||||
res, err := api.makeRequest("GET", "/user/virtual_dns", nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &VirtualDNSListResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response.Result, nil
|
||||
}
|
||||
|
||||
// UpdateVirtualDNS updates a Virtual DNS cluster.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#virtual-dns-users--modify-a-virtual-dns-cluster
|
||||
func (api *API) UpdateVirtualDNS(virtualDNSID string, vv VirtualDNS) error {
|
||||
uri := "/user/virtual_dns/" + virtualDNSID
|
||||
res, err := api.makeRequest("PUT", uri, vv)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &VirtualDNSResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteVirtualDNS deletes a Virtual DNS cluster. Note that this cannot be
|
||||
// undone, and will stop all traffic to that cluster.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#virtual-dns-users--delete-a-virtual-dns-cluster
|
||||
func (api *API) DeleteVirtualDNS(virtualDNSID string) error {
|
||||
uri := "/user/virtual_dns/" + virtualDNSID
|
||||
res, err := api.makeRequest("DELETE", uri, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &VirtualDNSResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
97
vendor/github.com/cloudflare/cloudflare-go/waf.go
generated
vendored
Normal file
97
vendor/github.com/cloudflare/cloudflare-go/waf.go
generated
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// WAFPackage represents a WAF package configuration.
|
||||
type WAFPackage struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ZoneID string `json:"zone_id"`
|
||||
DetectionMode string `json:"detection_mode"`
|
||||
Sensitivity string `json:"sensitivity"`
|
||||
ActionMode string `json:"action_mode"`
|
||||
}
|
||||
|
||||
// WAFPackagesResponse represents the response from the WAF packages endpoint.
|
||||
type WAFPackagesResponse struct {
|
||||
Response
|
||||
Result []WAFPackage `json:"result"`
|
||||
ResultInfo ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// WAFRule represents a WAF rule.
|
||||
type WAFRule struct {
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description"`
|
||||
Priority string `json:"priority"`
|
||||
PackageID string `json:"package_id"`
|
||||
Group struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"group"`
|
||||
Mode string `json:"mode"`
|
||||
DefaultMode string `json:"default_mode"`
|
||||
AllowedModes []string `json:"allowed_modes"`
|
||||
}
|
||||
|
||||
// WAFRulesResponse represents the response from the WAF rule endpoint.
|
||||
type WAFRulesResponse struct {
|
||||
Response
|
||||
Result []WAFRule `json:"result"`
|
||||
ResultInfo ResultInfo `json:"result_info"`
|
||||
}
|
||||
|
||||
// ListWAFPackages returns a slice of the WAF packages for the given zone.
|
||||
func (api *API) ListWAFPackages(zoneID string) ([]WAFPackage, error) {
|
||||
var p WAFPackagesResponse
|
||||
var packages []WAFPackage
|
||||
var res []byte
|
||||
var err error
|
||||
uri := "/zones/" + zoneID + "/firewall/waf/packages"
|
||||
res, err = api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return []WAFPackage{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
err = json.Unmarshal(res, &p)
|
||||
if err != nil {
|
||||
return []WAFPackage{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
if !p.Success {
|
||||
// TODO: Provide an actual error message instead of always returning nil
|
||||
return []WAFPackage{}, err
|
||||
}
|
||||
for pi := range p.Result {
|
||||
packages = append(packages, p.Result[pi])
|
||||
}
|
||||
return packages, nil
|
||||
}
|
||||
|
||||
// ListWAFRules returns a slice of the WAF rules for the given WAF package.
|
||||
func (api *API) ListWAFRules(zoneID, packageID string) ([]WAFRule, error) {
|
||||
var r WAFRulesResponse
|
||||
var rules []WAFRule
|
||||
var res []byte
|
||||
var err error
|
||||
uri := "/zones/" + zoneID + "/firewall/waf/packages/" + packageID + "/rules"
|
||||
res, err = api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return []WAFRule{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return []WAFRule{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
if !r.Success {
|
||||
// TODO: Provide an actual error message instead of always returning nil
|
||||
return []WAFRule{}, err
|
||||
}
|
||||
for ri := range r.Result {
|
||||
rules = append(rules, r.Result[ri])
|
||||
}
|
||||
return rules, nil
|
||||
}
|
587
vendor/github.com/cloudflare/cloudflare-go/zone.go
generated
vendored
Normal file
587
vendor/github.com/cloudflare/cloudflare-go/zone.go
generated
vendored
Normal file
|
@ -0,0 +1,587 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Owner describes the resource owner.
|
||||
type Owner struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
OwnerType string `json:"owner_type"`
|
||||
}
|
||||
|
||||
// Zone describes a Cloudflare zone.
|
||||
type Zone struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
// DevMode contains the time in seconds until development expires (if
|
||||
// positive) or since it expired (if negative). It will be 0 if never used.
|
||||
DevMode int `json:"development_mode"`
|
||||
OriginalNS []string `json:"original_name_servers"`
|
||||
OriginalRegistrar string `json:"original_registrar"`
|
||||
OriginalDNSHost string `json:"original_dnshost"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
ModifiedOn time.Time `json:"modified_on"`
|
||||
NameServers []string `json:"name_servers"`
|
||||
Owner Owner `json:"owner"`
|
||||
Permissions []string `json:"permissions"`
|
||||
Plan ZoneRatePlan `json:"plan"`
|
||||
PlanPending ZoneRatePlan `json:"plan_pending,omitempty"`
|
||||
Status string `json:"status"`
|
||||
Paused bool `json:"paused"`
|
||||
Type string `json:"type"`
|
||||
Host struct {
|
||||
Name string
|
||||
Website string
|
||||
} `json:"host"`
|
||||
VanityNS []string `json:"vanity_name_servers"`
|
||||
Betas []string `json:"betas"`
|
||||
DeactReason string `json:"deactivation_reason"`
|
||||
Meta ZoneMeta `json:"meta"`
|
||||
}
|
||||
|
||||
// ZoneMeta describes metadata about a zone.
|
||||
type ZoneMeta struct {
|
||||
// custom_certificate_quota is broken - sometimes it's a string, sometimes a number!
|
||||
// CustCertQuota int `json:"custom_certificate_quota"`
|
||||
PageRuleQuota int `json:"page_rule_quota"`
|
||||
WildcardProxiable bool `json:"wildcard_proxiable"`
|
||||
PhishingDetected bool `json:"phishing_detected"`
|
||||
}
|
||||
|
||||
// ZoneRatePlan contains the plan information for a zone.
|
||||
type ZoneRatePlan struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Price int `json:"price,omitempty"`
|
||||
Currency string `json:"currency,omitempty"`
|
||||
Duration int `json:"duration,omitempty"`
|
||||
Frequency string `json:"frequency,omitempty"`
|
||||
Components []zoneRatePlanComponents `json:"components,omitempty"`
|
||||
}
|
||||
|
||||
type zoneRatePlanComponents struct {
|
||||
Name string `json:"name"`
|
||||
Default int `json:"Default"`
|
||||
UnitPrice int `json:"unit_price"`
|
||||
}
|
||||
|
||||
// ZoneID contains only the zone ID.
|
||||
type ZoneID struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
// ZoneResponse represents the response from the Zone endpoint containing a single zone.
|
||||
type ZoneResponse struct {
|
||||
Response
|
||||
Result Zone `json:"result"`
|
||||
}
|
||||
|
||||
// ZonesResponse represents the response from the Zone endpoint containing an array of zones.
|
||||
type ZonesResponse struct {
|
||||
Response
|
||||
Result []Zone `json:"result"`
|
||||
}
|
||||
|
||||
// ZoneIDResponse represents the response from the Zone endpoint, containing only a zone ID.
|
||||
type ZoneIDResponse struct {
|
||||
Response
|
||||
Result ZoneID `json:"result"`
|
||||
}
|
||||
|
||||
// AvailableZoneRatePlansResponse represents the response from the Available Rate Plans endpoint.
|
||||
type AvailableZoneRatePlansResponse struct {
|
||||
Response
|
||||
Result []ZoneRatePlan `json:"result"`
|
||||
ResultInfo
|
||||
}
|
||||
|
||||
// ZoneRatePlanResponse represents the response from the Plan Details endpoint.
|
||||
type ZoneRatePlanResponse struct {
|
||||
Response
|
||||
Result ZoneRatePlan `json:"result"`
|
||||
}
|
||||
|
||||
// ZoneSetting contains settings for a zone.
|
||||
type ZoneSetting struct {
|
||||
ID string `json:"id"`
|
||||
Editable bool `json:"editable"`
|
||||
ModifiedOn string `json:"modified_on"`
|
||||
Value interface{} `json:"value"`
|
||||
TimeRemaining int `json:"time_remaining"`
|
||||
}
|
||||
|
||||
// ZoneSettingResponse represents the response from the Zone Setting endpoint.
|
||||
type ZoneSettingResponse struct {
|
||||
Response
|
||||
Result []ZoneSetting `json:"result"`
|
||||
}
|
||||
|
||||
// ZoneSSLSetting contains ssl setting for a zone.
|
||||
type ZoneSSLSetting struct {
|
||||
ID string `json:"id"`
|
||||
Editable bool `json:"editable"`
|
||||
ModifiedOn string `json:"modified_on"`
|
||||
Value string `json:"value"`
|
||||
CertificateStatus string `json:"certificate_status"`
|
||||
}
|
||||
|
||||
// ZoneSettingResponse represents the response from the Zone SSL Setting endpoint.
|
||||
type ZoneSSLSettingResponse struct {
|
||||
Response
|
||||
Result ZoneSSLSetting `json:"result"`
|
||||
}
|
||||
|
||||
// ZoneAnalyticsData contains totals and timeseries analytics data for a zone.
|
||||
type ZoneAnalyticsData struct {
|
||||
Totals ZoneAnalytics `json:"totals"`
|
||||
Timeseries []ZoneAnalytics `json:"timeseries"`
|
||||
}
|
||||
|
||||
// zoneAnalyticsDataResponse represents the response from the Zone Analytics Dashboard endpoint.
|
||||
type zoneAnalyticsDataResponse struct {
|
||||
Response
|
||||
Result ZoneAnalyticsData `json:"result"`
|
||||
}
|
||||
|
||||
// ZoneAnalyticsColocation contains analytics data by datacenter.
|
||||
type ZoneAnalyticsColocation struct {
|
||||
ColocationID string `json:"colo_id"`
|
||||
Timeseries []ZoneAnalytics `json:"timeseries"`
|
||||
}
|
||||
|
||||
// zoneAnalyticsColocationResponse represents the response from the Zone Analytics By Co-location endpoint.
|
||||
type zoneAnalyticsColocationResponse struct {
|
||||
Response
|
||||
Result []ZoneAnalyticsColocation `json:"result"`
|
||||
}
|
||||
|
||||
// ZoneAnalytics contains analytics data for a zone.
|
||||
type ZoneAnalytics struct {
|
||||
Since time.Time `json:"since"`
|
||||
Until time.Time `json:"until"`
|
||||
Requests struct {
|
||||
All int `json:"all"`
|
||||
Cached int `json:"cached"`
|
||||
Uncached int `json:"uncached"`
|
||||
ContentType map[string]int `json:"content_type"`
|
||||
Country map[string]int `json:"country"`
|
||||
SSL struct {
|
||||
Encrypted int `json:"encrypted"`
|
||||
Unencrypted int `json:"unencrypted"`
|
||||
} `json:"ssl"`
|
||||
HTTPStatus map[string]int `json:"http_status"`
|
||||
} `json:"requests"`
|
||||
Bandwidth struct {
|
||||
All int `json:"all"`
|
||||
Cached int `json:"cached"`
|
||||
Uncached int `json:"uncached"`
|
||||
ContentType map[string]int `json:"content_type"`
|
||||
Country map[string]int `json:"country"`
|
||||
SSL struct {
|
||||
Encrypted int `json:"encrypted"`
|
||||
Unencrypted int `json:"unencrypted"`
|
||||
} `json:"ssl"`
|
||||
} `json:"bandwidth"`
|
||||
Threats struct {
|
||||
All int `json:"all"`
|
||||
Country map[string]int `json:"country"`
|
||||
Type map[string]int `json:"type"`
|
||||
} `json:"threats"`
|
||||
Pageviews struct {
|
||||
All int `json:"all"`
|
||||
SearchEngines map[string]int `json:"search_engines"`
|
||||
} `json:"pageviews"`
|
||||
Uniques struct {
|
||||
All int `json:"all"`
|
||||
}
|
||||
}
|
||||
|
||||
// ZoneAnalyticsOptions represents the optional parameters in Zone Analytics
|
||||
// endpoint requests.
|
||||
type ZoneAnalyticsOptions struct {
|
||||
Since *time.Time
|
||||
Until *time.Time
|
||||
Continuous *bool
|
||||
}
|
||||
|
||||
// PurgeCacheRequest represents the request format made to the purge endpoint.
|
||||
type PurgeCacheRequest struct {
|
||||
Everything bool `json:"purge_everything,omitempty"`
|
||||
// Purge by filepath (exact match). Limit of 30
|
||||
Files []string `json:"files,omitempty"`
|
||||
// Purge by Tag (Enterprise only):
|
||||
// https://support.cloudflare.com/hc/en-us/articles/206596608-How-to-Purge-Cache-Using-Cache-Tags-Enterprise-only-
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
// Purge by hostname - e.g. "assets.example.com"
|
||||
Hosts []string `json:"hosts,omitempty"`
|
||||
}
|
||||
|
||||
// PurgeCacheResponse represents the response from the purge endpoint.
|
||||
type PurgeCacheResponse struct {
|
||||
Response
|
||||
Result struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"result"`
|
||||
}
|
||||
|
||||
// newZone describes a new zone.
|
||||
type newZone struct {
|
||||
Name string `json:"name"`
|
||||
JumpStart bool `json:"jump_start"`
|
||||
// We use a pointer to get a nil type when the field is empty.
|
||||
// This allows us to completely omit this with json.Marshal().
|
||||
Organization *Organization `json:"organization,omitempty"`
|
||||
}
|
||||
|
||||
// CreateZone creates a zone on an account.
|
||||
//
|
||||
// Setting jumpstart to true will attempt to automatically scan for existing
|
||||
// DNS records. Setting this to false will create the zone with no DNS records.
|
||||
//
|
||||
// If Organization is non-empty, it must have at least the ID field populated.
|
||||
// This will add the new zone to the specified multi-user organization.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-create-a-zone
|
||||
func (api *API) CreateZone(name string, jumpstart bool, org Organization) (Zone, error) {
|
||||
var newzone newZone
|
||||
newzone.Name = name
|
||||
newzone.JumpStart = jumpstart
|
||||
if org.ID != "" {
|
||||
newzone.Organization = &org
|
||||
}
|
||||
|
||||
res, err := api.makeRequest("POST", "/zones", newzone)
|
||||
if err != nil {
|
||||
return Zone{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
var r ZoneResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return Zone{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ZoneActivationCheck initiates another zone activation check for newly-created zones.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-initiate-another-zone-activation-check
|
||||
func (api *API) ZoneActivationCheck(zoneID string) (Response, error) {
|
||||
res, err := api.makeRequest("PUT", "/zones/"+zoneID+"/activation_check", nil)
|
||||
if err != nil {
|
||||
return Response{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r Response
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return Response{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// ListZones lists zones on an account. Optionally takes a list of zone names
|
||||
// to filter against.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-list-zones
|
||||
func (api *API) ListZones(z ...string) ([]Zone, error) {
|
||||
v := url.Values{}
|
||||
var res []byte
|
||||
var r ZonesResponse
|
||||
var zones []Zone
|
||||
var err error
|
||||
if len(z) > 0 {
|
||||
for _, zone := range z {
|
||||
v.Set("name", zone)
|
||||
res, err = api.makeRequest("GET", "/zones?"+v.Encode(), nil)
|
||||
if err != nil {
|
||||
return []Zone{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return []Zone{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
if !r.Success {
|
||||
// TODO: Provide an actual error message instead of always returning nil
|
||||
return []Zone{}, err
|
||||
}
|
||||
for zi := range r.Result {
|
||||
zones = append(zones, r.Result[zi])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: Paginate here. We only grab the first page of results.
|
||||
// Could do this concurrently after the first request by creating a
|
||||
// sync.WaitGroup or just a channel + workers.
|
||||
res, err = api.makeRequest("GET", "/zones", nil)
|
||||
if err != nil {
|
||||
return []Zone{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return []Zone{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
zones = r.Result
|
||||
}
|
||||
|
||||
return zones, nil
|
||||
}
|
||||
|
||||
// ZoneDetails fetches information about a zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-zone-details
|
||||
func (api *API) ZoneDetails(zoneID string) (Zone, error) {
|
||||
res, err := api.makeRequest("GET", "/zones/"+zoneID, nil)
|
||||
if err != nil {
|
||||
return Zone{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r ZoneResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return Zone{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ZoneOptions is a subset of Zone, for editable options.
|
||||
type ZoneOptions struct {
|
||||
Paused *bool `json:"paused,omitempty"`
|
||||
VanityNS []string `json:"vanity_name_servers,omitempty"`
|
||||
Plan *ZoneRatePlan `json:"plan,omitempty"`
|
||||
}
|
||||
|
||||
// ZoneSetPaused pauses Cloudflare service for the entire zone, sending all
|
||||
// traffic direct to the origin.
|
||||
func (api *API) ZoneSetPaused(zoneID string, paused bool) (Zone, error) {
|
||||
zoneopts := ZoneOptions{Paused: &paused}
|
||||
zone, err := api.EditZone(zoneID, zoneopts)
|
||||
if err != nil {
|
||||
return Zone{}, err
|
||||
}
|
||||
|
||||
return zone, nil
|
||||
}
|
||||
|
||||
// ZoneSetVanityNS sets custom nameservers for the zone.
|
||||
// These names must be within the same zone.
|
||||
func (api *API) ZoneSetVanityNS(zoneID string, ns []string) (Zone, error) {
|
||||
zoneopts := ZoneOptions{VanityNS: ns}
|
||||
zone, err := api.EditZone(zoneID, zoneopts)
|
||||
if err != nil {
|
||||
return Zone{}, err
|
||||
}
|
||||
|
||||
return zone, nil
|
||||
}
|
||||
|
||||
// ZoneSetRatePlan changes the zone plan.
|
||||
func (api *API) ZoneSetRatePlan(zoneID string, plan ZoneRatePlan) (Zone, error) {
|
||||
zoneopts := ZoneOptions{Plan: &plan}
|
||||
zone, err := api.EditZone(zoneID, zoneopts)
|
||||
if err != nil {
|
||||
return Zone{}, err
|
||||
}
|
||||
|
||||
return zone, nil
|
||||
}
|
||||
|
||||
// EditZone edits the given zone.
|
||||
//
|
||||
// This is usually called by ZoneSetPaused, ZoneSetVanityNS or ZoneSetPlan.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-edit-zone-properties
|
||||
func (api *API) EditZone(zoneID string, zoneOpts ZoneOptions) (Zone, error) {
|
||||
res, err := api.makeRequest("PATCH", "/zones/"+zoneID, zoneOpts)
|
||||
if err != nil {
|
||||
return Zone{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r ZoneResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return Zone{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// PurgeEverything purges the cache for the given zone.
|
||||
//
|
||||
// Note: this will substantially increase load on the origin server for that
|
||||
// zone if there is a high cached vs. uncached request ratio.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-purge-all-files
|
||||
func (api *API) PurgeEverything(zoneID string) (PurgeCacheResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/purge_cache"
|
||||
res, err := api.makeRequest("DELETE", uri, PurgeCacheRequest{true, nil, nil, nil})
|
||||
if err != nil {
|
||||
return PurgeCacheResponse{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r PurgeCacheResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return PurgeCacheResponse{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// PurgeCache purges the cache using the given PurgeCacheRequest (zone/url/tag).
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-purge-individual-files-by-url-and-cache-tags
|
||||
func (api *API) PurgeCache(zoneID string, pcr PurgeCacheRequest) (PurgeCacheResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/purge_cache"
|
||||
res, err := api.makeRequest("DELETE", uri, pcr)
|
||||
if err != nil {
|
||||
return PurgeCacheResponse{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r PurgeCacheResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return PurgeCacheResponse{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// DeleteZone deletes the given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-delete-a-zone
|
||||
func (api *API) DeleteZone(zoneID string) (ZoneID, error) {
|
||||
res, err := api.makeRequest("DELETE", "/zones/"+zoneID, nil)
|
||||
if err != nil {
|
||||
return ZoneID{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r ZoneIDResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return ZoneID{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// AvailableZoneRatePlans returns information about all plans available to the specified zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-plan-available-plans
|
||||
func (api *API) AvailableZoneRatePlans(zoneID string) ([]ZoneRatePlan, error) {
|
||||
uri := "/zones/" + zoneID + "/available_rate_plans"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return []ZoneRatePlan{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r AvailableZoneRatePlansResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return []ZoneRatePlan{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// encode encodes non-nil fields into URL encoded form.
|
||||
func (o ZoneAnalyticsOptions) encode() string {
|
||||
v := url.Values{}
|
||||
if o.Since != nil {
|
||||
v.Set("since", (*o.Since).Format(time.RFC3339))
|
||||
}
|
||||
if o.Until != nil {
|
||||
v.Set("until", (*o.Until).Format(time.RFC3339))
|
||||
}
|
||||
if o.Continuous != nil {
|
||||
v.Set("continuous", fmt.Sprintf("%t", *o.Continuous))
|
||||
}
|
||||
return v.Encode()
|
||||
}
|
||||
|
||||
// ZoneAnalyticsDashboard returns zone analytics information.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-analytics-dashboard
|
||||
func (api *API) ZoneAnalyticsDashboard(zoneID string, options ZoneAnalyticsOptions) (ZoneAnalyticsData, error) {
|
||||
uri := "/zones/" + zoneID + "/analytics/dashboard" + "?" + options.encode()
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return ZoneAnalyticsData{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r zoneAnalyticsDataResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return ZoneAnalyticsData{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ZoneAnalyticsByColocation returns zone analytics information by datacenter.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-analytics-analytics-by-co-locations
|
||||
func (api *API) ZoneAnalyticsByColocation(zoneID string, options ZoneAnalyticsOptions) ([]ZoneAnalyticsColocation, error) {
|
||||
uri := "/zones/" + zoneID + "/analytics/colos" + "?" + options.encode()
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r zoneAnalyticsColocationResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ZoneSettings returns all of the settings for a given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-settings-get-all-zone-settings
|
||||
func (api *API) ZoneSettings(zoneID string) (*ZoneSettingResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/settings"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &ZoneSettingResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// UpdateZoneSettings updates the settings for a given zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-settings-edit-zone-settings-info
|
||||
func (api *API) UpdateZoneSettings(zoneID string, settings []ZoneSetting) (*ZoneSettingResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/settings"
|
||||
res, err := api.makeRequest("PATCH", uri, struct {
|
||||
Items []ZoneSetting `json:"items"`
|
||||
}{settings})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
|
||||
response := &ZoneSettingResponse{}
|
||||
err = json.Unmarshal(res, &response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ZoneSSLSettings returns information about SSL setting to the specified zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-settings-get-ssl-setting
|
||||
func (api *API) ZoneSSLSettings(zoneID string) (ZoneSSLSetting, error) {
|
||||
uri := "/zones/" + zoneID + "/settings/ssl"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return ZoneSSLSetting{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r ZoneSSLSettingResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return ZoneSSLSetting{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
3
vendor/golang.org/x/time/AUTHORS
generated
vendored
Normal file
3
vendor/golang.org/x/time/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/AUTHORS.
|
3
vendor/golang.org/x/time/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/golang.org/x/time/CONTRIBUTORS
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
27
vendor/golang.org/x/time/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/time/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2009 The Go Authors. 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.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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
|
||||
OWNER 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.
|
22
vendor/golang.org/x/time/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/time/PATENTS
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
384
vendor/golang.org/x/time/rate/rate.go
generated
vendored
Normal file
384
vendor/golang.org/x/time/rate/rate.go
generated
vendored
Normal file
|
@ -0,0 +1,384 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package rate provides a rate limiter.
|
||||
package rate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Limit defines the maximum frequency of some events.
|
||||
// Limit is represented as number of events per second.
|
||||
// A zero Limit allows no events.
|
||||
type Limit float64
|
||||
|
||||
// Inf is the infinite rate limit; it allows all events (even if burst is zero).
|
||||
const Inf = Limit(math.MaxFloat64)
|
||||
|
||||
// Every converts a minimum time interval between events to a Limit.
|
||||
func Every(interval time.Duration) Limit {
|
||||
if interval <= 0 {
|
||||
return Inf
|
||||
}
|
||||
return 1 / Limit(interval.Seconds())
|
||||
}
|
||||
|
||||
// A Limiter controls how frequently events are allowed to happen.
|
||||
// It implements a "token bucket" of size b, initially full and refilled
|
||||
// at rate r tokens per second.
|
||||
// Informally, in any large enough time interval, the Limiter limits the
|
||||
// rate to r tokens per second, with a maximum burst size of b events.
|
||||
// As a special case, if r == Inf (the infinite rate), b is ignored.
|
||||
// See https://en.wikipedia.org/wiki/Token_bucket for more about token buckets.
|
||||
//
|
||||
// The zero value is a valid Limiter, but it will reject all events.
|
||||
// Use NewLimiter to create non-zero Limiters.
|
||||
//
|
||||
// Limiter has three main methods, Allow, Reserve, and Wait.
|
||||
// Most callers should use Wait.
|
||||
//
|
||||
// Each of the three methods consumes a single token.
|
||||
// They differ in their behavior when no token is available.
|
||||
// If no token is available, Allow returns false.
|
||||
// If no token is available, Reserve returns a reservation for a future token
|
||||
// and the amount of time the caller must wait before using it.
|
||||
// If no token is available, Wait blocks until one can be obtained
|
||||
// or its associated context.Context is canceled.
|
||||
//
|
||||
// The methods AllowN, ReserveN, and WaitN consume n tokens.
|
||||
type Limiter struct {
|
||||
limit Limit
|
||||
burst int
|
||||
|
||||
mu sync.Mutex
|
||||
tokens float64
|
||||
// last is the last time the limiter's tokens field was updated
|
||||
last time.Time
|
||||
// lastEvent is the latest time of a rate-limited event (past or future)
|
||||
lastEvent time.Time
|
||||
}
|
||||
|
||||
// Limit returns the maximum overall event rate.
|
||||
func (lim *Limiter) Limit() Limit {
|
||||
lim.mu.Lock()
|
||||
defer lim.mu.Unlock()
|
||||
return lim.limit
|
||||
}
|
||||
|
||||
// Burst returns the maximum burst size. Burst is the maximum number of tokens
|
||||
// that can be consumed in a single call to Allow, Reserve, or Wait, so higher
|
||||
// Burst values allow more events to happen at once.
|
||||
// A zero Burst allows no events, unless limit == Inf.
|
||||
func (lim *Limiter) Burst() int {
|
||||
return lim.burst
|
||||
}
|
||||
|
||||
// NewLimiter returns a new Limiter that allows events up to rate r and permits
|
||||
// bursts of at most b tokens.
|
||||
func NewLimiter(r Limit, b int) *Limiter {
|
||||
return &Limiter{
|
||||
limit: r,
|
||||
burst: b,
|
||||
}
|
||||
}
|
||||
|
||||
// Allow is shorthand for AllowN(time.Now(), 1).
|
||||
func (lim *Limiter) Allow() bool {
|
||||
return lim.AllowN(time.Now(), 1)
|
||||
}
|
||||
|
||||
// AllowN reports whether n events may happen at time now.
|
||||
// Use this method if you intend to drop / skip events that exceed the rate limit.
|
||||
// Otherwise use Reserve or Wait.
|
||||
func (lim *Limiter) AllowN(now time.Time, n int) bool {
|
||||
return lim.reserveN(now, n, 0).ok
|
||||
}
|
||||
|
||||
// A Reservation holds information about events that are permitted by a Limiter to happen after a delay.
|
||||
// A Reservation may be canceled, which may enable the Limiter to permit additional events.
|
||||
type Reservation struct {
|
||||
ok bool
|
||||
lim *Limiter
|
||||
tokens int
|
||||
timeToAct time.Time
|
||||
// This is the Limit at reservation time, it can change later.
|
||||
limit Limit
|
||||
}
|
||||
|
||||
// OK returns whether the limiter can provide the requested number of tokens
|
||||
// within the maximum wait time. If OK is false, Delay returns InfDuration, and
|
||||
// Cancel does nothing.
|
||||
func (r *Reservation) OK() bool {
|
||||
return r.ok
|
||||
}
|
||||
|
||||
// Delay is shorthand for DelayFrom(time.Now()).
|
||||
func (r *Reservation) Delay() time.Duration {
|
||||
return r.DelayFrom(time.Now())
|
||||
}
|
||||
|
||||
// InfDuration is the duration returned by Delay when a Reservation is not OK.
|
||||
const InfDuration = time.Duration(1<<63 - 1)
|
||||
|
||||
// DelayFrom returns the duration for which the reservation holder must wait
|
||||
// before taking the reserved action. Zero duration means act immediately.
|
||||
// InfDuration means the limiter cannot grant the tokens requested in this
|
||||
// Reservation within the maximum wait time.
|
||||
func (r *Reservation) DelayFrom(now time.Time) time.Duration {
|
||||
if !r.ok {
|
||||
return InfDuration
|
||||
}
|
||||
delay := r.timeToAct.Sub(now)
|
||||
if delay < 0 {
|
||||
return 0
|
||||
}
|
||||
return delay
|
||||
}
|
||||
|
||||
// Cancel is shorthand for CancelAt(time.Now()).
|
||||
func (r *Reservation) Cancel() {
|
||||
r.CancelAt(time.Now())
|
||||
return
|
||||
}
|
||||
|
||||
// CancelAt indicates that the reservation holder will not perform the reserved action
|
||||
// and reverses the effects of this Reservation on the rate limit as much as possible,
|
||||
// considering that other reservations may have already been made.
|
||||
func (r *Reservation) CancelAt(now time.Time) {
|
||||
if !r.ok {
|
||||
return
|
||||
}
|
||||
|
||||
r.lim.mu.Lock()
|
||||
defer r.lim.mu.Unlock()
|
||||
|
||||
if r.lim.limit == Inf || r.tokens == 0 || r.timeToAct.Before(now) {
|
||||
return
|
||||
}
|
||||
|
||||
// calculate tokens to restore
|
||||
// The duration between lim.lastEvent and r.timeToAct tells us how many tokens were reserved
|
||||
// after r was obtained. These tokens should not be restored.
|
||||
restoreTokens := float64(r.tokens) - r.limit.tokensFromDuration(r.lim.lastEvent.Sub(r.timeToAct))
|
||||
if restoreTokens <= 0 {
|
||||
return
|
||||
}
|
||||
// advance time to now
|
||||
now, _, tokens := r.lim.advance(now)
|
||||
// calculate new number of tokens
|
||||
tokens += restoreTokens
|
||||
if burst := float64(r.lim.burst); tokens > burst {
|
||||
tokens = burst
|
||||
}
|
||||
// update state
|
||||
r.lim.last = now
|
||||
r.lim.tokens = tokens
|
||||
if r.timeToAct == r.lim.lastEvent {
|
||||
prevEvent := r.timeToAct.Add(r.limit.durationFromTokens(float64(-r.tokens)))
|
||||
if !prevEvent.Before(now) {
|
||||
r.lim.lastEvent = prevEvent
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Reserve is shorthand for ReserveN(time.Now(), 1).
|
||||
func (lim *Limiter) Reserve() *Reservation {
|
||||
return lim.ReserveN(time.Now(), 1)
|
||||
}
|
||||
|
||||
// ReserveN returns a Reservation that indicates how long the caller must wait before n events happen.
|
||||
// The Limiter takes this Reservation into account when allowing future events.
|
||||
// ReserveN returns false if n exceeds the Limiter's burst size.
|
||||
// Usage example:
|
||||
// r := lim.ReserveN(time.Now(), 1)
|
||||
// if !r.OK() {
|
||||
// // Not allowed to act! Did you remember to set lim.burst to be > 0 ?
|
||||
// return
|
||||
// }
|
||||
// time.Sleep(r.Delay())
|
||||
// Act()
|
||||
// Use this method if you wish to wait and slow down in accordance with the rate limit without dropping events.
|
||||
// If you need to respect a deadline or cancel the delay, use Wait instead.
|
||||
// To drop or skip events exceeding rate limit, use Allow instead.
|
||||
func (lim *Limiter) ReserveN(now time.Time, n int) *Reservation {
|
||||
r := lim.reserveN(now, n, InfDuration)
|
||||
return &r
|
||||
}
|
||||
|
||||
// contextContext is a temporary(?) copy of the context.Context type
|
||||
// to support both Go 1.6 using golang.org/x/net/context and Go 1.7+
|
||||
// with the built-in context package. If people ever stop using Go 1.6
|
||||
// we can remove this.
|
||||
type contextContext interface {
|
||||
Deadline() (deadline time.Time, ok bool)
|
||||
Done() <-chan struct{}
|
||||
Err() error
|
||||
Value(key interface{}) interface{}
|
||||
}
|
||||
|
||||
// Wait is shorthand for WaitN(ctx, 1).
|
||||
func (lim *Limiter) wait(ctx contextContext) (err error) {
|
||||
return lim.WaitN(ctx, 1)
|
||||
}
|
||||
|
||||
// WaitN blocks until lim permits n events to happen.
|
||||
// It returns an error if n exceeds the Limiter's burst size, the Context is
|
||||
// canceled, or the expected wait time exceeds the Context's Deadline.
|
||||
// The burst limit is ignored if the rate limit is Inf.
|
||||
func (lim *Limiter) waitN(ctx contextContext, n int) (err error) {
|
||||
if n > lim.burst && lim.limit != Inf {
|
||||
return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, lim.burst)
|
||||
}
|
||||
// Check if ctx is already cancelled
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
// Determine wait limit
|
||||
now := time.Now()
|
||||
waitLimit := InfDuration
|
||||
if deadline, ok := ctx.Deadline(); ok {
|
||||
waitLimit = deadline.Sub(now)
|
||||
}
|
||||
// Reserve
|
||||
r := lim.reserveN(now, n, waitLimit)
|
||||
if !r.ok {
|
||||
return fmt.Errorf("rate: Wait(n=%d) would exceed context deadline", n)
|
||||
}
|
||||
// Wait if necessary
|
||||
delay := r.DelayFrom(now)
|
||||
if delay == 0 {
|
||||
return nil
|
||||
}
|
||||
t := time.NewTimer(delay)
|
||||
defer t.Stop()
|
||||
select {
|
||||
case <-t.C:
|
||||
// We can proceed.
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
// Context was canceled before we could proceed. Cancel the
|
||||
// reservation, which may permit other events to proceed sooner.
|
||||
r.Cancel()
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
// SetLimit is shorthand for SetLimitAt(time.Now(), newLimit).
|
||||
func (lim *Limiter) SetLimit(newLimit Limit) {
|
||||
lim.SetLimitAt(time.Now(), newLimit)
|
||||
}
|
||||
|
||||
// SetLimitAt sets a new Limit for the limiter. The new Limit, and Burst, may be violated
|
||||
// or underutilized by those which reserved (using Reserve or Wait) but did not yet act
|
||||
// before SetLimitAt was called.
|
||||
func (lim *Limiter) SetLimitAt(now time.Time, newLimit Limit) {
|
||||
lim.mu.Lock()
|
||||
defer lim.mu.Unlock()
|
||||
|
||||
now, _, tokens := lim.advance(now)
|
||||
|
||||
lim.last = now
|
||||
lim.tokens = tokens
|
||||
lim.limit = newLimit
|
||||
}
|
||||
|
||||
// reserveN is a helper method for AllowN, ReserveN, and WaitN.
|
||||
// maxFutureReserve specifies the maximum reservation wait duration allowed.
|
||||
// reserveN returns Reservation, not *Reservation, to avoid allocation in AllowN and WaitN.
|
||||
func (lim *Limiter) reserveN(now time.Time, n int, maxFutureReserve time.Duration) Reservation {
|
||||
lim.mu.Lock()
|
||||
|
||||
if lim.limit == Inf {
|
||||
lim.mu.Unlock()
|
||||
return Reservation{
|
||||
ok: true,
|
||||
lim: lim,
|
||||
tokens: n,
|
||||
timeToAct: now,
|
||||
}
|
||||
}
|
||||
|
||||
now, last, tokens := lim.advance(now)
|
||||
|
||||
// Calculate the remaining number of tokens resulting from the request.
|
||||
tokens -= float64(n)
|
||||
|
||||
// Calculate the wait duration
|
||||
var waitDuration time.Duration
|
||||
if tokens < 0 {
|
||||
waitDuration = lim.limit.durationFromTokens(-tokens)
|
||||
}
|
||||
|
||||
// Decide result
|
||||
ok := n <= lim.burst && waitDuration <= maxFutureReserve
|
||||
|
||||
// Prepare reservation
|
||||
r := Reservation{
|
||||
ok: ok,
|
||||
lim: lim,
|
||||
limit: lim.limit,
|
||||
}
|
||||
if ok {
|
||||
r.tokens = n
|
||||
r.timeToAct = now.Add(waitDuration)
|
||||
}
|
||||
|
||||
// Update state
|
||||
if ok {
|
||||
lim.last = now
|
||||
lim.tokens = tokens
|
||||
lim.lastEvent = r.timeToAct
|
||||
} else {
|
||||
lim.last = last
|
||||
}
|
||||
|
||||
lim.mu.Unlock()
|
||||
return r
|
||||
}
|
||||
|
||||
// advance calculates and returns an updated state for lim resulting from the passage of time.
|
||||
// lim is not changed.
|
||||
func (lim *Limiter) advance(now time.Time) (newNow time.Time, newLast time.Time, newTokens float64) {
|
||||
last := lim.last
|
||||
if now.Before(last) {
|
||||
last = now
|
||||
}
|
||||
|
||||
// Avoid making delta overflow below when last is very old.
|
||||
maxElapsed := lim.limit.durationFromTokens(float64(lim.burst) - lim.tokens)
|
||||
elapsed := now.Sub(last)
|
||||
if elapsed > maxElapsed {
|
||||
elapsed = maxElapsed
|
||||
}
|
||||
|
||||
// Calculate the new number of tokens, due to time that passed.
|
||||
delta := lim.limit.tokensFromDuration(elapsed)
|
||||
tokens := lim.tokens + delta
|
||||
if burst := float64(lim.burst); tokens > burst {
|
||||
tokens = burst
|
||||
}
|
||||
|
||||
return now, last, tokens
|
||||
}
|
||||
|
||||
// durationFromTokens is a unit conversion function from the number of tokens to the duration
|
||||
// of time it takes to accumulate them at a rate of limit tokens per second.
|
||||
func (limit Limit) durationFromTokens(tokens float64) time.Duration {
|
||||
seconds := tokens / float64(limit)
|
||||
return time.Nanosecond * time.Duration(1e9*seconds)
|
||||
}
|
||||
|
||||
// tokensFromDuration is a unit conversion function from a time duration to the number of tokens
|
||||
// which could be accumulated during that duration at a rate of limit tokens per second.
|
||||
func (limit Limit) tokensFromDuration(d time.Duration) float64 {
|
||||
return d.Seconds() * float64(limit)
|
||||
}
|
21
vendor/golang.org/x/time/rate/rate_go16.go
generated
vendored
Normal file
21
vendor/golang.org/x/time/rate/rate_go16.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.7
|
||||
|
||||
package rate
|
||||
|
||||
import "golang.org/x/net/context"
|
||||
|
||||
// Wait is shorthand for WaitN(ctx, 1).
|
||||
func (lim *Limiter) Wait(ctx context.Context) (err error) {
|
||||
return lim.waitN(ctx, 1)
|
||||
}
|
||||
|
||||
// WaitN blocks until lim permits n events to happen.
|
||||
// It returns an error if n exceeds the Limiter's burst size, the Context is
|
||||
// canceled, or the expected wait time exceeds the Context's Deadline.
|
||||
func (lim *Limiter) WaitN(ctx context.Context, n int) (err error) {
|
||||
return lim.waitN(ctx, n)
|
||||
}
|
21
vendor/golang.org/x/time/rate/rate_go17.go
generated
vendored
Normal file
21
vendor/golang.org/x/time/rate/rate_go17.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.7
|
||||
|
||||
package rate
|
||||
|
||||
import "context"
|
||||
|
||||
// Wait is shorthand for WaitN(ctx, 1).
|
||||
func (lim *Limiter) Wait(ctx context.Context) (err error) {
|
||||
return lim.waitN(ctx, 1)
|
||||
}
|
||||
|
||||
// WaitN blocks until lim permits n events to happen.
|
||||
// It returns an error if n exceeds the Limiter's burst size, the Context is
|
||||
// canceled, or the expected wait time exceeds the Context's Deadline.
|
||||
func (lim *Limiter) WaitN(ctx context.Context, n int) (err error) {
|
||||
return lim.waitN(ctx, n)
|
||||
}
|
Loading…
Reference in a new issue