Initial commit

This commit is contained in:
2016-08-16 00:14:59 +01:00
commit fec014579d
26 changed files with 2947 additions and 0 deletions

31
Makefile Normal file
View File

@@ -0,0 +1,31 @@
DEV_DEPS = github.com/kardianos/govendor \
github.com/vektra/mockery/.../ \
BIN_PATH = ./bin/cloudflare-dyndns
test: dev-deps
@govendor test +local +program
install: dev-deps
@govendor install +local +program
build:
mkdir -p bin && go build -o $(BIN_PATH)
run: build
$(BIN_PATH)
fetch-vendor: dev-deps
@govendor fetch +external +missing
install-vendor: dev-deps
@govendor install +vendor
dev-deps:
@$(foreach DEP,$(DEV_DEPS),go get $(DEP);)
update-dev-deps:
@$(foreach DEP,$(DEV_DEPS),go get -u $(DEP);)
.PHONY: test install build run fetch-vendor install-vendor dev-deps \
update-dev-deps

21
main.go Normal file
View File

@@ -0,0 +1,21 @@
package main
import (
"log"
"os"
"github.com/jimeh/cloudflare-dyndns/updater"
)
func main() {
var email = os.Getenv("CF_EMAIL")
var apiKey = os.Getenv("CF_API")
var host = os.Getenv("CF_HOST")
updater := updater.New(email, apiKey)
err := updater.Update(host)
if err != nil {
log.Fatal(err)
}
}

173
updater/updater.go Normal file
View File

@@ -0,0 +1,173 @@
package updater
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
"time"
"github.com/cloudflare/cloudflare-go"
)
// DefaultIPCheckURL is the default URL used to figure out the public IP.
const DefaultIPCheckURL = "http://whatismyip.akamai.com/"
// DefaultInterval is the default number of seconds to wait before each update.
const DefaultInterval = 30
// New creates a new DynDNS instance.
func New(email string, apiKey string) *Updater {
api, err := cloudflare.New(apiKey, email)
if err != nil {
log.Fatal(err)
}
return &Updater{
API: api,
IPCheckURL: DefaultIPCheckURL,
Interval: DefaultInterval,
}
}
// Updater deals with updating the IP address for a DNS record
type Updater struct {
API *cloudflare.API
IPCheckURL string
Interval int
}
// Update performs a the full update sequence.
func (u *Updater) Update(host string) error {
fmt.Printf("Looking up record for %s...\n", host)
record, err := u.RecordByHost(host)
if err != nil {
return err
}
fmt.Printf("Found %s (%s)\n", record.Name, record.ID)
fmt.Printf("Starting IP check (repeats every %d seconds)\n", u.Interval)
for {
record, err = u.UpdateRecord(record)
if err != nil {
fmt.Printf("ERROR: %s\n", err.Error())
fmt.Printf("Retrying in %d seconds...", u.Interval)
}
time.Sleep(time.Duration(u.Interval) * time.Second)
}
}
// UpdateRecord updates a cloudflare.DNSRecord.
func (u *Updater) UpdateRecord(record *cloudflare.DNSRecord) (*cloudflare.DNSRecord, error) {
currentIP, err := u.WhatIsMyIP()
if err != nil {
return nil, err
}
record, err = u.Record(record.ZoneID, record.ID)
if err != nil {
return nil, err
}
if currentIP != record.Content {
fmt.Printf(
"Updating %s to %s (was %s)\n",
record.Name, currentIP, record.Content,
)
record.Content = currentIP
err = u.API.UpdateDNSRecord(record.ZoneID, record.ID, *record)
if err != nil {
return nil, err
}
}
return record, nil
}
// Record fetches a cloudflare.DNSRecord from the given Zone and Record IDs.
func (u *Updater) Record(zoneID string, recordID string) (*cloudflare.DNSRecord, error) {
record, err := u.API.DNSRecord(zoneID, recordID)
if err != nil {
return nil, err
}
return &record, nil
}
// RecordByHost fetches a cloudflare.DNSRecord from the host given.
func (u *Updater) RecordByHost(host string) (*cloudflare.DNSRecord, error) {
zoneID, err := u.ZoneID(host)
if err != nil {
return nil, err
}
recordID, err := u.RecordID(host, zoneID)
if err != nil {
return nil, err
}
record, err := u.Record(zoneID, recordID)
if err != nil {
return nil, err
}
return record, nil
}
// WhatIsMyIP fetches the public IP via http://whatismyip.akamai.com/
func (u *Updater) WhatIsMyIP() (string, error) {
client := &http.Client{Timeout: time.Second * 10}
resp, err := client.Get(u.IPCheckURL)
if err != nil {
return "", err
}
if resp.StatusCode != 200 {
return "", fmt.Errorf(
"Got a %d response from %s",
resp.StatusCode, u.IPCheckURL,
)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}
// ZoneID finds the zone ID for the relevant Host.
func (u *Updater) ZoneID(host string) (string, error) {
zones, err := u.API.ListZones()
if err != nil {
return "", err
}
for _, zone := range zones {
if strings.HasSuffix(host, zone.Name) {
return zone.ID, nil
}
}
return "", fmt.Errorf("No zone found for \"%s\"", host)
}
// RecordID finds the host's DNS record ID.
func (u *Updater) RecordID(host string, zoneID string) (string, error) {
records, err := u.API.DNSRecords(zoneID, cloudflare.DNSRecord{})
if err != nil {
return "", err
}
for _, r := range records {
if r.Type == "A" && r.Name == host {
return r.ID, nil
}
}
return "", fmt.Errorf("No A type record found for \"%s\"", host)
}

26
vendor/github.com/cloudflare/cloudflare-go/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,26 @@
Copyright (c) 2015-2016, CloudFlare. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

96
vendor/github.com/cloudflare/cloudflare-go/README.md generated vendored Normal file
View File

@@ -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.

View File

@@ -0,0 +1,330 @@
// 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)
case http.StatusServiceUnavailable, http.StatusBadGateway, http.StatusGatewayTimeout,
522, 523, 524:
return nil, errors.Errorf("HTTP status %d: service failure", 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 = cloneHeader(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
}
// cloneHeader returns a shallow copy of the header.
// copied from https://godoc.org/github.com/golang/gddo/httputil/header#Copy
func cloneHeader(header http.Header) http.Header {
h := make(http.Header)
for k, vs := range header {
h[k] = vs
}
return h
}
// ResponseInfo contains a code and message returned by the API as errors or
// informational messages inside the response.
type ResponseInfo struct {
Code int `json:"code"`
Message string `json:"message"`
}
// Response is a template. There will also be a result struct. There will be a
// unique response type for each response, which will include this type.
type Response struct {
Success bool `json:"success"`
Errors []ResponseInfo `json:"errors"`
Messages []ResponseInfo `json:"messages"`
}
// ResultInfo contains metadata about the Response.
type ResultInfo struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
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"`
}

10
vendor/github.com/cloudflare/cloudflare-go/cpage.go generated vendored Normal file
View File

@@ -0,0 +1,10 @@
package cloudflare
// https://api.cloudflare.com/#custom-pages-for-a-zone-available-custom-pages
// GET /zones/:zone_identifier/custom_pages
// https://api.cloudflare.com/#custom-pages-for-a-zone-custom-page-details
// GET /zones/:zone_identifier/custom_pages/:identifier
// https://api.cloudflare.com/#custom-pages-for-a-zone-update-custom-page-url
// PUT /zones/:zone_identifier/custom_pages/:identifier

124
vendor/github.com/cloudflare/cloudflare-go/dns.go generated vendored Normal file
View File

@@ -0,0 +1,124 @@
package cloudflare
import (
"encoding/json"
"net/url"
"github.com/pkg/errors"
)
// 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 nil, errors.Wrap(err, errMakeRequestError)
}
var recordResp *DNSRecordResponse
err = json.Unmarshal(res, &recordResp)
if err != nil {
return nil, errors.Wrap(err, errUnmarshalError)
}
return recordResp, nil
}
// DNSRecords returns a slice of DNS records for the given zone identifier.
// 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{}
if rr.Name != "" {
v.Set("name", rr.Name)
}
if rr.Type != "" {
v.Set("type", rr.Type)
}
if rr.Content != "" {
v.Set("content", rr.Content)
}
var query string
if len(v) > 0 {
query = "?" + v.Encode()
}
uri := "/zones/" + zoneID + "/dns_records" + query
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return []DNSRecord{}, errors.Wrap(err, errMakeRequestError)
}
var r DNSListResponse
err = json.Unmarshal(res, &r)
if err != nil {
return []DNSRecord{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}
// DNSRecord returns a single DNS record for the given zone & record
// identifiers.
// API reference:
// https://api.cloudflare.com/#dns-records-for-a-zone-dns-record-details
// 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)
if err != nil {
return DNSRecord{}, errors.Wrap(err, errMakeRequestError)
}
var r DNSRecordResponse
err = json.Unmarshal(res, &r)
if err != nil {
return DNSRecord{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}
// UpdateDNSRecord updates a single DNS record for the given zone & record
// identifiers.
// API reference:
// https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record
// 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 {
return err
}
rr.Name = rec.Name
rr.Type = rec.Type
uri := "/zones/" + zoneID + "/dns_records/" + recordID
res, err := api.makeRequest("PUT", uri, rr)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
var r DNSRecordResponse
err = json.Unmarshal(res, &r)
if err != nil {
return errors.Wrap(err, errUnmarshalError)
}
return nil
}
// DeleteDNSRecord deletes a single DNS record for the given zone & record
// identifiers.
// API reference:
// https://api.cloudflare.com/#dns-records-for-a-zone-delete-dns-record
// 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)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
var r DNSRecordResponse
err = json.Unmarshal(res, &r)
if err != nil {
return errors.Wrap(err, errUnmarshalError)
}
return nil
}

47
vendor/github.com/cloudflare/cloudflare-go/errors.go generated vendored Normal file
View File

@@ -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()
}

36
vendor/github.com/cloudflare/cloudflare-go/ips.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
package cloudflare
import (
"encoding/json"
"io/ioutil"
"net/http"
"github.com/pkg/errors"
)
/*
IPs gets a list of CloudFlare's IP ranges
This does not require logging in to the API.
API reference:
https://api.cloudflare.com/#cloudflare-ips
GET /client/v4/ips
*/
func IPs() (IPRanges, error) {
resp, err := http.Get(apiURL + "/ips")
if err != nil {
return IPRanges{}, errors.Wrap(err, "HTTP request failed")
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return IPRanges{}, errors.Wrap(err, "Response body could not be read")
}
var r IPsResponse
err = json.Unmarshal(body, &r)
if err != nil {
return IPRanges{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}

36
vendor/github.com/cloudflare/cloudflare-go/keyless.go generated vendored Normal file
View File

@@ -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() {
}

39
vendor/github.com/cloudflare/cloudflare-go/options.go generated vendored Normal file
View File

@@ -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
}

View File

@@ -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"`
}

232
vendor/github.com/cloudflare/cloudflare-go/pagerules.go generated vendored Normal file
View File

@@ -0,0 +1,232 @@
package cloudflare
import (
"encoding/json"
"time"
"github.com/pkg/errors"
)
/*
PageRuleTarget is the target to evaluate on a request.
Currently Target must always be "url" and Operator must be "matches". Value
is the URL pattern to match against.
*/
type PageRuleTarget struct {
Target string `json:"target"`
Constraint struct {
Operator string `json:"operator"`
Value string `json:"value"`
} `json:"constraint"`
}
/*
PageRuleAction is the action to take when the target is matched.
Valid IDs are:
always_online
always_use_https
browser_cache_ttl
browser_check
cache_level
disable_apps
disable_performance
disable_railgun
disable_security
edge_cache_ttl
email_obfuscation
forwarding_url
ip_geolocation
mirage
rocket_loader
security_level
server_side_exclude
smart_errors
ssl
waf
*/
type PageRuleAction struct {
ID string `json:"id"`
Value interface{} `json:"value"`
}
// PageRuleActions maps API action IDs to human-readable strings
var PageRuleActions = map[string]string{
"always_online": "Always Online", // Value of type string
"always_use_https": "Always Use HTTPS", // Value of type interface{}
"browser_cache_ttl": "Browser Cache TTL", // Value of type int
"browser_check": "Browser Integrity Check", // Value of type string
"cache_level": "Cache Level", // Value of type string
"disable_apps": "Disable Apps", // Value of type interface{}
"disable_performance": "Disable Performance", // Value of type interface{}
"disable_railgun": "Disable Railgun", // Value of type string
"disable_security": "Disable Security", // Value of type interface{}
"edge_cache_ttl": "Edge Cache TTL", // Value of type int
"email_obfuscation": "Email Obfuscation", // Value of type string
"forwarding_url": "Forwarding URL", // Value of type map[string]interface
"ip_geolocation": "IP Geolocation Header", // Value of type string
"mirage": "Mirage", // Value of type string
"rocket_loader": "Rocker Loader", // Value of type string
"security_level": "Security Level", // Value of type string
"server_side_exclude": "Server Side Excludes", // Value of type string
"smart_errors": "Smart Errors", // Value of type string
"ssl": "SSL", // Value of type string
"waf": "Web Application Firewall", // Value of type string
}
// PageRule describes a Page Rule.
type PageRule struct {
ID string `json:"id,omitempty"`
Targets []PageRuleTarget `json:"targets"`
Actions []PageRuleAction `json:"actions"`
Priority int `json:"priority"`
Status string `json:"status"` // can be: active, paused
ModifiedOn time.Time `json:"modified_on,omitempty"`
CreatedOn time.Time `json:"created_on,omitempty"`
}
// PageRuleDetailResponse is the API response, containing a single PageRule.
type PageRuleDetailResponse struct {
Success bool `json:"success"`
Errors []string `json:"errors"`
Messages []string `json:"messages"`
Result PageRule `json:"result"`
}
// PageRulesResponse is the API response, containing an array of PageRules.
type PageRulesResponse struct {
Success bool `json:"success"`
Errors []string `json:"errors"`
Messages []string `json:"messages"`
Result []PageRule `json:"result"`
}
/*
CreatePageRule creates a new Page Rule for a zone.
API reference:
https://api.cloudflare.com/#page-rules-for-a-zone-create-a-page-rule
POST /zones/:zone_identifier/pagerules
*/
func (api *API) CreatePageRule(zoneID string, rule PageRule) error {
uri := "/zones/" + zoneID + "/pagerules"
res, err := api.makeRequest("POST", uri, rule)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
var r PageRuleDetailResponse
err = json.Unmarshal(res, &r)
if err != nil {
return errors.Wrap(err, errUnmarshalError)
}
return nil
}
/*
ListPageRules returns all Page Rules for a zone.
API reference:
https://api.cloudflare.com/#page-rules-for-a-zone-list-page-rules
GET /zones/:zone_identifier/pagerules
*/
func (api *API) ListPageRules(zoneID string) ([]PageRule, error) {
uri := "/zones/" + zoneID + "/pagerules"
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return []PageRule{}, errors.Wrap(err, errMakeRequestError)
}
var r PageRulesResponse
err = json.Unmarshal(res, &r)
if err != nil {
return []PageRule{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}
/*
PageRule fetches detail about one Page Rule for a zone.
API reference:
https://api.cloudflare.com/#page-rules-for-a-zone-page-rule-details
GET /zones/:zone_identifier/pagerules/:identifier
*/
func (api *API) PageRule(zoneID, ruleID string) (PageRule, error) {
uri := "/zones/" + zoneID + "/pagerules/" + ruleID
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return PageRule{}, errors.Wrap(err, errMakeRequestError)
}
var r PageRuleDetailResponse
err = json.Unmarshal(res, &r)
if err != nil {
return PageRule{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}
/*
ChangePageRule lets change individual settings for a Page Rule. This is in
contrast to UpdatePageRule which replaces the entire Page Rule.
API reference:
https://api.cloudflare.com/#page-rules-for-a-zone-change-a-page-rule
PATCH /zones/:zone_identifier/pagerules/:identifier
*/
func (api *API) ChangePageRule(zoneID, ruleID string, rule PageRule) error {
uri := "/zones/" + zoneID + "/pagerules/" + ruleID
res, err := api.makeRequest("PATCH", uri, rule)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
var r PageRuleDetailResponse
err = json.Unmarshal(res, &r)
if err != nil {
return errors.Wrap(err, errUnmarshalError)
}
return nil
}
/*
UpdatePageRule lets you replace a Page Rule. This is in contrast to
ChangePageRule which lets you change individual settings.
API reference:
https://api.cloudflare.com/#page-rules-for-a-zone-update-a-page-rule
PUT /zones/:zone_identifier/pagerules/:identifier
*/
func (api *API) UpdatePageRule(zoneID, ruleID string, rule PageRule) error {
uri := "/zones/" + zoneID + "/pagerules/" + ruleID
res, err := api.makeRequest("PUT", uri, nil)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
var r PageRuleDetailResponse
err = json.Unmarshal(res, &r)
if err != nil {
return errors.Wrap(err, errUnmarshalError)
}
return nil
}
/*
DeletePageRule deletes a Page Rule for a zone.
API reference:
https://api.cloudflare.com/#page-rules-for-a-zone-delete-a-page-rule
DELETE /zones/:zone_identifier/pagerules/:identifier
*/
func (api *API) DeletePageRule(zoneID, ruleID string) error {
uri := "/zones/" + zoneID + "/pagerules/" + ruleID
res, err := api.makeRequest("DELETE", uri, nil)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
var r PageRuleDetailResponse
err = json.Unmarshal(res, &r)
if err != nil {
return errors.Wrap(err, errUnmarshalError)
}
return nil
}

311
vendor/github.com/cloudflare/cloudflare-go/railgun.go generated vendored Normal file
View File

@@ -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)
}

154
vendor/github.com/cloudflare/cloudflare-go/ssl.go generated vendored Normal file
View File

@@ -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
}

35
vendor/github.com/cloudflare/cloudflare-go/user.go generated vendored Normal file
View File

@@ -0,0 +1,35 @@
package cloudflare
import (
"encoding/json"
"github.com/pkg/errors"
)
// 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
}
// 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
}

View File

@@ -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
}

57
vendor/github.com/cloudflare/cloudflare-go/waf.go generated vendored Normal file
View File

@@ -0,0 +1,57 @@
package cloudflare
import (
"encoding/json"
"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
var res []byte
var err error
uri := "/zones/" + zoneID + "/firewall/waf/packages"
res, err = api.makeRequest("GET", uri, nil)
if err != nil {
return []WAFPackage{}, errors.Wrap(err, errMakeRequestError)
}
err = json.Unmarshal(res, &p)
if err != nil {
return []WAFPackage{}, errors.Wrap(err, errUnmarshalError)
}
if !p.Success {
// TODO: Provide an actual error message instead of always returning nil
return []WAFPackage{}, err
}
for pi := range p.Result {
packages = append(packages, p.Result[pi])
}
return packages, nil
}
// ListWAFRules returns a slice of the WAF rules for the given WAF package.
func (api *API) ListWAFRules(zoneID, packageID string) ([]WAFRule, error) {
var r WAFRulesResponse
var rules []WAFRule
var res []byte
var err error
uri := "/zones/" + zoneID + "/firewall/waf/packages/" + packageID + "/rules"
res, err = api.makeRequest("GET", uri, nil)
if err != nil {
return []WAFRule{}, errors.Wrap(err, errMakeRequestError)
}
err = json.Unmarshal(res, &r)
if err != nil {
return []WAFRule{}, errors.Wrap(err, errUnmarshalError)
}
if !r.Success {
// TODO: Provide an actual error message instead of always returning nil
return []WAFRule{}, err
}
for ri := range r.Result {
rules = append(rules, r.Result[ri])
}
return rules, nil
}

502
vendor/github.com/cloudflare/cloudflare-go/zone.go generated vendored Normal file
View File

@@ -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 time.Time `json:"created_on"`
ModifiedOn time.Time `json:"modified_on"`
NameServers []string `json:"name_servers"`
Owner Owner `json:"owner"`
Permissions []string `json:"permissions"`
Plan 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

23
vendor/github.com/pkg/errors/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,23 @@
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

52
vendor/github.com/pkg/errors/README.md generated vendored Normal file
View File

@@ -0,0 +1,52 @@
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors)
Package errors provides simple error handling primitives.
`go get github.com/pkg/errors`
The traditional error handling idiom in Go is roughly akin to
```go
if err != nil {
return err
}
```
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
## Adding context to an error
The errors.Wrap function returns a new error that adds context to the original error. For example
```go
_, err := ioutil.ReadAll(r)
if err != nil {
return errors.Wrap(err, "read failed")
}
```
## Retrieving the cause of an error
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
```go
type causer interface {
Cause() error
}
```
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
```go
switch err := errors.Cause(err).(type) {
case *MyError:
// handle specifically
default:
// unknown error
}
```
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
## Contributing
We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
Before proposing a change, please discuss your change by raising an issue.
## Licence
BSD-2-Clause

32
vendor/github.com/pkg/errors/appveyor.yml generated vendored Normal file
View File

@@ -0,0 +1,32 @@
version: build-{build}.{branch}
clone_folder: C:\gopath\src\github.com\pkg\errors
shallow_clone: true # for startup speed
environment:
GOPATH: C:\gopath
platform:
- x64
# http://www.appveyor.com/docs/installed-software
install:
# some helpful output for debugging builds
- go version
- go env
# pre-installed MinGW at C:\MinGW is 32bit only
# but MSYS2 at C:\msys64 has mingw64
- set PATH=C:\msys64\mingw64\bin;%PATH%
- gcc --version
- g++ --version
build_script:
- go install -v ./...
test_script:
- set PATH=C:\gopath\bin;%PATH%
- go test -v ./...
#artifacts:
# - path: '%GOPATH%\bin\*.exe'
deploy: off

236
vendor/github.com/pkg/errors/errors.go generated vendored Normal file
View File

@@ -0,0 +1,236 @@
// Package errors provides simple error handling primitives.
//
// The traditional error handling idiom in Go is roughly akin to
//
// if err != nil {
// return err
// }
//
// which applied recursively up the call stack results in error reports
// without context or debugging information. The errors package allows
// programmers to add context to the failure path in their code in a way
// that does not destroy the original value of the error.
//
// Adding context to an error
//
// The errors.Wrap function returns a new error that adds context to the
// original error. For example
//
// _, err := ioutil.ReadAll(r)
// if err != nil {
// return errors.Wrap(err, "read failed")
// }
//
// Retrieving the cause of an error
//
// Using errors.Wrap constructs a stack of errors, adding context to the
// preceding error. Depending on the nature of the error it may be necessary
// to reverse the operation of errors.Wrap to retrieve the original error
// for inspection. Any error value which implements this interface
//
// type causer interface {
// Cause() error
// }
//
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
// the topmost error which does not implement causer, which is assumed to be
// the original cause. For example:
//
// switch err := errors.Cause(err).(type) {
// case *MyError:
// // handle specifically
// default:
// // unknown error
// }
//
// causer interface is not exported by this package, but is considered a part
// of stable public API.
//
// Formatted printing of errors
//
// All error values returned from this package implement fmt.Formatter and can
// be formatted by the fmt package. The following verbs are supported
//
// %s print the error. If the error has a Cause it will be
// printed recursively
// %v see %s
// %+v extended format. Each Frame of the error's StackTrace will
// be printed in detail.
//
// Retrieving the stack trace of an error or wrapper
//
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
// invoked. This information can be retrieved with the following interface.
//
// type stackTracer interface {
// StackTrace() errors.StackTrace
// }
//
// Where errors.StackTrace is defined as
//
// type StackTrace []Frame
//
// The Frame type represents a call site in the stack trace. Frame supports
// the fmt.Formatter interface that can be used for printing information about
// the stack trace of this error. For example:
//
// if err, ok := err.(stackTracer); ok {
// for _, f := range err.StackTrace() {
// fmt.Printf("%+s:%d", f)
// }
// }
//
// stackTracer interface is not exported by this package, but is considered a part
// of stable public API.
//
// See the documentation for Frame.Format for more details.
package errors
import (
"fmt"
"io"
)
// New returns an error with the supplied message.
// New also records the stack trace at the point it was called.
func New(message string) error {
return &fundamental{
msg: message,
stack: callers(),
}
}
// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
// Errorf also records the stack trace at the point it was called.
func Errorf(format string, args ...interface{}) error {
return &fundamental{
msg: fmt.Sprintf(format, args...),
stack: callers(),
}
}
// fundamental is an error that has a message and a stack, but no caller.
type fundamental struct {
msg string
*stack
}
func (f *fundamental) Error() string { return f.msg }
func (f *fundamental) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
io.WriteString(s, f.msg)
f.stack.Format(s, verb)
return
}
fallthrough
case 's', 'q':
io.WriteString(s, f.msg)
}
}
type withStack struct {
error
*stack
}
func (w *withStack) Cause() error { return w.error }
func (w *withStack) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v", w.Cause())
w.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, w.Error())
case 'q':
fmt.Fprintf(s, "%q", w.Error())
}
}
// Wrap returns an error annotating err with message.
// If err is nil, Wrap returns nil.
func Wrap(err error, message string) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: message,
}
return &withStack{
err,
callers(),
}
}
// Wrapf returns an error annotating err with the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
return &withStack{
err,
callers(),
}
}
type withMessage struct {
cause error
msg string
}
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error { return w.cause }
func (w *withMessage) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v\n", w.Cause())
io.WriteString(s, w.msg)
return
}
fallthrough
case 's', 'q':
io.WriteString(s, w.Error())
}
}
// Cause returns the underlying cause of the error, if possible.
// An error value has a cause if it implements the following
// interface:
//
// type causer interface {
// Cause() error
// }
//
// If the error does not implement Cause, the original error will
// be returned. If the error is nil, nil will be returned without further
// investigation.
func Cause(err error) error {
type causer interface {
Cause() error
}
for err != nil {
cause, ok := err.(causer)
if !ok {
break
}
err = cause.Cause()
}
return err
}

178
vendor/github.com/pkg/errors/stack.go generated vendored Normal file
View File

@@ -0,0 +1,178 @@
package errors
import (
"fmt"
"io"
"path"
"runtime"
"strings"
)
// Frame represents a program counter inside a stack frame.
type Frame uintptr
// pc returns the program counter for this frame;
// multiple frames may have the same PC value.
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
// file returns the full path to the file that contains the
// function for this Frame's pc.
func (f Frame) file() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
file, _ := fn.FileLine(f.pc())
return file
}
// line returns the line number of source code of the
// function for this Frame's pc.
func (f Frame) line() int {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return 0
}
_, line := fn.FileLine(f.pc())
return line
}
// Format formats the frame according to the fmt.Formatter interface.
//
// %s source file
// %d source line
// %n function name
// %v equivalent to %s:%d
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+s path of source file relative to the compile time GOPATH
// %+v equivalent to %+s:%d
func (f Frame) Format(s fmt.State, verb rune) {
switch verb {
case 's':
switch {
case s.Flag('+'):
pc := f.pc()
fn := runtime.FuncForPC(pc)
if fn == nil {
io.WriteString(s, "unknown")
} else {
file, _ := fn.FileLine(pc)
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
}
default:
io.WriteString(s, path.Base(f.file()))
}
case 'd':
fmt.Fprintf(s, "%d", f.line())
case 'n':
name := runtime.FuncForPC(f.pc()).Name()
io.WriteString(s, funcname(name))
case 'v':
f.Format(s, 's')
io.WriteString(s, ":")
f.Format(s, 'd')
}
}
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame
func (st StackTrace) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case s.Flag('+'):
for _, f := range st {
fmt.Fprintf(s, "\n%+v", f)
}
case s.Flag('#'):
fmt.Fprintf(s, "%#v", []Frame(st))
default:
fmt.Fprintf(s, "%v", []Frame(st))
}
case 's':
fmt.Fprintf(s, "%s", []Frame(st))
}
}
// stack represents a stack of program counters.
type stack []uintptr
func (s *stack) Format(st fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case st.Flag('+'):
for _, pc := range *s {
f := Frame(pc)
fmt.Fprintf(st, "\n%+v", f)
}
}
}
}
func (s *stack) StackTrace() StackTrace {
f := make([]Frame, len(*s))
for i := 0; i < len(f); i++ {
f[i] = Frame((*s)[i])
}
return f
}
func callers() *stack {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
var st stack = pcs[0:n]
return &st
}
// funcname removes the path prefix component of a function's name reported by func.Name().
func funcname(name string) string {
i := strings.LastIndex(name, "/")
name = name[i+1:]
i = strings.Index(name, ".")
return name[i+1:]
}
func trimGOPATH(name, file string) string {
// Here we want to get the source file path relative to the compile time
// GOPATH. As of Go 1.6.x there is no direct way to know the compiled
// GOPATH at runtime, but we can infer the number of path segments in the
// GOPATH. We note that fn.Name() returns the function name qualified by
// the import path, which does not include the GOPATH. Thus we can trim
// segments from the beginning of the file path until the number of path
// separators remaining is one more than the number of path separators in
// the function name. For example, given:
//
// GOPATH /home/user
// file /home/user/src/pkg/sub/file.go
// fn.Name() pkg/sub.Type.Method
//
// We want to produce:
//
// pkg/sub/file.go
//
// From this we can easily see that fn.Name() has one less path separator
// than our desired output. We count separators from the end of the file
// path until it finds two more than in the function name and then move
// one character forward to preserve the initial path segment without a
// leading separator.
const sep = "/"
goal := strings.Count(name, sep) + 2
i := len(file)
for n := 0; n < goal; n++ {
i = strings.LastIndex(file[:i], sep)
if i == -1 {
// not enough separators found, set i so that the slice expression
// below leaves file unmodified
i = -len(sep)
break
}
}
// get back to 0 or trim the leading separator
file = file[i+len(sep):]
return file
}

19
vendor/vendor.json vendored Normal file
View File

@@ -0,0 +1,19 @@
{
"comment": "",
"ignore": "test",
"package": [
{
"checksumSHA1": "emj4cTM9bcEjpCtc6a2ri9pwNH8=",
"path": "github.com/cloudflare/cloudflare-go",
"revision": "1bef4b5a4aab0b06a9b4d47a1715f8fee5038583",
"revisionTime": "2016-08-02T13:28:18Z"
},
{
"checksumSHA1": "QoVjlQFru1ixgV8vh63T4/JAtLI=",
"path": "github.com/pkg/errors",
"revision": "a22138067af1c4942683050411a841ade67fe1eb",
"revisionTime": "2016-08-08T05:55:40Z"
}
],
"rootPath": "github.com/jimeh/cloudflare-dyndns"
}