provider/cloudflare: Swap out mitchellh fork for upstream cloudflare-go
TODO noted that this should be done when a PR was merged, and it has so
This commit is contained in:
parent
8c3ff93395
commit
d70d7aba57
|
@ -3,8 +3,7 @@ package cloudflare
|
|||
import (
|
||||
"log"
|
||||
|
||||
// NOTE: Temporary until they merge my PR:
|
||||
"github.com/mitchellh/cloudflare-go"
|
||||
"github.com/cloudflare/cloudflare-go"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
|
|
@ -4,10 +4,8 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/cloudflare/cloudflare-go"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
|
||||
// NOTE: Temporary until they merge my PR:
|
||||
"github.com/mitchellh/cloudflare-go"
|
||||
)
|
||||
|
||||
func resourceCloudFlareRecord() *schema.Resource {
|
||||
|
|
|
@ -5,11 +5,9 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/cloudflare/cloudflare-go"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
||||
// NOTE: Temporary until they merge my PR:
|
||||
"github.com/mitchellh/cloudflare-go"
|
||||
)
|
||||
|
||||
func TestAccCloudFlareRecord_Basic(t *testing.T) {
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
# cloudflare-go
|
||||
|
||||
[![GoDoc](https://img.shields.io/badge/godoc-reference-5673AF.svg?style=flat-square)](https://godoc.org/github.com/cloudflare/cloudflare-go)
|
||||
[![Build Status](https://img.shields.io/travis/cloudflare/cloudflare-go/master.svg?style=flat-square)](https://travis-ci.org/cloudflare/cloudflare-go)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/cloudflare/cloudflare-go?style=flat-square)](https://goreportcard.com/report/github.com/cloudflare/cloudflare-go)
|
||||
|
||||
> **Note**: This library is under active development as we expand it to cover our (expanding!) API.
|
||||
Consider the public API of this package a little unstable as we work towards a v1.0.
|
||||
|
||||
A Go library for interacting with [CloudFlare's API v4](https://api.cloudflare.com/). This library
|
||||
allows you to:
|
||||
|
||||
* Manage and automate changes to your DNS records within CloudFlare
|
||||
* Manage and automate changes to your zones (domains) on CloudFlare, including adding new zones to
|
||||
your account
|
||||
* List and modify the status of WAF (Web Application Firewall) rules for your zones
|
||||
* Fetch CloudFlare's IP ranges for automating your firewall whitelisting
|
||||
|
||||
A command-line client, [flarectl](cmd/flarectl), is also available as part of this project.
|
||||
|
||||
## Features
|
||||
|
||||
The current feature list includes:
|
||||
|
||||
- [x] DNS Records
|
||||
- [x] Zones
|
||||
- [x] Web Application Firewall (WAF)
|
||||
- [x] CloudFlare IPs
|
||||
- [x] User Administration (partial)
|
||||
- [x] Virtual DNS Management
|
||||
- [ ] Organization Administration
|
||||
- [ ] [Railgun](https://www.cloudflare.com/railgun/) administration
|
||||
- [ ] [Keyless SSL](https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/)
|
||||
- [ ] [Origin CA](https://blog.cloudflare.com/universal-ssl-encryption-all-the-way-to-the-origin-for-free/)
|
||||
|
||||
Pull Requests are welcome, but please open an issue (or comment in an existing issue) to discuss any
|
||||
non-trivial changes before submitting code.
|
||||
|
||||
## Installation
|
||||
|
||||
You need a working Go environment.
|
||||
|
||||
```
|
||||
go get github.com/cloudflare/cloudflare-go
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/cloudflare/cloudflare-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Construct a new API object
|
||||
api, err := cloudflare.New(os.Getenv("CF_API_KEY"), os.Getenv("CF_API_EMAIL"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Fetch user details on the account
|
||||
u, err := api.UserDetails()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Print user details
|
||||
fmt.Println(u)
|
||||
|
||||
// Fetch the zone ID
|
||||
id, err := api.ZoneIDByName("example.com") // Assuming example.com exists in your CloudFlare account already
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Fetch zone details
|
||||
zone, err := api.ZoneDetails(id)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Print zone details
|
||||
fmt.Println(zone)
|
||||
}
|
||||
```
|
||||
|
||||
Also refer to the [API documentation](https://godoc.org/github.com/cloudflare/cloudflare-go) for how
|
||||
to use this package in-depth.
|
||||
|
||||
# License
|
||||
|
||||
BSD licensed. See the [LICENSE](LICENSE) file for details.
|
|
@ -0,0 +1,317 @@
|
|||
// Package cloudflare implements the CloudFlare v4 API.
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const apiURL = "https://api.cloudflare.com/client/v4"
|
||||
|
||||
// API holds the configuration for the current API client. A client should not
|
||||
// be modified concurrently.
|
||||
type API struct {
|
||||
APIKey string
|
||||
APIEmail string
|
||||
BaseURL string
|
||||
headers http.Header
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
api := &API{
|
||||
APIKey: key,
|
||||
APIEmail: email,
|
||||
BaseURL: apiURL,
|
||||
headers: make(http.Header),
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Replace nil with a JSON object if needed
|
||||
var reqBody io.Reader
|
||||
if params != nil {
|
||||
json, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error marshalling params to JSON")
|
||||
}
|
||||
reqBody = bytes.NewReader(json)
|
||||
} else {
|
||||
reqBody = nil
|
||||
}
|
||||
|
||||
resp, err := api.request(method, uri, reqBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read response body")
|
||||
}
|
||||
|
||||
switch resp.StatusCode {
|
||||
case http.StatusOK:
|
||||
break
|
||||
case http.StatusUnauthorized:
|
||||
return nil, errors.Errorf("HTTP status %d: invalid credentials", resp.StatusCode)
|
||||
case http.StatusForbidden:
|
||||
return nil, errors.Errorf("HTTP status %d: insufficient permissions", resp.StatusCode)
|
||||
default:
|
||||
var s string
|
||||
if body != nil {
|
||||
s = string(body)
|
||||
}
|
||||
return nil, errors.Errorf("HTTP status %d: content %q", resp.StatusCode, s)
|
||||
}
|
||||
|
||||
return body, 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) (*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 = api.headers
|
||||
req.Header.Set("X-Auth-Key", api.APIKey)
|
||||
req.Header.Set("X-Auth-Email", api.APIEmail)
|
||||
|
||||
resp, err := api.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "HTTP request failed")
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// 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"`
|
||||
Count int `json:"count"`
|
||||
Total int `json:"total_count"`
|
||||
}
|
||||
|
||||
// User describes a user account.
|
||||
type User struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Username string `json:"username"`
|
||||
Telephone string `json:"telephone"`
|
||||
Country string `json:"country"`
|
||||
Zipcode string `json:"zipcode"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
ModifiedOn time.Time `json:"modified_on"`
|
||||
APIKey string `json:"api_key"`
|
||||
TwoFA bool `json:"two_factor_authentication_enabled"`
|
||||
Betas []string `json:"betas"`
|
||||
Organizations []Organization `json:"organizations"`
|
||||
}
|
||||
|
||||
// UserResponse wraps a response containing User accounts.
|
||||
type UserResponse struct {
|
||||
Response
|
||||
Result User `json:"result"`
|
||||
}
|
||||
|
||||
// Owner describes the resource owner.
|
||||
type Owner struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
OwnerType string `json:"owner_type"`
|
||||
}
|
||||
|
||||
// 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 {
|
||||
Response
|
||||
Result DNSRecord `json:"result"`
|
||||
}
|
||||
|
||||
// DNSListResponse represents the response from the list DNS records endpoint.
|
||||
type DNSListResponse struct {
|
||||
Response
|
||||
Result []DNSRecord `json:"result"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// PurgeCacheRequest represents the request format made to the purge endpoint.
|
||||
type PurgeCacheRequest struct {
|
||||
Everything bool `json:"purge_everything,omitempty"`
|
||||
Files []string `json:"files,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// PurgeCacheResponse represents the response from the purge endpoint.
|
||||
type PurgeCacheResponse struct {
|
||||
Response
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
|
@ -7,34 +7,30 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
Create a DNS record.
|
||||
|
||||
API reference:
|
||||
https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record
|
||||
POST /zones/:zone_identifier/dns_records
|
||||
*/
|
||||
func (api *API) CreateDNSRecord(zoneID string, rr DNSRecord) (DNSRecord, error) {
|
||||
// CreateDNSRecord creates a DNS record for the zone identifier.
|
||||
// API reference:
|
||||
// https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record
|
||||
// POST /zones/:zone_identifier/dns_records
|
||||
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 DNSRecord{}, errors.Wrap(err, errMakeRequestError)
|
||||
return nil, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r DNSRecordResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
|
||||
var recordResp *DNSRecordResponse
|
||||
err = json.Unmarshal(res, &recordResp)
|
||||
if err != nil {
|
||||
return DNSRecord{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
return nil, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
|
||||
/*
|
||||
Fetches DNS records for a zone.
|
||||
return recordResp, nil
|
||||
}
|
||||
|
||||
API reference:
|
||||
https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records
|
||||
GET /zones/:zone_identifier/dns_records
|
||||
*/
|
||||
// DNSRecords returns a slice of DNS records for the given zone identifier.
|
||||
// API reference:
|
||||
// https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records
|
||||
// GET /zones/:zone_identifier/dns_records
|
||||
func (api *API) DNSRecords(zoneID string, rr DNSRecord) ([]DNSRecord, error) {
|
||||
// Construct a query string
|
||||
v := url.Values{}
|
||||
|
@ -64,13 +60,11 @@ func (api *API) DNSRecords(zoneID string, rr DNSRecord) ([]DNSRecord, error) {
|
|||
return r.Result, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Fetches a single DNS record.
|
||||
|
||||
API reference:
|
||||
https://api.cloudflare.com/#dns-records-for-a-zone-dns-record-details
|
||||
GET /zones/:zone_identifier/dns_records/:identifier
|
||||
*/
|
||||
// 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
|
||||
// GET /zones/:zone_identifier/dns_records/:identifier
|
||||
func (api *API) DNSRecord(zoneID, recordID string) (DNSRecord, error) {
|
||||
uri := "/zones/" + zoneID + "/dns_records/" + recordID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
|
@ -85,13 +79,11 @@ func (api *API) DNSRecord(zoneID, recordID string) (DNSRecord, error) {
|
|||
return r.Result, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Change a DNS record.
|
||||
|
||||
API reference:
|
||||
https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record
|
||||
PUT /zones/:zone_identifier/dns_records/:identifier
|
||||
*/
|
||||
// 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
|
||||
// PUT /zones/:zone_identifier/dns_records/:identifier
|
||||
func (api *API) UpdateDNSRecord(zoneID, recordID string, rr DNSRecord) error {
|
||||
rec, err := api.DNSRecord(zoneID, recordID)
|
||||
if err != nil {
|
||||
|
@ -112,13 +104,11 @@ func (api *API) UpdateDNSRecord(zoneID, recordID string, rr DNSRecord) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
Delete a DNS record.
|
||||
|
||||
API reference:
|
||||
https://api.cloudflare.com/#dns-records-for-a-zone-delete-dns-record
|
||||
DELETE /zones/:zone_identifier/dns_records/:identifier
|
||||
*/
|
||||
// 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
|
||||
// DELETE /zones/:zone_identifier/dns_records/:identifier
|
||||
func (api *API) DeleteDNSRecord(zoneID, recordID string) error {
|
||||
uri := "/zones/" + zoneID + "/dns_records/" + recordID
|
||||
res, err := api.makeRequest("DELETE", uri, nil)
|
|
@ -0,0 +1,47 @@
|
|||
package cloudflare
|
||||
|
||||
// Error messages
|
||||
const (
|
||||
errEmptyCredentials = "invalid credentials: key & email must not be empty"
|
||||
errMakeRequestError = "error from makeRequest"
|
||||
errUnmarshalError = "error unmarshalling the JSON response"
|
||||
)
|
||||
|
||||
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()
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package cloudflare
|
||||
|
||||
// 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
|
||||
// POST /zones/:zone_identifier/keyless_certificates
|
||||
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
|
||||
// GET /zones/:zone_identifier/keyless_certificates
|
||||
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
|
||||
// GET /zones/:zone_identifier/keyless_certificates/:identifier
|
||||
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
|
||||
// PATCH /zones/:zone_identifier/keyless_certificates/:identifier
|
||||
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
|
||||
// DELETE /zones/:zone_identifier/keyless_certificates/:identifier
|
||||
func (api *API) DeleteKeyless() {
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package cloudflare
|
||||
|
||||
import "net/http"
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package cloudflare
|
||||
|
||||
// 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 ResultInfo `json:"result_info"`
|
||||
}
|
|
@ -2,6 +2,7 @@ package cloudflare
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
@ -32,13 +33,13 @@ Valid IDs are:
|
|||
cache_level
|
||||
disable_apps
|
||||
disable_performance
|
||||
disable_railgun
|
||||
disable_security
|
||||
edge_cache_ttl
|
||||
email_obfuscation
|
||||
forwarding_url
|
||||
ip_geolocation
|
||||
mirage
|
||||
railgun
|
||||
rocket_loader
|
||||
security_level
|
||||
server_side_exclude
|
||||
|
@ -60,13 +61,13 @@ var PageRuleActions = map[string]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
|
||||
"railgun": "Railgun", // 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
|
||||
|
@ -82,8 +83,8 @@ type PageRule struct {
|
|||
Actions []PageRuleAction `json:"actions"`
|
||||
Priority int `json:"priority"`
|
||||
Status string `json:"status"` // can be: active, paused
|
||||
ModifiedOn string `json:"modified_on,omitempty"`
|
||||
CreatedOn string `json:"created_on,omitempty"`
|
||||
ModifiedOn time.Time `json:"modified_on,omitempty"`
|
||||
CreatedOn time.Time `json:"created_on,omitempty"`
|
||||
}
|
||||
|
||||
// PageRuleDetailResponse is the API response, containing a single PageRule.
|
|
@ -0,0 +1,311 @@
|
|||
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
|
||||
// POST /railguns
|
||||
func (api *API) CreateRailgun(name string) (Railgun, error) {
|
||||
uri := "/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
|
||||
// GET /railguns
|
||||
func (api *API) ListRailguns(options RailgunListOptions) ([]Railgun, error) {
|
||||
v := url.Values{}
|
||||
if options.Direction != "" {
|
||||
v.Set("direction", options.Direction)
|
||||
}
|
||||
uri := "/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
|
||||
// GET /railguns/:identifier
|
||||
func (api *API) RailgunDetails(railgunID string) (Railgun, error) {
|
||||
uri := "/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
|
||||
// GET /railguns/:identifier/zones
|
||||
func (api *API) RailgunZones(railgunID string) ([]Zone, error) {
|
||||
uri := "/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
|
||||
// PATCH /railguns/:identifier
|
||||
func (api *API) enableRailgun(railgunID string, enable bool) (Railgun, error) {
|
||||
uri := "/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
|
||||
// PATCH /railguns/:identifier
|
||||
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
|
||||
// PATCH /railguns/:identifier
|
||||
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
|
||||
// DELETE /railguns/:identifier
|
||||
func (api *API) DeleteRailgun(railgunID string) error {
|
||||
uri := "/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
|
||||
// GET /zones/:zone_identifier/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
|
||||
}
|
||||
|
||||
// Railgun returns the configuration for a given Railgun.
|
||||
// API reference:
|
||||
// https://api.cloudflare.com/#railguns-for-a-zone-get-railgun-details
|
||||
// GET /zones/:zone_identifier/railguns/:identifier
|
||||
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
|
||||
}
|
||||
|
||||
// TestRailgunResponse tests a Railgun connection for a given zone.
|
||||
// API reference:
|
||||
// https://api.cloudflare.com/#railgun-connections-for-a-zone-test-railgun-connection
|
||||
// GET /zones/:zone_identifier/railguns/:identifier/diagnose
|
||||
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
|
||||
// PATCH /zones/:zone_identifier/railguns/:identifier
|
||||
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
|
||||
}
|
||||
|
||||
// ZoneRailgun connects a Railgun for a given zone.
|
||||
// API reference:
|
||||
// https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
|
||||
// PATCH /zones/:zone_identifier/railguns/:identifier
|
||||
func (api *API) ConnectZoneRailgun(zoneID, railgunID string) (ZoneRailgun, error) {
|
||||
return api.connectZoneRailgun(zoneID, railgunID, true)
|
||||
}
|
||||
|
||||
// ZoneRailgun disconnects a Railgun for a given zone.
|
||||
// API reference:
|
||||
// https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
|
||||
// PATCH /zones/:zone_identifier/railguns/:identifier
|
||||
func (api *API) DisconnectZoneRailgun(zoneID, railgunID string) (ZoneRailgun, error) {
|
||||
return api.connectZoneRailgun(zoneID, railgunID, false)
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
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
|
||||
// POST /zones/:zone_identifier/custom_certificates
|
||||
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
|
||||
// GET /zones/:zone_identifier/custom_certificates
|
||||
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
|
||||
// GET /zones/:zone_identifier/custom_certificates/:identifier
|
||||
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
|
||||
// PATCH /zones/:zone_identifier/custom_certificates/:identifier
|
||||
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
|
||||
// PUT /zones/:zone_identifier/custom_certificates/prioritize
|
||||
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
|
||||
// DELETE /zones/:zone_identifier/custom_certificates/:identifier
|
||||
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
|
||||
}
|
|
@ -6,30 +6,30 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
Information about the logged-in user.
|
||||
|
||||
API reference: https://api.cloudflare.com/#user-user-details
|
||||
*/
|
||||
func (api API) UserDetails() (User, error) {
|
||||
// UserDetails provides information about the logged-in user.
|
||||
// API reference:
|
||||
// https://api.cloudflare.com/#user-user-details
|
||||
// GET /user
|
||||
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
|
||||
}
|
||||
|
||||
/*
|
||||
Update user properties.
|
||||
|
||||
API reference: https://api.cloudflare.com/#user-update-user
|
||||
*/
|
||||
func (api API) UpdateUser() (User, error) {
|
||||
// UpdateUser updates the properties of the given user.
|
||||
// API reference:
|
||||
// https://api.cloudflare.com/#user-update-user
|
||||
// PATCH /user
|
||||
func (api *API) UpdateUser() (User, error) {
|
||||
// api.makeRequest("PATCH", "/user", user)
|
||||
return User{}, nil
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
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
|
||||
// POST /user/virtual_dns
|
||||
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
|
||||
// GET /user/virtual_dns/:identifier
|
||||
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
|
||||
// GET /user/virtual_dns
|
||||
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
|
||||
// PATCH /user/virtual_dns/:identifier
|
||||
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
|
||||
// DELETE /user/virtual_dns/:identifier
|
||||
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
|
||||
}
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// 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
|
||||
|
@ -24,12 +25,13 @@ func (api *API) ListWAFPackages(zoneID string) ([]WAFPackage, error) {
|
|||
// TODO: Provide an actual error message instead of always returning nil
|
||||
return []WAFPackage{}, err
|
||||
}
|
||||
for pi, _ := range p.Result {
|
||||
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
|
||||
|
@ -48,7 +50,7 @@ func (api *API) ListWAFRules(zoneID, packageID string) ([]WAFRule, error) {
|
|||
// TODO: Provide an actual error message instead of always returning nil
|
||||
return []WAFRule{}, err
|
||||
}
|
||||
for ri, _ := range r.Result {
|
||||
for ri := range r.Result {
|
||||
rules = append(rules, r.Result[ri])
|
||||
}
|
||||
return rules, nil
|
|
@ -0,0 +1,502 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Zone describes a CloudFlare zone.
|
||||
type Zone struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
DevMode int `json:"development_mode"`
|
||||
OriginalNS []string `json:"original_name_servers"`
|
||||
OriginalRegistrar string `json:"original_registrar"`
|
||||
OriginalDNSHost string `json:"original_dnshost"`
|
||||
CreatedOn string `json:"created_on"`
|
||||
ModifiedOn string `json:"modified_on"`
|
||||
NameServers []string `json:"name_servers"`
|
||||
Owner Owner `json:"owner"`
|
||||
Permissions []string `json:"permissions"`
|
||||
Plan ZonePlan `json:"plan"`
|
||||
PlanPending ZonePlan `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 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"`
|
||||
}
|
||||
|
||||
// ZonePlan contains the plan information for a zone.
|
||||
type ZonePlan struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Price int `json:"price,omitempty"`
|
||||
Currency string `json:"currency,omitempty"`
|
||||
Frequency string `json:"frequency,omitempty"`
|
||||
LegacyID string `json:"legacy_id,omitempty"`
|
||||
IsSubscribed bool `json:"is_subscribed,omitempty"`
|
||||
CanSubscribe bool `json:"can_subscribe,omitempty"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// AvailableZonePlansResponse represents the response from the Available Plans endpoint.
|
||||
type AvailableZonePlansResponse struct {
|
||||
Response
|
||||
Result []ZonePlan `json:"result"`
|
||||
ResultInfo
|
||||
}
|
||||
|
||||
// ZonePlanResponse represents the response from the Plan Details endpoint.
|
||||
type ZonePlanResponse struct {
|
||||
Response
|
||||
Result ZonePlan `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"`
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
// 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 {
|
||||
// FIXME(jamesog): Using omitempty here means we can't disable Paused.
|
||||
// Currently unsure how to work around this.
|
||||
Paused bool `json:"paused,omitempty"`
|
||||
VanityNS []string `json:"vanity_name_servers,omitempty"`
|
||||
Plan *ZonePlan `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
|
||||
}
|
||||
|
||||
// ZoneSetPlan changes the zone plan.
|
||||
func (api *API) ZoneSetPlan(zoneID string, plan ZonePlan) (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})
|
||||
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
|
||||
}
|
||||
|
||||
// AvailableZonePlans returns information about all plans available to the specified zone.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-plan-available-plans
|
||||
func (api *API) AvailableZonePlans(zoneID string) ([]ZonePlan, error) {
|
||||
uri := "/zones/" + zoneID + "/available_plans"
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return []ZonePlan{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r AvailableZonePlansResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return []ZonePlan{}, errors.Wrap(err, errUnmarshalError)
|
||||
}
|
||||
return r.Result, nil
|
||||
}
|
||||
|
||||
// ZonePlanDetails returns information about a zone plan.
|
||||
//
|
||||
// API reference: https://api.cloudflare.com/#zone-plan-plan-details
|
||||
func (api *API) ZonePlanDetails(zoneID, planID string) (ZonePlan, error) {
|
||||
uri := "/zones/" + zoneID + "/available_plans/" + planID
|
||||
res, err := api.makeRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return ZonePlan{}, errors.Wrap(err, errMakeRequestError)
|
||||
}
|
||||
var r ZonePlanResponse
|
||||
err = json.Unmarshal(res, &r)
|
||||
if err != nil {
|
||||
return ZonePlan{}, 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
|
||||
// GET /zones/:zone_identifier/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
|
||||
// GET /zones/:zone_identifier/analytics/colos
|
||||
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
|
||||
}
|
||||
|
||||
// Zone Settings
|
||||
// https://api.cloudflare.com/#zone-settings-for-a-zone-get-all-zone-settings
|
||||
// e.g.
|
||||
// https://api.cloudflare.com/#zone-settings-for-a-zone-get-always-online-setting
|
||||
// https://api.cloudflare.com/#zone-settings-for-a-zone-change-always-online-setting
|
|
@ -1,23 +0,0 @@
|
|||
language: go
|
||||
sudo: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- go: 1.4
|
||||
- go: 1.5
|
||||
- go: 1.6
|
||||
- go: tip
|
||||
allow_failures:
|
||||
- go: tip
|
||||
|
||||
script:
|
||||
- go get -t -v $(go list ./... | grep -v '/vendor/')
|
||||
- diff -u <(echo -n) <(gofmt -d .)
|
||||
- go vet $(go list ./... | grep -v '/vendor/')
|
||||
- go test -v -race ./...
|
||||
|
||||
notifications:
|
||||
email:
|
||||
recipients:
|
||||
- jamesog@cloudflare.com
|
||||
- msilverlock@cloudflare.com
|
|
@ -1,44 +0,0 @@
|
|||
[![GoDoc](https://godoc.org/github.com/cloudflare/cloudflare-go?status.svg)](https://godoc.org/github.com/cloudflare/cloudflare-go)
|
||||
|
||||
# cloudflare
|
||||
|
||||
A Go library for interacting with [CloudFlare's API v4](https://api.cloudflare.com/).
|
||||
|
||||
# Installation
|
||||
|
||||
You need a working Go environment.
|
||||
|
||||
```
|
||||
go get github.com/cloudflare/cloudflare-go
|
||||
```
|
||||
|
||||
# Getting Started
|
||||
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudflare/cloudflare-go"
|
||||
)
|
||||
|
||||
var api *cloudflare.API
|
||||
|
||||
func main() {
|
||||
// Construct a new API object
|
||||
api = cloudflare.New(os.Getenv("CF_API_KEY"), os.Getenv("CF_API_EMAIL"))
|
||||
|
||||
// Fetch the list of zones on the account
|
||||
zones, err := api.ListZones()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
// Print the zone names
|
||||
for _, z := range zones {
|
||||
fmt.Println(z.Name)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
An example application, [flarectl](cmd/flarectl), is in this repository.
|
|
@ -1,451 +0,0 @@
|
|||
/*
|
||||
Package cloudflare implements the CloudFlare v4 API.
|
||||
|
||||
New API requests created like:
|
||||
|
||||
api := cloudflare.New(apikey, apiemail)
|
||||
|
||||
*/
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const apiURL = "https://api.cloudflare.com/client/v4"
|
||||
|
||||
// Error messages
|
||||
const errMakeRequestError = "Error from makeRequest"
|
||||
const errUnmarshalError = "Error unmarshalling JSON"
|
||||
|
||||
type API struct {
|
||||
APIKey string
|
||||
APIEmail string
|
||||
}
|
||||
|
||||
// Initializes the API configuration.
|
||||
func New(key, email string) *API {
|
||||
return &API{key, email}
|
||||
}
|
||||
|
||||
// Initializes a new zone.
|
||||
func NewZone() *Zone {
|
||||
return &Zone{}
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
// Params can be turned into a URL query string or a body
|
||||
// TODO: Give this func a better name
|
||||
func (api *API) makeRequest(method, uri string, params interface{}) ([]byte, error) {
|
||||
// Replace nil with a JSON object if needed
|
||||
var reqBody io.Reader
|
||||
if params != nil {
|
||||
json, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error marshalling params to JSON")
|
||||
}
|
||||
reqBody = bytes.NewReader(json)
|
||||
} else {
|
||||
reqBody = nil
|
||||
}
|
||||
req, err := http.NewRequest(method, apiURL+uri, reqBody)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "HTTP request creation failed")
|
||||
}
|
||||
req.Header.Add("X-Auth-Key", api.APIKey)
|
||||
req.Header.Add("X-Auth-Email", api.APIEmail)
|
||||
// Could be application/json or multipart/form-data
|
||||
// req.Header.Add("Content-Type", "application/json")
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "HTTP request failed")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
resBody, err := ioutil.ReadAll(resp.Body)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error returned from API")
|
||||
} else if resBody != nil {
|
||||
return nil, errors.New(string(resBody))
|
||||
} else {
|
||||
return nil, errors.New(resp.Status)
|
||||
}
|
||||
}
|
||||
return resBody, nil
|
||||
}
|
||||
|
||||
// The Response struct 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 []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
}
|
||||
|
||||
type ResultInfo struct {
|
||||
Page int `json:"page"`
|
||||
PerPage int `json:"per_page"`
|
||||
Count int `json:"count"`
|
||||
Total int `json:"total_count"`
|
||||
}
|
||||
|
||||
// An Organization describes a multi-user organization. (Enterprise only.)
|
||||
type Organization struct {
|
||||
ID string
|
||||
Name string
|
||||
Status string
|
||||
Permissions []string
|
||||
Roles []string
|
||||
}
|
||||
|
||||
// A User describes a user account.
|
||||
type User struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Username string `json:"username"`
|
||||
Telephone string `json:"telephone"`
|
||||
Country string `json:"country"`
|
||||
Zipcode string `json:"zipcode"`
|
||||
CreatedOn string `json:"created_on"` // Should this be a time.Date?
|
||||
ModifiedOn string `json:"modified_on"`
|
||||
APIKey string `json:"api_key"`
|
||||
TwoFA bool `json:"two_factor_authentication_enabled"`
|
||||
Betas []string `json:"betas"`
|
||||
Organizations []Organization `json:"organizations"`
|
||||
}
|
||||
|
||||
type UserResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result User `json:"result"`
|
||||
}
|
||||
|
||||
type Owner struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
OwnerType string `json:"owner_type"`
|
||||
}
|
||||
|
||||
// A Zone describes a CloudFlare zone.
|
||||
type Zone struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
DevMode int `json:"development_mode"`
|
||||
OriginalNS []string `json:"original_name_servers"`
|
||||
OriginalRegistrar string `json:"original_registrar"`
|
||||
OriginalDNSHost string `json:"original_dnshost"`
|
||||
CreatedOn string `json:"created_on"`
|
||||
ModifiedOn string `json:"modified_on"`
|
||||
NameServers []string `json:"name_servers"`
|
||||
Owner Owner `json:"owner"`
|
||||
Permissions []string `json:"permissions"`
|
||||
Plan ZonePlan `json:"plan"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// Contains 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"`
|
||||
}
|
||||
|
||||
// Contains the plan information for a zone.
|
||||
type ZonePlan struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Price int `json:"price"`
|
||||
Currency string `json:"currency"`
|
||||
Frequency string `json:"frequency"`
|
||||
LegacyID string `json:"legacy_id"`
|
||||
IsSubscribed bool `json:"is_subscribed"`
|
||||
CanSubscribe bool `json:"can_subscribe"`
|
||||
}
|
||||
|
||||
type ZoneResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result []Zone `json:"result"`
|
||||
}
|
||||
|
||||
type ZonePlanResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result []ZonePlan `json:"result"`
|
||||
}
|
||||
|
||||
// type zoneSetting struct {
|
||||
// ID string `json:"id"`
|
||||
// Editable bool `json:"editable"`
|
||||
// ModifiedOn string `json:"modified_on"`
|
||||
// }
|
||||
// type zoneSettingStringVal struct {
|
||||
// zoneSetting
|
||||
// Value string `json:"value"`
|
||||
// }
|
||||
// type zoneSettingIntVal struct {
|
||||
// zoneSetting
|
||||
// Value int64 `json:"value"`
|
||||
// }
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
type ZoneSettingResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result []ZoneSetting `json:"result"`
|
||||
}
|
||||
|
||||
// Describes a DNS record for 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 string `json:"created_on,omitempty"`
|
||||
ModifiedOn string `json:"modified_on,omitempty"`
|
||||
Data interface{} `json:"data,omitempty"` // data returned by: SRV, LOC
|
||||
Meta interface{} `json:"meta,omitempty"`
|
||||
Priority int `json:"priority,omitempty"`
|
||||
}
|
||||
|
||||
// The response for creating or updating a DNS record.
|
||||
type DNSRecordResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []interface{} `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result DNSRecord `json:"result"`
|
||||
}
|
||||
|
||||
// The response for listing DNS records.
|
||||
type DNSListResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []interface{} `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result []DNSRecord `json:"result"`
|
||||
}
|
||||
|
||||
// Railgun status for a zone.
|
||||
type ZoneRailgun struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"string"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Connected bool `json:"connected"`
|
||||
}
|
||||
|
||||
type ZoneRailgunResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result []ZoneRailgun `json:"result"`
|
||||
}
|
||||
|
||||
// Custom SSL certificates for a zone.
|
||||
type ZoneCustomSSL struct {
|
||||
ID string `json:"id"`
|
||||
Hosts []string `json:"hosts"`
|
||||
Issuer string `json:"issuer"`
|
||||
Priority int `json:"priority"`
|
||||
Status string `json:"success"`
|
||||
BundleMethod string `json:"bundle_method"`
|
||||
ZoneID string `json:"zone_id"`
|
||||
Permissions []string `json:"permissions"`
|
||||
UploadedOn string `json:"uploaded_on"`
|
||||
ModifiedOn string `json:"modified_on"`
|
||||
ExpiresOn string `json:"expires_on"`
|
||||
KeylessServer KeylessSSL `json:"keyless_server"`
|
||||
}
|
||||
|
||||
type ZoneCustomSSLResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result []ZoneCustomSSL `json:"result"`
|
||||
}
|
||||
|
||||
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 string `json:"created_on"`
|
||||
ModifiedOn string `json:"modifed_on"`
|
||||
}
|
||||
|
||||
type KeylessSSLResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result []KeylessSSL `json:"result"`
|
||||
}
|
||||
|
||||
type Railgun struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"success"`
|
||||
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 string `json:"activated_on"`
|
||||
CreatedOn string `json:"created_on"`
|
||||
ModifiedOn string `json:"modified_on"`
|
||||
// XXX: UpgradeInfo struct {
|
||||
// version string
|
||||
// url string
|
||||
// } `json:"upgrade_info"`
|
||||
}
|
||||
|
||||
type RailgunResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result []Railgun `json:"result"`
|
||||
}
|
||||
|
||||
// Custom error pages.
|
||||
type CustomPage struct {
|
||||
CreatedOn string `json:"created_on"`
|
||||
ModifiedOn string `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"`
|
||||
}
|
||||
|
||||
type CustomPageResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result []CustomPage `json:"result"`
|
||||
}
|
||||
|
||||
// WAF packages
|
||||
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"`
|
||||
}
|
||||
|
||||
type WAFPackagesResponse struct {
|
||||
Result []WAFPackage `json:"result"`
|
||||
Success bool `json:"success"`
|
||||
ResultInfo struct {
|
||||
Page uint `json:"page"`
|
||||
PerPage uint `json:"per_page"`
|
||||
Count uint `json:"count"`
|
||||
TotalCount uint `json:"total_count"`
|
||||
} `json:"result_info"`
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
type WAFRulesResponse struct {
|
||||
Result []WAFRule `json:"result"`
|
||||
Success bool `json:"success"`
|
||||
ResultInfo struct {
|
||||
Page uint `json:"page"`
|
||||
PerPage uint `json:"per_page"`
|
||||
Count uint `json:"count"`
|
||||
TotalCount uint `json:"total_count"`
|
||||
} `json:"result_info"`
|
||||
}
|
||||
|
||||
type PurgeCacheRequest struct {
|
||||
Everything bool `json:"purge_everything,omitempty"`
|
||||
Files []string `json:"files,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
type PurgeCacheResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
}
|
||||
|
||||
// IPs contains a list 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 {
|
||||
Success bool `json:"success"`
|
||||
Errors []string `json:"errors"`
|
||||
Messages []string `json:"messages"`
|
||||
Result IPRanges `json:"result"`
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package cloudflare
|
||||
|
||||
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-create-a-keyless-ssl-configuration
|
||||
// POST /zones/:zone_identifier/keyless_certificates
|
||||
func (c *API) CreateKeyless() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-list-keyless-ssls
|
||||
// GET /zones/:zone_identifier/keyless_certificates
|
||||
func (c *API) ListKeyless() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-keyless-ssl-details
|
||||
// GET /zones/:zone_identifier/keyless_certificates/:identifier
|
||||
func (c *API) Keyless() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-update-keyless-configuration
|
||||
// PATCH /zones/:zone_identifier/keyless_certificates/:identifier
|
||||
func (c *API) UpdateKeyless() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-delete-keyless-configuration
|
||||
// DELETE /zones/:zone_identifier/keyless_certificates/:identifier
|
||||
func (c *API) DeleteKeyless() {
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package cloudflare
|
||||
|
||||
// Railgun
|
||||
|
||||
// https://api.cloudflare.com/#railgun-create-railgun
|
||||
// POST /railguns
|
||||
func (c *API) CreateRailgun() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#railgun-railgun-details
|
||||
// GET /railguns/:identifier
|
||||
|
||||
// https://api.cloudflare.com/#railgun-get-zones-connected-to-a-railgun
|
||||
// GET /railguns/:identifier/zones
|
||||
|
||||
// https://api.cloudflare.com/#railgun-enable-or-disable-a-railgun
|
||||
// PATCH /railguns/:identifier
|
||||
|
||||
// https://api.cloudflare.com/#railgun-delete-railgun
|
||||
// DELETE /railguns/:identifier
|
||||
|
||||
// Zone railgun info
|
||||
|
||||
// https://api.cloudflare.com/#railguns-for-a-zone-get-available-railguns
|
||||
// GET /zones/:zone_identifier/railguns
|
||||
func (c *API) Railguns() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#railguns-for-a-zone-get-railgun-details
|
||||
// GET /zones/:zone_identifier/railguns/:identifier
|
||||
func (c *API) Railgun() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
|
||||
// PATCH /zones/:zone_identifier/railguns/:identifier
|
||||
func (c *API) ZoneRailgun(connected bool) {
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package cloudflare
|
||||
|
||||
// https://api.cloudflare.com/#custom-ssl-for-a-zone-create-ssl-configuration
|
||||
// POST /zones/:zone_identifier/custom_certificates
|
||||
func (c *API) CreateSSL() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#custom-ssl-for-a-zone-list-ssl-configurations
|
||||
// GET /zones/:zone_identifier/custom_certificates
|
||||
func (c *API) ListSSL() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#custom-ssl-for-a-zone-ssl-configuration-details
|
||||
// GET /zones/:zone_identifier/custom_certificates/:identifier
|
||||
func (c *API) SSLDetails() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#custom-ssl-for-a-zone-update-ssl-configuration
|
||||
// PATCH /zones/:zone_identifier/custom_certificates/:identifier
|
||||
func (c *API) UpdateSSL() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#custom-ssl-for-a-zone-re-prioritize-ssl-certificates
|
||||
// PUT /zones/:zone_identifier/custom_certificates/prioritize
|
||||
func (c *API) ReprioSSL() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#custom-ssl-for-a-zone-delete-an-ssl-certificate
|
||||
// DELETE /zones/:zone_identifier/custom_certificates/:identifier
|
||||
func (c *API) DeleteSSL() {
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
package cloudflare
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
Creates a zone on an account.
|
||||
|
||||
API reference: https://api.cloudflare.com/#zone-create-a-zone
|
||||
*/
|
||||
func (api *API) CreateZone(z Zone) {
|
||||
// res, err := api.makeRequest("POST", "/zones", z)
|
||||
}
|
||||
|
||||
/*
|
||||
List zones on an account. Optionally takes a list of zones to filter results.
|
||||
|
||||
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 ZoneResponse
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
/*
|
||||
Fetches information about a zone.
|
||||
|
||||
|
||||
https://api.cloudflare.com/#zone-zone-details
|
||||
GET /zones/:id
|
||||
*/
|
||||
func (api *API) ZoneDetails(z Zone) {
|
||||
// XXX: Should we make the user get the zone ID themselves with ListZones, or do the hard work here?
|
||||
// ListZones gives the same information as this endpoint anyway so perhaps this is of limited use?
|
||||
// Maybe for users who already know the ID or fetched it in another call.
|
||||
type result struct {
|
||||
Response
|
||||
Result Zone `json:"result"`
|
||||
}
|
||||
// If z has an ID then query for that directly, else call ListZones to
|
||||
// fetch by name.
|
||||
// var zone Zone
|
||||
if z.ID != "" {
|
||||
// res, _ := makeRequest(c, "GET", "/zones/"+z.ID, nil)
|
||||
// zone = res.Result
|
||||
} else {
|
||||
// zones, err := ListZones(c, z.Name)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// Only one zone should have been returned
|
||||
// zone := zones[0]
|
||||
}
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#zone-edit-zone-properties
|
||||
// PATCH /zones/:id
|
||||
func EditZone() {
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#zone-purge-all-files
|
||||
// DELETE /zones/:id/purge_cache
|
||||
func (api *API) PurgeEverything(zoneID string) (PurgeCacheResponse, error) {
|
||||
uri := "/zones/" + zoneID + "/purge_cache"
|
||||
res, err := api.makeRequest("DELETE", uri, PurgeCacheRequest{true, 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
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#zone-purge-individual-files-by-url-and-cache-tags
|
||||
// DELETE /zones/:id/purge_cache
|
||||
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
|
||||
}
|
||||
|
||||
// https://api.cloudflare.com/#zone-delete-a-zone
|
||||
// DELETE /zones/:id
|
||||
func DeleteZone() {
|
||||
}
|
||||
|
||||
// Zone Plan
|
||||
// https://api.cloudflare.com/#zone-plan-available-plans
|
||||
// https://api.cloudflare.com/#zone-plan-plan-details
|
||||
|
||||
// Zone Settings
|
||||
// https://api.cloudflare.com/#zone-settings-for-a-zone-get-all-zone-settings
|
||||
// e.g.
|
||||
// https://api.cloudflare.com/#zone-settings-for-a-zone-get-always-online-setting
|
||||
// https://api.cloudflare.com/#zone-settings-for-a-zone-change-always-online-setting
|
|
@ -530,6 +530,12 @@
|
|||
"path": "github.com/cenkalti/backoff",
|
||||
"revision": "4dc77674aceaabba2c7e3da25d4c823edfb73f99"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "JJWLM3YJwgJD4vOLZnOYi1C2k0E=",
|
||||
"path": "github.com/cloudflare/cloudflare-go",
|
||||
"revision": "746075f034254832ead032aee02ac072636ff25a",
|
||||
"revisionTime": "2016-06-01T21:42:51Z"
|
||||
},
|
||||
{
|
||||
"comment": "v2.3.0-alpha.0-652-ge552791",
|
||||
"path": "github.com/coreos/etcd/client",
|
||||
|
@ -989,10 +995,6 @@
|
|||
"path": "github.com/mitchellh/cli",
|
||||
"revision": "83f97d41cf100ee5f33944a8815c167d5e4aa272"
|
||||
},
|
||||
{
|
||||
"path": "github.com/mitchellh/cloudflare-go",
|
||||
"revision": "84c7a0993a06d555dbfddd2b32f5fa9b92fa1dc1"
|
||||
},
|
||||
{
|
||||
"path": "github.com/mitchellh/colorstring",
|
||||
"revision": "8631ce90f28644f54aeedcb3e389a85174e067d1"
|
||||
|
|
Loading…
Reference in New Issue