Update lego

This commit is contained in:
Daniel Becker
2019-08-05 18:08:04 +02:00
committed by Traefiker Bot
parent 0a89cccdc0
commit 73e0561610
782 changed files with 113827 additions and 17222 deletions

View File

@@ -0,0 +1,180 @@
package cloudflare
import (
"encoding/json"
"fmt"
"net/url"
"strconv"
"time"
"github.com/pkg/errors"
)
// AccessApplication represents an Access application.
type AccessApplication struct {
ID string `json:"id,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
AUD string `json:"aud,omitempty"`
Name string `json:"name"`
Domain string `json:"domain"`
SessionDuration string `json:"session_duration,omitempty"`
}
// AccessApplicationListResponse represents the response from the list
// access applications endpoint.
type AccessApplicationListResponse struct {
Result []AccessApplication `json:"result"`
Response
ResultInfo `json:"result_info"`
}
// AccessApplicationDetailResponse is the API response, containing a single
// access application.
type AccessApplicationDetailResponse struct {
Success bool `json:"success"`
Errors []string `json:"errors"`
Messages []string `json:"messages"`
Result AccessApplication `json:"result"`
}
// AccessApplications returns all applications within a zone.
//
// API reference: https://api.cloudflare.com/#access-applications-list-access-applications
func (api *API) AccessApplications(zoneID string, pageOpts PaginationOptions) ([]AccessApplication, ResultInfo, error) {
v := url.Values{}
if pageOpts.PerPage > 0 {
v.Set("per_page", strconv.Itoa(pageOpts.PerPage))
}
if pageOpts.Page > 0 {
v.Set("page", strconv.Itoa(pageOpts.Page))
}
uri := "/zones/" + zoneID + "/access/apps"
if len(v) > 0 {
uri = uri + "?" + v.Encode()
}
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return []AccessApplication{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
}
var accessApplicationListResponse AccessApplicationListResponse
err = json.Unmarshal(res, &accessApplicationListResponse)
if err != nil {
return []AccessApplication{}, ResultInfo{}, errors.Wrap(err, errUnmarshalError)
}
return accessApplicationListResponse.Result, accessApplicationListResponse.ResultInfo, nil
}
// AccessApplication returns a single application based on the
// application ID.
//
// API reference: https://api.cloudflare.com/#access-applications-access-applications-details
func (api *API) AccessApplication(zoneID, applicationID string) (AccessApplication, error) {
uri := fmt.Sprintf(
"/zones/%s/access/apps/%s",
zoneID,
applicationID,
)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return AccessApplication{}, errors.Wrap(err, errMakeRequestError)
}
var accessApplicationDetailResponse AccessApplicationDetailResponse
err = json.Unmarshal(res, &accessApplicationDetailResponse)
if err != nil {
return AccessApplication{}, errors.Wrap(err, errUnmarshalError)
}
return accessApplicationDetailResponse.Result, nil
}
// CreateAccessApplication creates a new access application.
//
// API reference: https://api.cloudflare.com/#access-applications-create-access-application
func (api *API) CreateAccessApplication(zoneID string, accessApplication AccessApplication) (AccessApplication, error) {
uri := "/zones/" + zoneID + "/access/apps"
res, err := api.makeRequest("POST", uri, accessApplication)
if err != nil {
return AccessApplication{}, errors.Wrap(err, errMakeRequestError)
}
var accessApplicationDetailResponse AccessApplicationDetailResponse
err = json.Unmarshal(res, &accessApplicationDetailResponse)
if err != nil {
return AccessApplication{}, errors.Wrap(err, errUnmarshalError)
}
return accessApplicationDetailResponse.Result, nil
}
// UpdateAccessApplication updates an existing access application.
//
// API reference: https://api.cloudflare.com/#access-applications-update-access-application
func (api *API) UpdateAccessApplication(zoneID string, accessApplication AccessApplication) (AccessApplication, error) {
if accessApplication.ID == "" {
return AccessApplication{}, errors.Errorf("access application ID cannot be empty")
}
uri := fmt.Sprintf(
"/zones/%s/access/apps/%s",
zoneID,
accessApplication.ID,
)
res, err := api.makeRequest("PUT", uri, accessApplication)
if err != nil {
return AccessApplication{}, errors.Wrap(err, errMakeRequestError)
}
var accessApplicationDetailResponse AccessApplicationDetailResponse
err = json.Unmarshal(res, &accessApplicationDetailResponse)
if err != nil {
return AccessApplication{}, errors.Wrap(err, errUnmarshalError)
}
return accessApplicationDetailResponse.Result, nil
}
// DeleteAccessApplication deletes an access application.
//
// API reference: https://api.cloudflare.com/#access-applications-delete-access-application
func (api *API) DeleteAccessApplication(zoneID, applicationID string) error {
uri := fmt.Sprintf(
"/zones/%s/access/apps/%s",
zoneID,
applicationID,
)
_, err := api.makeRequest("DELETE", uri, nil)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
return nil
}
// RevokeAccessApplicationTokens revokes tokens associated with an
// access application.
//
// API reference: https://api.cloudflare.com/#access-applications-revoke-access-tokens
func (api *API) RevokeAccessApplicationTokens(zoneID, applicationID string) error {
uri := fmt.Sprintf(
"/zones/%s/access/apps/%s/revoke-tokens",
zoneID,
applicationID,
)
_, err := api.makeRequest("POST", uri, nil)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
return nil
}

View File

@@ -0,0 +1,221 @@
package cloudflare
import (
"encoding/json"
"fmt"
"net/url"
"strconv"
"time"
"github.com/pkg/errors"
)
// AccessPolicy defines a policy for allowing or disallowing access to
// one or more Access applications.
type AccessPolicy struct {
ID string `json:"id,omitempty"`
Precedence int `json:"precedence"`
Decision string `json:"decision"`
CreatedAt *time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at"`
Name string `json:"name"`
// The include policy works like an OR logical operator. The user must
// satisfy one of the rules.
Include []interface{} `json:"include"`
// The exclude policy works like a NOT logical operator. The user must
// not satisfy all of the rules in exclude.
Exclude []interface{} `json:"exclude"`
// The require policy works like a AND logical operator. The user must
// satisfy all of the rules in require.
Require []interface{} `json:"require"`
}
// AccessPolicyEmail is used for managing access based on the email.
// For example, restrict access to users with the email addresses
// `test@example.com` or `someone@example.com`.
type AccessPolicyEmail struct {
Email struct {
Email string `json:"email"`
} `json:"email"`
}
// AccessPolicyEmailDomain is used for managing access based on an email
// domain domain such as `example.com` instead of individual addresses.
type AccessPolicyEmailDomain struct {
EmailDomain struct {
Domain string `json:"domain"`
} `json:"email_domain"`
}
// AccessPolicyIP is used for managing access based in the IP. It
// accepts individual IPs or CIDRs.
type AccessPolicyIP struct {
IP struct {
IP string `json:"ip"`
} `json:"ip"`
}
// AccessPolicyEveryone is used for managing access to everyone.
type AccessPolicyEveryone struct {
Everyone struct{} `json:"everyone"`
}
// AccessPolicyAccessGroup is used for managing access based on an
// access group.
type AccessPolicyAccessGroup struct {
Group struct {
ID string `json:"id"`
} `json:"group"`
}
// AccessPolicyListResponse represents the response from the list
// access polciies endpoint.
type AccessPolicyListResponse struct {
Result []AccessPolicy `json:"result"`
Response
ResultInfo `json:"result_info"`
}
// AccessPolicyDetailResponse is the API response, containing a single
// access policy.
type AccessPolicyDetailResponse struct {
Success bool `json:"success"`
Errors []string `json:"errors"`
Messages []string `json:"messages"`
Result AccessPolicy `json:"result"`
}
// AccessPolicies returns all access policies for an access application.
//
// API reference: https://api.cloudflare.com/#access-policy-list-access-policies
func (api *API) AccessPolicies(zoneID, applicationID string, pageOpts PaginationOptions) ([]AccessPolicy, ResultInfo, error) {
v := url.Values{}
if pageOpts.PerPage > 0 {
v.Set("per_page", strconv.Itoa(pageOpts.PerPage))
}
if pageOpts.Page > 0 {
v.Set("page", strconv.Itoa(pageOpts.Page))
}
uri := fmt.Sprintf(
"/zones/%s/access/apps/%s/policies",
zoneID,
applicationID,
)
if len(v) > 0 {
uri = uri + "?" + v.Encode()
}
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return []AccessPolicy{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
}
var accessPolicyListResponse AccessPolicyListResponse
err = json.Unmarshal(res, &accessPolicyListResponse)
if err != nil {
return []AccessPolicy{}, ResultInfo{}, errors.Wrap(err, errUnmarshalError)
}
return accessPolicyListResponse.Result, accessPolicyListResponse.ResultInfo, nil
}
// AccessPolicy returns a single policy based on the policy ID.
//
// API reference: https://api.cloudflare.com/#access-policy-access-policy-details
func (api *API) AccessPolicy(zoneID, applicationID, policyID string) (AccessPolicy, error) {
uri := fmt.Sprintf(
"/zones/%s/access/apps/%s/policies/%s",
zoneID,
applicationID,
policyID,
)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return AccessPolicy{}, errors.Wrap(err, errMakeRequestError)
}
var accessPolicyDetailResponse AccessPolicyDetailResponse
err = json.Unmarshal(res, &accessPolicyDetailResponse)
if err != nil {
return AccessPolicy{}, errors.Wrap(err, errUnmarshalError)
}
return accessPolicyDetailResponse.Result, nil
}
// CreateAccessPolicy creates a new access policy.
//
// API reference: https://api.cloudflare.com/#access-policy-create-access-policy
func (api *API) CreateAccessPolicy(zoneID, applicationID string, accessPolicy AccessPolicy) (AccessPolicy, error) {
uri := fmt.Sprintf(
"/zones/%s/access/apps/%s/policies",
zoneID,
applicationID,
)
res, err := api.makeRequest("POST", uri, accessPolicy)
if err != nil {
return AccessPolicy{}, errors.Wrap(err, errMakeRequestError)
}
var accessPolicyDetailResponse AccessPolicyDetailResponse
err = json.Unmarshal(res, &accessPolicyDetailResponse)
if err != nil {
return AccessPolicy{}, errors.Wrap(err, errUnmarshalError)
}
return accessPolicyDetailResponse.Result, nil
}
// UpdateAccessPolicy updates an existing access policy.
//
// API reference: https://api.cloudflare.com/#access-policy-update-access-policy
func (api *API) UpdateAccessPolicy(zoneID, applicationID string, accessPolicy AccessPolicy) (AccessPolicy, error) {
if accessPolicy.ID == "" {
return AccessPolicy{}, errors.Errorf("access policy ID cannot be empty")
}
uri := fmt.Sprintf(
"/zones/%s/access/apps/%s/policies/%s",
zoneID,
applicationID,
accessPolicy.ID,
)
res, err := api.makeRequest("PUT", uri, accessPolicy)
if err != nil {
return AccessPolicy{}, errors.Wrap(err, errMakeRequestError)
}
var accessPolicyDetailResponse AccessPolicyDetailResponse
err = json.Unmarshal(res, &accessPolicyDetailResponse)
if err != nil {
return AccessPolicy{}, errors.Wrap(err, errUnmarshalError)
}
return accessPolicyDetailResponse.Result, nil
}
// DeleteAccessPolicy deletes an access policy.
//
// API reference: https://api.cloudflare.com/#access-policy-update-access-policy
func (api *API) DeleteAccessPolicy(zoneID, applicationID, accessPolicyID string) error {
uri := fmt.Sprintf(
"/zones/%s/access/apps/%s/policies/%s",
zoneID,
applicationID,
accessPolicyID,
)
_, err := api.makeRequest("DELETE", uri, nil)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
return nil
}

View File

@@ -0,0 +1,186 @@
package cloudflare
import (
"encoding/json"
"fmt"
"net/url"
"strconv"
"github.com/pkg/errors"
)
// AccountMember is the definition of a member of an account.
type AccountMember struct {
ID string `json:"id"`
Code string `json:"code"`
User AccountMemberUserDetails `json:"user"`
Status string `json:"status"`
Roles []AccountRole `json:"roles"`
}
// AccountMemberUserDetails outlines all the personal information about
// a member.
type AccountMemberUserDetails struct {
ID string `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
TwoFactorAuthenticationEnabled bool
}
// AccountMembersListResponse represents the response from the list
// account members endpoint.
type AccountMembersListResponse struct {
Result []AccountMember `json:"result"`
Response
ResultInfo `json:"result_info"`
}
// AccountMemberDetailResponse is the API response, containing a single
// account member.
type AccountMemberDetailResponse struct {
Success bool `json:"success"`
Errors []string `json:"errors"`
Messages []string `json:"messages"`
Result AccountMember `json:"result"`
}
// AccountMemberInvitation represents the invitation for a new member to
// the account.
type AccountMemberInvitation struct {
Email string `json:"email"`
Roles []string `json:"roles"`
}
// AccountMembers returns all members of an account.
//
// API reference: https://api.cloudflare.com/#accounts-list-accounts
func (api *API) AccountMembers(accountID string, pageOpts PaginationOptions) ([]AccountMember, ResultInfo, error) {
if accountID == "" {
return []AccountMember{}, ResultInfo{}, errors.New(errMissingAccountID)
}
v := url.Values{}
if pageOpts.PerPage > 0 {
v.Set("per_page", strconv.Itoa(pageOpts.PerPage))
}
if pageOpts.Page > 0 {
v.Set("page", strconv.Itoa(pageOpts.Page))
}
uri := "/accounts/" + accountID + "/members"
if len(v) > 0 {
uri = uri + "?" + v.Encode()
}
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return []AccountMember{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
}
var accountMemberListresponse AccountMembersListResponse
err = json.Unmarshal(res, &accountMemberListresponse)
if err != nil {
return []AccountMember{}, ResultInfo{}, errors.Wrap(err, errUnmarshalError)
}
return accountMemberListresponse.Result, accountMemberListresponse.ResultInfo, nil
}
// CreateAccountMember invites a new member to join an account.
//
// API reference: https://api.cloudflare.com/#account-members-add-member
func (api *API) CreateAccountMember(accountID string, emailAddress string, roles []string) (AccountMember, error) {
if accountID == "" {
return AccountMember{}, errors.New(errMissingAccountID)
}
uri := "/accounts/" + accountID + "/members"
var newMember = AccountMemberInvitation{
Email: emailAddress,
Roles: roles,
}
res, err := api.makeRequest("POST", uri, newMember)
if err != nil {
return AccountMember{}, errors.Wrap(err, errMakeRequestError)
}
var accountMemberListResponse AccountMemberDetailResponse
err = json.Unmarshal(res, &accountMemberListResponse)
if err != nil {
return AccountMember{}, errors.Wrap(err, errUnmarshalError)
}
return accountMemberListResponse.Result, nil
}
// DeleteAccountMember removes a member from an account.
//
// API reference: https://api.cloudflare.com/#account-members-remove-member
func (api *API) DeleteAccountMember(accountID string, userID string) error {
if accountID == "" {
return errors.New(errMissingAccountID)
}
uri := fmt.Sprintf("/accounts/%s/members/%s", accountID, userID)
_, err := api.makeRequest("DELETE", uri, nil)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
return nil
}
// UpdateAccountMember modifies an existing account member.
//
// API reference: https://api.cloudflare.com/#account-members-update-member
func (api *API) UpdateAccountMember(accountID string, userID string, member AccountMember) (AccountMember, error) {
if accountID == "" {
return AccountMember{}, errors.New(errMissingAccountID)
}
uri := fmt.Sprintf("/accounts/%s/members/%s", accountID, userID)
res, err := api.makeRequest("PUT", uri, member)
if err != nil {
return AccountMember{}, errors.Wrap(err, errMakeRequestError)
}
var accountMemberListResponse AccountMemberDetailResponse
err = json.Unmarshal(res, &accountMemberListResponse)
if err != nil {
return AccountMember{}, errors.Wrap(err, errUnmarshalError)
}
return accountMemberListResponse.Result, nil
}
// AccountMember returns details of a single account member.
//
// API reference: https://api.cloudflare.com/#account-members-member-details
func (api *API) AccountMember(accountID string, memberID string) (AccountMember, error) {
if accountID == "" {
return AccountMember{}, errors.New(errMissingAccountID)
}
uri := fmt.Sprintf(
"/accounts/%s/members/%s",
accountID,
memberID,
)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return AccountMember{}, errors.Wrap(err, errMakeRequestError)
}
var accountMemberResponse AccountMemberDetailResponse
err = json.Unmarshal(res, &accountMemberResponse)
if err != nil {
return AccountMember{}, errors.Wrap(err, errUnmarshalError)
}
return accountMemberResponse.Result, nil
}

View File

@@ -0,0 +1,80 @@
package cloudflare
import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
)
// AccountRole defines the roles that a member can have attached.
type AccountRole struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Permissions map[string]AccountRolePermission `json:"permissions"`
}
// AccountRolePermission is the shared structure for all permissions
// that can be assigned to a member.
type AccountRolePermission struct {
Read bool `json:"read"`
Edit bool `json:"edit"`
}
// AccountRolesListResponse represents the list response from the
// account roles.
type AccountRolesListResponse struct {
Result []AccountRole `json:"result"`
Response
ResultInfo `json:"result_info"`
}
// AccountRoleDetailResponse is the API response, containing a single
// account role.
type AccountRoleDetailResponse struct {
Success bool `json:"success"`
Errors []string `json:"errors"`
Messages []string `json:"messages"`
Result AccountRole `json:"result"`
}
// AccountRoles returns all roles of an account.
//
// API reference: https://api.cloudflare.com/#account-roles-list-roles
func (api *API) AccountRoles(accountID string) ([]AccountRole, error) {
uri := "/accounts/" + accountID + "/roles"
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return []AccountRole{}, errors.Wrap(err, errMakeRequestError)
}
var accountRolesListResponse AccountRolesListResponse
err = json.Unmarshal(res, &accountRolesListResponse)
if err != nil {
return []AccountRole{}, errors.Wrap(err, errUnmarshalError)
}
return accountRolesListResponse.Result, nil
}
// AccountRole returns the details of a single account role.
//
// API reference: https://api.cloudflare.com/#account-roles-role-details
func (api *API) AccountRole(accountID string, roleID string) (AccountRole, error) {
uri := fmt.Sprintf("/accounts/%s/roles/%s", accountID, roleID)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return AccountRole{}, errors.Wrap(err, errMakeRequestError)
}
var accountRole AccountRoleDetailResponse
err = json.Unmarshal(res, &accountRole)
if err != nil {
return AccountRole{}, errors.Wrap(err, errUnmarshalError)
}
return accountRole.Result, nil
}

114
vendor/github.com/cloudflare/cloudflare-go/accounts.go generated vendored Normal file
View File

@@ -0,0 +1,114 @@
package cloudflare
import (
"encoding/json"
"net/url"
"strconv"
"github.com/pkg/errors"
)
// AccountSettings outlines the available options for an account.
type AccountSettings struct {
EnforceTwoFactor bool `json:"enforce_twofactor"`
}
// Account represents the root object that owns resources.
type Account struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Settings *AccountSettings `json:"settings"`
}
// AccountResponse represents the response from the accounts endpoint for a
// single account ID.
type AccountResponse struct {
Result Account `json:"result"`
Response
ResultInfo `json:"result_info"`
}
// AccountListResponse represents the response from the list accounts endpoint.
type AccountListResponse struct {
Result []Account `json:"result"`
Response
ResultInfo `json:"result_info"`
}
// AccountDetailResponse is the API response, containing a single Account.
type AccountDetailResponse struct {
Success bool `json:"success"`
Errors []string `json:"errors"`
Messages []string `json:"messages"`
Result Account `json:"result"`
}
// Accounts returns all accounts the logged in user has access to.
//
// API reference: https://api.cloudflare.com/#accounts-list-accounts
func (api *API) Accounts(pageOpts PaginationOptions) ([]Account, ResultInfo, error) {
v := url.Values{}
if pageOpts.PerPage > 0 {
v.Set("per_page", strconv.Itoa(pageOpts.PerPage))
}
if pageOpts.Page > 0 {
v.Set("page", strconv.Itoa(pageOpts.Page))
}
uri := "/accounts"
if len(v) > 0 {
uri = uri + "?" + v.Encode()
}
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return []Account{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
}
var accListResponse AccountListResponse
err = json.Unmarshal(res, &accListResponse)
if err != nil {
return []Account{}, ResultInfo{}, errors.Wrap(err, errUnmarshalError)
}
return accListResponse.Result, accListResponse.ResultInfo, nil
}
// Account returns a single account based on the ID.
//
// API reference: https://api.cloudflare.com/#accounts-account-details
func (api *API) Account(accountID string) (Account, ResultInfo, error) {
uri := "/accounts/" + accountID
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return Account{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
}
var accResponse AccountResponse
err = json.Unmarshal(res, &accResponse)
if err != nil {
return Account{}, ResultInfo{}, errors.Wrap(err, errUnmarshalError)
}
return accResponse.Result, accResponse.ResultInfo, nil
}
// UpdateAccount allows management of an account using the account ID.
//
// API reference: https://api.cloudflare.com/#accounts-update-account
func (api *API) UpdateAccount(accountID string, account Account) (Account, error) {
uri := "/accounts/" + accountID
res, err := api.makeRequest("PUT", uri, account)
if err != nil {
return Account{}, errors.Wrap(err, errMakeRequestError)
}
var a AccountDetailResponse
err = json.Unmarshal(res, &a)
if err != nil {
return Account{}, errors.Wrap(err, errUnmarshalError)
}
return a.Result, nil
}

120
vendor/github.com/cloudflare/cloudflare-go/argo.go generated vendored Normal file
View File

@@ -0,0 +1,120 @@
package cloudflare
import (
"encoding/json"
"fmt"
"time"
"github.com/pkg/errors"
)
var validSettingValues = []string{"on", "off"}
// ArgoFeatureSetting is the structure of the API object for the
// argo smart routing and tiered caching settings.
type ArgoFeatureSetting struct {
Editable bool `json:"editable,omitempty"`
ID string `json:"id,omitempty"`
ModifiedOn time.Time `json:"modified_on,omitempty"`
Value string `json:"value"`
}
// ArgoDetailsResponse is the API response for the argo smart routing
// and tiered caching response.
type ArgoDetailsResponse struct {
Result ArgoFeatureSetting `json:"result"`
Response
}
// ArgoSmartRouting returns the current settings for smart routing.
//
// API reference: https://api.cloudflare.com/#argo-smart-routing-get-argo-smart-routing-setting
func (api *API) ArgoSmartRouting(zoneID string) (ArgoFeatureSetting, error) {
uri := "/zones/" + zoneID + "/argo/smart_routing"
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return ArgoFeatureSetting{}, errors.Wrap(err, errMakeRequestError)
}
var argoDetailsResponse ArgoDetailsResponse
err = json.Unmarshal(res, &argoDetailsResponse)
if err != nil {
return ArgoFeatureSetting{}, errors.Wrap(err, errUnmarshalError)
}
return argoDetailsResponse.Result, nil
}
// UpdateArgoSmartRouting updates the setting for smart routing.
//
// API reference: https://api.cloudflare.com/#argo-smart-routing-patch-argo-smart-routing-setting
func (api *API) UpdateArgoSmartRouting(zoneID, settingValue string) (ArgoFeatureSetting, error) {
if !contains(validSettingValues, settingValue) {
return ArgoFeatureSetting{}, errors.New(fmt.Sprintf("invalid setting value '%s'. must be 'on' or 'off'", settingValue))
}
uri := "/zones/" + zoneID + "/argo/smart_routing"
res, err := api.makeRequest("PATCH", uri, ArgoFeatureSetting{Value: settingValue})
if err != nil {
return ArgoFeatureSetting{}, errors.Wrap(err, errMakeRequestError)
}
var argoDetailsResponse ArgoDetailsResponse
err = json.Unmarshal(res, &argoDetailsResponse)
if err != nil {
return ArgoFeatureSetting{}, errors.Wrap(err, errUnmarshalError)
}
return argoDetailsResponse.Result, nil
}
// ArgoTieredCaching returns the current settings for tiered caching.
//
// API reference: TBA
func (api *API) ArgoTieredCaching(zoneID string) (ArgoFeatureSetting, error) {
uri := "/zones/" + zoneID + "/argo/tiered_caching"
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return ArgoFeatureSetting{}, errors.Wrap(err, errMakeRequestError)
}
var argoDetailsResponse ArgoDetailsResponse
err = json.Unmarshal(res, &argoDetailsResponse)
if err != nil {
return ArgoFeatureSetting{}, errors.Wrap(err, errUnmarshalError)
}
return argoDetailsResponse.Result, nil
}
// UpdateArgoTieredCaching updates the setting for tiered caching.
//
// API reference: TBA
func (api *API) UpdateArgoTieredCaching(zoneID, settingValue string) (ArgoFeatureSetting, error) {
if !contains(validSettingValues, settingValue) {
return ArgoFeatureSetting{}, errors.New(fmt.Sprintf("invalid setting value '%s'. must be 'on' or 'off'", settingValue))
}
uri := "/zones/" + zoneID + "/argo/tiered_caching"
res, err := api.makeRequest("PATCH", uri, ArgoFeatureSetting{Value: settingValue})
if err != nil {
return ArgoFeatureSetting{}, errors.Wrap(err, errMakeRequestError)
}
var argoDetailsResponse ArgoDetailsResponse
err = json.Unmarshal(res, &argoDetailsResponse)
if err != nil {
return ArgoFeatureSetting{}, errors.Wrap(err, errUnmarshalError)
}
return argoDetailsResponse.Result, nil
}
func contains(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}

143
vendor/github.com/cloudflare/cloudflare-go/auditlogs.go generated vendored Normal file
View File

@@ -0,0 +1,143 @@
package cloudflare
import (
"encoding/base64"
"encoding/json"
"fmt"
"time"
)
// AuditLogAction is a member of AuditLog, the action that was taken.
type AuditLogAction struct {
Result bool `json:"result"`
Type string `json:"type"`
}
// AuditLogActor is a member of AuditLog, who performed the action.
type AuditLogActor struct {
Email string `json:"email"`
ID string `json:"id"`
IP string `json:"ip"`
Type string `json:"type"`
}
// AuditLogOwner is a member of AuditLog, who owns this audit log.
type AuditLogOwner struct {
ID string `json:"id"`
}
// AuditLogResource is a member of AuditLog, what was the action performed on.
type AuditLogResource struct {
ID string `json:"id"`
Type string `json:"type"`
}
// AuditLog is an resource that represents an update in the cloudflare dash
type AuditLog struct {
Action AuditLogAction `json:"action"`
Actor AuditLogActor `json:"actor"`
ID string `json:"id"`
Metadata map[string]interface{} `json:"metadata"`
NewValue string `json:"newValue"`
OldValue string `json:"oldValue"`
Owner AuditLogOwner `json:"owner"`
Resource AuditLogResource `json:"resource"`
When time.Time `json:"when"`
}
// AuditLogResponse is the response returned from the cloudflare v4 api
type AuditLogResponse struct {
Response Response
Result []AuditLog `json:"result"`
ResultInfo `json:"result_info"`
}
// AuditLogFilter is an object for filtering the audit log response from the api.
type AuditLogFilter struct {
ID string
ActorIP string
ActorEmail string
Direction string
ZoneName string
Since string
Before string
PerPage int
Page int
}
// String turns an audit log filter in to an HTTP Query Param
// list. It will not inclue empty members of the struct in the
// query parameters.
func (a AuditLogFilter) String() string {
params := "?"
if a.ID != "" {
params += "&id=" + a.ID
}
if a.ActorIP != "" {
params += "&actor.ip=" + a.ActorIP
}
if a.ActorEmail != "" {
params += "&actor.email=" + a.ActorEmail
}
if a.ZoneName != "" {
params += "&zone.name=" + a.ZoneName
}
if a.Direction != "" {
params += "&direction=" + a.Direction
}
if a.Since != "" {
params += "&since=" + a.Since
}
if a.Before != "" {
params += "&before=" + a.Before
}
if a.PerPage > 0 {
params += "&per_page=" + fmt.Sprintf("%d", a.PerPage)
}
if a.Page > 0 {
params += "&page=" + fmt.Sprintf("%d", a.Page)
}
return params
}
// GetOrganizationAuditLogs will return the audit logs of a specific
// organization, based on the ID passed in. The audit logs can be
// filtered based on any argument in the AuditLogFilter
//
// API Reference: https://api.cloudflare.com/#audit-logs-list-organization-audit-logs
func (api *API) GetOrganizationAuditLogs(organizationID string, a AuditLogFilter) (AuditLogResponse, error) {
uri := "/organizations/" + organizationID + "/audit_logs" + fmt.Sprintf("%s", a)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return AuditLogResponse{}, err
}
buf, err := base64.RawStdEncoding.DecodeString(string(res))
if err != nil {
return AuditLogResponse{}, err
}
return unmarshalReturn(buf)
}
// unmarshalReturn will unmarshal bytes and return an auditlogresponse
func unmarshalReturn(res []byte) (AuditLogResponse, error) {
var auditResponse AuditLogResponse
err := json.Unmarshal(res, &auditResponse)
if err != nil {
return auditResponse, err
}
return auditResponse, nil
}
// GetUserAuditLogs will return your user's audit logs. The audit logs can be
// filtered based on any argument in the AuditLogFilter
//
// API Reference: https://api.cloudflare.com/#audit-logs-list-user-audit-logs
func (api *API) GetUserAuditLogs(a AuditLogFilter) (AuditLogResponse, error) {
uri := "/user/audit_logs" + fmt.Sprintf("%s", a)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return AuditLogResponse{}, err
}
return unmarshalReturn(res)
}

View File

@@ -10,6 +10,8 @@ import (
"log"
"math"
"net/http"
"net/url"
"strconv"
"strings"
"time"
@@ -18,11 +20,14 @@ import (
)
const apiURL = "https://api.cloudflare.com/client/v4"
const (
// AuthKeyEmail specifies that we should authenticate with API key and email address
AuthKeyEmail = 1 << iota
// AuthUserService specifies that we should authenticate with a User-Service key
AuthUserService
// AuthToken specifies that we should authenticate with an API Token
AuthToken
)
// API holds the configuration for the current API client. A client should not
@@ -31,8 +36,10 @@ type API struct {
APIKey string
APIEmail string
APIUserServiceKey string
APIToken string
BaseURL string
organizationID string
OrganizationID string
UserAgent string
headers http.Header
httpClient *http.Client
authType int
@@ -41,20 +48,13 @@ type API struct {
logger Logger
}
// New creates a new Cloudflare v4 API client.
func New(key, email string, opts ...Option) (*API, error) {
if key == "" || email == "" {
return nil, errors.New(errEmptyCredentials)
}
// newClient provides shared logic for New and NewWithUserServiceKey
func newClient(opts ...Option) (*API, error) {
silentLogger := log.New(ioutil.Discard, "", log.LstdFlags)
api := &API{
APIKey: key,
APIEmail: email,
BaseURL: apiURL,
headers: make(http.Header),
authType: AuthKeyEmail,
rateLimiter: rate.NewLimiter(rate.Limit(4), 1), // 4rps equates to default api limit (1200 req/5 min)
retryPolicy: RetryPolicy{
MaxRetries: 3,
@@ -78,39 +78,120 @@ func New(key, email string, opts ...Option) (*API, error) {
return api, nil
}
// SetAuthType sets the authentication method (AuthyKeyEmail or AuthUserService).
// 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, err := newClient(opts...)
if err != nil {
return nil, err
}
api.APIKey = key
api.APIEmail = email
api.authType = AuthKeyEmail
return api, nil
}
// NewWithAPIToken creates a new Cloudflare v4 API client using API Tokens
func NewWithAPIToken(token string, opts ...Option) (*API, error) {
if token == "" {
return nil, errors.New(errEmptyAPIToken)
}
api, err := newClient(opts...)
if err != nil {
return nil, err
}
api.APIToken = token
api.authType = AuthToken
return api, nil
}
// NewWithUserServiceKey creates a new Cloudflare v4 API client using service key authentication.
func NewWithUserServiceKey(key string, opts ...Option) (*API, error) {
if key == "" {
return nil, errors.New(errEmptyCredentials)
}
api, err := newClient(opts...)
if err != nil {
return nil, err
}
api.APIUserServiceKey = key
api.authType = AuthUserService
return api, nil
}
// SetAuthType sets the authentication method (AuthKeyEmail, AuthToken, or AuthUserService).
func (api *API) SetAuthType(authType int) {
api.authType = authType
}
// ZoneIDByName retrieves a zone's ID from the name.
func (api *API) ZoneIDByName(zoneName string) (string, error) {
res, err := api.ListZones(zoneName)
res, err := api.ListZonesContext(context.TODO(), WithZoneFilter(zoneName))
if err != nil {
return "", errors.Wrap(err, "ListZones command failed")
return "", errors.Wrap(err, "ListZonesContext command failed")
}
for _, zone := range res {
if zone.Name == zoneName {
return zone.ID, nil
if len(res.Result) > 1 && api.OrganizationID == "" {
return "", errors.New("ambiguous zone name used without an account ID")
}
for _, zone := range res.Result {
if api.OrganizationID != "" {
if zone.Name == zoneName && api.OrganizationID == zone.Account.ID {
return zone.ID, nil
}
} else {
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.
// closing it before returning. params will be serialized to JSON.
func (api *API) makeRequest(method, uri string, params interface{}) ([]byte, error) {
return api.makeRequestWithAuthType(method, uri, params, api.authType)
return api.makeRequestWithAuthType(context.TODO(), method, uri, params, api.authType)
}
func (api *API) makeRequestWithAuthType(method, uri string, params interface{}, authType int) ([]byte, error) {
func (api *API) makeRequestContext(ctx context.Context, method, uri string, params interface{}) ([]byte, error) {
return api.makeRequestWithAuthType(ctx, method, uri, params, api.authType)
}
func (api *API) makeRequestWithHeaders(method, uri string, params interface{}, headers http.Header) ([]byte, error) {
return api.makeRequestWithAuthTypeAndHeaders(context.TODO(), method, uri, params, api.authType, headers)
}
func (api *API) makeRequestWithAuthType(ctx context.Context, method, uri string, params interface{}, authType int) ([]byte, error) {
return api.makeRequestWithAuthTypeAndHeaders(ctx, method, uri, params, authType, nil)
}
func (api *API) makeRequestWithAuthTypeAndHeaders(ctx context.Context, method, uri string, params interface{}, authType int, headers http.Header) ([]byte, error) {
// Replace nil with a JSON object if needed
var jsonBody []byte
var err error
if params != nil {
jsonBody, err = json.Marshal(params)
if err != nil {
return nil, errors.Wrap(err, "error marshalling params to JSON")
if paramBytes, ok := params.([]byte); ok {
jsonBody = paramBytes
} else {
jsonBody, err = json.Marshal(params)
if err != nil {
return nil, errors.Wrap(err, "error marshalling params to JSON")
}
}
} else {
jsonBody = nil
@@ -124,10 +205,9 @@ func (api *API) makeRequestWithAuthType(method, uri string, params interface{},
if jsonBody != nil {
reqBody = bytes.NewReader(jsonBody)
}
if i > 0 {
// expect the backoff introduced here on errored requests to dominate the effect of rate limiting
// dont need a random component here as the rate limiter should do something similar
// don't need a random component here as the rate limiter should do something similar
// nb time duration could truncate an arbitrary float. Since our inputs are all ints, we should be ok
sleepDuration := time.Duration(math.Pow(2, float64(i-1)) * float64(api.retryPolicy.MinRetryDelay))
@@ -137,12 +217,13 @@ func (api *API) makeRequestWithAuthType(method, uri string, params interface{},
// useful to do some simple logging here, maybe introduce levels later
api.logger.Printf("Sleeping %s before retry attempt number %d for request %s %s", sleepDuration.String(), i, method, uri)
time.Sleep(sleepDuration)
}
api.rateLimiter.Wait(context.TODO())
err = api.rateLimiter.Wait(context.TODO())
if err != nil {
return nil, errors.Wrap(err, "Error caused by request rate limiting")
}
resp, respErr = api.request(method, uri, reqBody, authType)
resp, respErr = api.request(ctx, method, uri, reqBody, authType, headers)
// retry if the server is rate limiting us or if it failed
// assumes server operations are rolled back on failure
@@ -187,6 +268,11 @@ func (api *API) makeRequestWithAuthType(method, uri string, params interface{},
resp.StatusCode == 523,
resp.StatusCode == 524:
return nil, errors.Errorf("HTTP status %d: service failure", resp.StatusCode)
// This isn't a great solution due to the way the `default` case is
// a catch all and that the `filters/validate-expr` returns a HTTP 400
// yet the clients need to use the HTTP body as a JSON string.
case resp.StatusCode == 400 && strings.HasSuffix(resp.Request.URL.Path, "/filters/validate-expr"):
return nil, errors.Errorf("%s", respBody)
default:
var s string
if respBody != nil {
@@ -201,14 +287,18 @@ func (api *API) makeRequestWithAuthType(method, uri string, params interface{},
// request makes a HTTP request to the given API endpoint, returning the raw
// *http.Response, or an error if one occurred. The caller is responsible for
// closing the response body.
func (api *API) request(method, uri string, reqBody io.Reader, authType int) (*http.Response, error) {
func (api *API) request(ctx context.Context, method, uri string, reqBody io.Reader, authType int, headers http.Header) (*http.Response, error) {
req, err := http.NewRequest(method, api.BaseURL+uri, reqBody)
if err != nil {
return nil, errors.Wrap(err, "HTTP request creation failed")
}
req.WithContext(ctx)
combinedHeaders := make(http.Header)
copyHeader(combinedHeaders, api.headers)
copyHeader(combinedHeaders, headers)
req.Header = combinedHeaders
// Apply any user-defined headers first.
req.Header = cloneHeader(api.headers)
if authType&AuthKeyEmail != 0 {
req.Header.Set("X-Auth-Key", api.APIKey)
req.Header.Set("X-Auth-Email", api.APIEmail)
@@ -216,6 +306,13 @@ func (api *API) request(method, uri string, reqBody io.Reader, authType int) (*h
if authType&AuthUserService != 0 {
req.Header.Set("X-Auth-User-Service-Key", api.APIUserServiceKey)
}
if authType&AuthToken != 0 {
req.Header.Set("Authorization", "Bearer "+api.APIToken)
}
if api.UserAgent != "" {
req.Header.Set("User-Agent", api.UserAgent)
}
if req.Header.Get("Content-Type") == "" {
req.Header.Set("Content-Type", "application/json")
@@ -235,20 +332,18 @@ func (api *API) request(method, uri string, reqBody io.Reader, authType int) (*h
// accountBase is the base URL for endpoints referring to the current user. It exists as a
// parameter because it is not consistent across APIs.
func (api *API) userBaseURL(accountBase string) string {
if api.organizationID != "" {
return "/organizations/" + api.organizationID
if api.OrganizationID != "" {
return "/accounts/" + api.OrganizationID
}
return accountBase
}
// cloneHeader returns a shallow copy of the header.
// copied from https://godoc.org/github.com/golang/gddo/httputil/header#Copy
func cloneHeader(header http.Header) http.Header {
h := make(http.Header)
for k, vs := range header {
h[k] = vs
// copyHeader copies all headers for `source` and sets them on `target`.
// based on https://godoc.org/github.com/golang/gddo/httputil/header#Copy
func copyHeader(target, source http.Header) {
for k, vs := range source {
target[k] = vs
}
return h
}
// ResponseInfo contains a code and message returned by the API as errors or
@@ -316,3 +411,24 @@ type RetryPolicy struct {
type Logger interface {
Printf(format string, v ...interface{})
}
// ReqOption is a functional option for configuring API requests
type ReqOption func(opt *reqOption)
type reqOption struct {
params url.Values
}
// WithZoneFilter applies a filter based on zone name.
func WithZoneFilter(zone string) ReqOption {
return func(opt *reqOption) {
opt.params.Set("name", zone)
}
}
// WithPagination configures the pagination for a response.
func WithPagination(opts PaginationOptions) ReqOption {
return func(opt *reqOption) {
opt.params.Set("page", strconv.Itoa(opts.Page))
opt.params.Set("per_page", strconv.Itoa(opts.PerPage))
}
}

View File

@@ -1,29 +0,0 @@
package cloudflare
import "time"
// CustomPage represents a custom page configuration.
type CustomPage struct {
CreatedOn string `json:"created_on"`
ModifiedOn time.Time `json:"modified_on"`
URL string `json:"url"`
State string `json:"state"`
RequiredTokens []string `json:"required_tokens"`
PreviewTarget string `json:"preview_target"`
Description string `json:"description"`
}
// CustomPageResponse represents the response from the custom pages endpoint.
type CustomPageResponse struct {
Response
Result []CustomPage `json:"result"`
}
// https://api.cloudflare.com/#custom-pages-for-a-zone-available-custom-pages
// GET /zones/:zone_identifier/custom_pages
// https://api.cloudflare.com/#custom-pages-for-a-zone-custom-page-details
// GET /zones/:zone_identifier/custom_pages/:identifier
// https://api.cloudflare.com/#custom-pages-for-a-zone-update-custom-page-url
// PUT /zones/:zone_identifier/custom_pages/:identifier

View File

@@ -8,13 +8,22 @@ import (
"github.com/pkg/errors"
)
// CustomHostnameSSLSettings represents the SSL settings for a custom hostname.
type CustomHostnameSSLSettings struct {
HTTP2 string `json:"http2,omitempty"`
TLS13 string `json:"tls_1_3,omitempty"`
MinTLSVersion string `json:"min_tls_version,omitempty"`
Ciphers []string `json:"ciphers,omitempty"`
}
// CustomHostnameSSL represents the SSL section in a given custom hostname.
type CustomHostnameSSL struct {
Status string `json:"status,omitempty"`
Method string `json:"method,omitempty"`
Type string `json:"type,omitempty"`
CnameTarget string `json:"cname_target,omitempty"`
CnameName string `json:"cname_name,omitempty"`
Status string `json:"status,omitempty"`
Method string `json:"method,omitempty"`
Type string `json:"type,omitempty"`
CnameTarget string `json:"cname_target,omitempty"`
CnameName string `json:"cname,omitempty"`
Settings CustomHostnameSSLSettings `json:"settings,omitempty"`
}
// CustomMetadata defines custom metadata for the hostname. This requires logic to be implemented by Cloudflare to act on the data provided.
@@ -28,7 +37,7 @@ type CustomHostname struct {
CustomMetadata CustomMetadata `json:"custom_metadata,omitempty"`
}
// CustomHostNameResponse represents a response from the Custom Hostnames endpoints.
// CustomHostnameResponse represents a response from the Custom Hostnames endpoints.
type CustomHostnameResponse struct {
Result CustomHostname `json:"result"`
Response
@@ -41,14 +50,16 @@ type CustomHostnameListResponse struct {
ResultInfo `json:"result_info"`
}
// Modify SSL configuration for the given custom hostname in the given zone.
// UpdateCustomHostnameSSL modifies SSL configuration for the given custom
// hostname in the given zone.
//
// API reference: https://api.cloudflare.com/#custom-hostname-for-a-zone-update-custom-hostname-configuration
func (api *API) UpdateCustomHostnameSSL(zoneID string, customHostnameID string, ssl CustomHostnameSSL) (CustomHostname, error) {
return CustomHostname{}, errors.New("Not implemented")
}
// Delete a custom hostname (and any issued SSL certificates)
// DeleteCustomHostname deletes a custom hostname (and any issued SSL
// certificates).
//
// API reference: https://api.cloudflare.com/#custom-hostname-for-a-zone-delete-a-custom-hostname-and-any-issued-ssl-certificates-
func (api *API) DeleteCustomHostname(zoneID string, customHostnameID string) error {

View File

@@ -0,0 +1,176 @@
package cloudflare
import (
"encoding/json"
"fmt"
"time"
"github.com/pkg/errors"
)
// CustomPage represents a custom page configuration.
type CustomPage struct {
CreatedOn time.Time `json:"created_on"`
ModifiedOn time.Time `json:"modified_on"`
URL interface{} `json:"url"`
State string `json:"state"`
RequiredTokens []string `json:"required_tokens"`
PreviewTarget string `json:"preview_target"`
Description string `json:"description"`
ID string `json:"id"`
}
// CustomPageResponse represents the response from the custom pages endpoint.
type CustomPageResponse struct {
Response
Result []CustomPage `json:"result"`
}
// CustomPageDetailResponse represents the response from the custom page endpoint.
type CustomPageDetailResponse struct {
Response
Result CustomPage `json:"result"`
}
// CustomPageOptions is used to determine whether or not the operation
// should take place on an account or zone level based on which is
// provided to the function.
//
// A non-empty value denotes desired use.
type CustomPageOptions struct {
AccountID string
ZoneID string
}
// CustomPageParameters is used to update a particular custom page with
// the values provided.
type CustomPageParameters struct {
URL interface{} `json:"url"`
State string `json:"state"`
}
// CustomPages lists custom pages for a zone or account.
//
// Zone API reference: https://api.cloudflare.com/#custom-pages-for-a-zone-list-available-custom-pages
// Account API reference: https://api.cloudflare.com/#custom-pages-account--list-custom-pages
func (api *API) CustomPages(options *CustomPageOptions) ([]CustomPage, error) {
var (
pageType, identifier string
)
if options.AccountID == "" && options.ZoneID == "" {
return nil, errors.New("either account ID or zone ID must be provided")
}
if options.AccountID != "" && options.ZoneID != "" {
return nil, errors.New("account ID and zone ID are mutually exclusive")
}
// Should the account ID be defined, treat this as an account level operation.
if options.AccountID != "" {
pageType = "accounts"
identifier = options.AccountID
} else {
pageType = "zones"
identifier = options.ZoneID
}
uri := fmt.Sprintf("/%s/%s/custom_pages", pageType, identifier)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return nil, errors.Wrap(err, errMakeRequestError)
}
var customPageResponse CustomPageResponse
err = json.Unmarshal(res, &customPageResponse)
if err != nil {
return nil, errors.Wrap(err, errUnmarshalError)
}
return customPageResponse.Result, nil
}
// CustomPage lists a single custom page based on the ID.
//
// Zone API reference: https://api.cloudflare.com/#custom-pages-for-a-zone-custom-page-details
// Account API reference: https://api.cloudflare.com/#custom-pages-account--custom-page-details
func (api *API) CustomPage(options *CustomPageOptions, customPageID string) (CustomPage, error) {
var (
pageType, identifier string
)
if options.AccountID == "" && options.ZoneID == "" {
return CustomPage{}, errors.New("either account ID or zone ID must be provided")
}
if options.AccountID != "" && options.ZoneID != "" {
return CustomPage{}, errors.New("account ID and zone ID are mutually exclusive")
}
// Should the account ID be defined, treat this as an account level operation.
if options.AccountID != "" {
pageType = "accounts"
identifier = options.AccountID
} else {
pageType = "zones"
identifier = options.ZoneID
}
uri := fmt.Sprintf("/%s/%s/custom_pages/%s", pageType, identifier, customPageID)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return CustomPage{}, errors.Wrap(err, errMakeRequestError)
}
var customPageResponse CustomPageDetailResponse
err = json.Unmarshal(res, &customPageResponse)
if err != nil {
return CustomPage{}, errors.Wrap(err, errUnmarshalError)
}
return customPageResponse.Result, nil
}
// UpdateCustomPage updates a single custom page setting.
//
// Zone API reference: https://api.cloudflare.com/#custom-pages-for-a-zone-update-custom-page-url
// Account API reference: https://api.cloudflare.com/#custom-pages-account--update-custom-page
func (api *API) UpdateCustomPage(options *CustomPageOptions, customPageID string, pageParameters CustomPageParameters) (CustomPage, error) {
var (
pageType, identifier string
)
if options.AccountID == "" && options.ZoneID == "" {
return CustomPage{}, errors.New("either account ID or zone ID must be provided")
}
if options.AccountID != "" && options.ZoneID != "" {
return CustomPage{}, errors.New("account ID and zone ID are mutually exclusive")
}
// Should the account ID be defined, treat this as an account level operation.
if options.AccountID != "" {
pageType = "accounts"
identifier = options.AccountID
} else {
pageType = "zones"
identifier = options.ZoneID
}
uri := fmt.Sprintf("/%s/%s/custom_pages/%s", pageType, identifier, customPageID)
res, err := api.makeRequest("PUT", uri, pageParameters)
if err != nil {
return CustomPage{}, errors.Wrap(err, errMakeRequestError)
}
var customPageResponse CustomPageDetailResponse
err = json.Unmarshal(res, &customPageResponse)
if err != nil {
return CustomPage{}, errors.Wrap(err, errUnmarshalError)
}
return customPageResponse.Result, nil
}

View File

@@ -16,7 +16,7 @@ type DNSRecord struct {
Name string `json:"name,omitempty"`
Content string `json:"content,omitempty"`
Proxiable bool `json:"proxiable,omitempty"`
Proxied bool `json:"proxied,omitempty"`
Proxied bool `json:"proxied"`
TTL int `json:"ttl,omitempty"`
Locked bool `json:"locked,omitempty"`
ZoneID string `json:"zone_id,omitempty"`
@@ -25,7 +25,7 @@ type DNSRecord struct {
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"`
Priority int `json:"priority"`
}
// DNSRecordResponse represents the response from the DNS endpoint.
@@ -143,7 +143,7 @@ func (api *API) UpdateDNSRecord(zoneID, recordID string, rr DNSRecord) error {
}
rr.Type = rec.Type
uri := "/zones/" + zoneID + "/dns_records/" + recordID
res, err := api.makeRequest("PUT", uri, rr)
res, err := api.makeRequest("PATCH", uri, rr)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}

40
vendor/github.com/cloudflare/cloudflare-go/duration.go generated vendored Normal file
View File

@@ -0,0 +1,40 @@
package cloudflare
import (
"encoding/json"
"time"
)
// Duration implements json.Marshaler and json.Unmarshaler for time.Duration
// using the fmt.Stringer interface of time.Duration and time.ParseDuration.
type Duration struct {
time.Duration
}
// MarshalJSON encodes a Duration as a JSON string formatted using String.
func (d Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(d.Duration.String())
}
// UnmarshalJSON decodes a Duration from a JSON string parsed using time.ParseDuration.
func (d *Duration) UnmarshalJSON(buf []byte) error {
var str string
err := json.Unmarshal(buf, &str)
if err != nil {
return err
}
dur, err := time.ParseDuration(str)
if err != nil {
return err
}
d.Duration = dur
return nil
}
var (
_ = json.Marshaler((*Duration)(nil))
_ = json.Unmarshaler((*Duration)(nil))
)

View File

@@ -3,9 +3,11 @@ package cloudflare
// Error messages
const (
errEmptyCredentials = "invalid credentials: key & email must not be empty"
errEmptyAPIToken = "invalid credentials: API Token must not be empty"
errMakeRequestError = "error from makeRequest"
errUnmarshalError = "error unmarshalling the JSON response"
errRequestNotSuccessful = "error reported by API"
errMissingAccountID = "account ID is empty and must be provided"
)
var _ Error = &UserError{}

241
vendor/github.com/cloudflare/cloudflare-go/filter.go generated vendored Normal file
View File

@@ -0,0 +1,241 @@
package cloudflare
import (
"encoding/json"
"fmt"
"net/url"
"strconv"
"strings"
"github.com/pkg/errors"
)
// Filter holds the structure of the filter type.
type Filter struct {
ID string `json:"id,omitempty"`
Expression string `json:"expression"`
Paused bool `json:"paused"`
Description string `json:"description"`
// Property is mentioned in documentation however isn't populated in
// any of the API requests. For now, let's just omit it unless it's
// provided.
Ref string `json:"ref,omitempty"`
}
// FiltersDetailResponse is the API response that is returned
// for requesting all filters on a zone.
type FiltersDetailResponse struct {
Result []Filter `json:"result"`
ResultInfo `json:"result_info"`
Response
}
// FilterDetailResponse is the API response that is returned
// for requesting a single filter on a zone.
type FilterDetailResponse struct {
Result Filter `json:"result"`
ResultInfo `json:"result_info"`
Response
}
// FilterValidateExpression represents the JSON payload for checking
// an expression.
type FilterValidateExpression struct {
Expression string `json:"expression"`
}
// FilterValidateExpressionResponse represents the API response for
// checking the expression. It conforms to the JSON API approach however
// we don't need all of the fields exposed.
type FilterValidateExpressionResponse struct {
Success bool `json:"success"`
Errors []FilterValidationExpressionMessage `json:"errors"`
}
// FilterValidationExpressionMessage represents the API error message.
type FilterValidationExpressionMessage struct {
Message string `json:"message"`
}
// Filter returns a single filter in a zone based on the filter ID.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-filters/get/#get-by-filter-id
func (api *API) Filter(zoneID, filterID string) (Filter, error) {
uri := fmt.Sprintf("/zones/%s/filters/%s", zoneID, filterID)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return Filter{}, errors.Wrap(err, errMakeRequestError)
}
var filterResponse FilterDetailResponse
err = json.Unmarshal(res, &filterResponse)
if err != nil {
return Filter{}, errors.Wrap(err, errUnmarshalError)
}
return filterResponse.Result, nil
}
// Filters returns all filters for a zone.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-filters/get/#get-all-filters
func (api *API) Filters(zoneID string, pageOpts PaginationOptions) ([]Filter, error) {
uri := "/zones/" + zoneID + "/filters"
v := url.Values{}
if pageOpts.PerPage > 0 {
v.Set("per_page", strconv.Itoa(pageOpts.PerPage))
}
if pageOpts.Page > 0 {
v.Set("page", strconv.Itoa(pageOpts.Page))
}
if len(v) > 0 {
uri = uri + "?" + v.Encode()
}
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return []Filter{}, errors.Wrap(err, errMakeRequestError)
}
var filtersResponse FiltersDetailResponse
err = json.Unmarshal(res, &filtersResponse)
if err != nil {
return []Filter{}, errors.Wrap(err, errUnmarshalError)
}
return filtersResponse.Result, nil
}
// CreateFilters creates new filters.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-filters/post/
func (api *API) CreateFilters(zoneID string, filters []Filter) ([]Filter, error) {
uri := "/zones/" + zoneID + "/filters"
res, err := api.makeRequest("POST", uri, filters)
if err != nil {
return []Filter{}, errors.Wrap(err, errMakeRequestError)
}
var filtersResponse FiltersDetailResponse
err = json.Unmarshal(res, &filtersResponse)
if err != nil {
return []Filter{}, errors.Wrap(err, errUnmarshalError)
}
return filtersResponse.Result, nil
}
// UpdateFilter updates a single filter.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-filters/put/#update-a-single-filter
func (api *API) UpdateFilter(zoneID string, filter Filter) (Filter, error) {
if filter.ID == "" {
return Filter{}, errors.Errorf("filter ID cannot be empty")
}
uri := fmt.Sprintf("/zones/%s/filters/%s", zoneID, filter.ID)
res, err := api.makeRequest("PUT", uri, filter)
if err != nil {
return Filter{}, errors.Wrap(err, errMakeRequestError)
}
var filterResponse FilterDetailResponse
err = json.Unmarshal(res, &filterResponse)
if err != nil {
return Filter{}, errors.Wrap(err, errUnmarshalError)
}
return filterResponse.Result, nil
}
// UpdateFilters updates many filters at once.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-filters/put/#update-multiple-filters
func (api *API) UpdateFilters(zoneID string, filters []Filter) ([]Filter, error) {
for _, filter := range filters {
if filter.ID == "" {
return []Filter{}, errors.Errorf("filter ID cannot be empty")
}
}
uri := "/zones/" + zoneID + "/filters"
res, err := api.makeRequest("PUT", uri, filters)
if err != nil {
return []Filter{}, errors.Wrap(err, errMakeRequestError)
}
var filtersResponse FiltersDetailResponse
err = json.Unmarshal(res, &filtersResponse)
if err != nil {
return []Filter{}, errors.Wrap(err, errUnmarshalError)
}
return filtersResponse.Result, nil
}
// DeleteFilter deletes a single filter.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-filters/delete/#delete-a-single-filter
func (api *API) DeleteFilter(zoneID, filterID string) error {
if filterID == "" {
return errors.Errorf("filter ID cannot be empty")
}
uri := fmt.Sprintf("/zones/%s/filters/%s", zoneID, filterID)
_, err := api.makeRequest("DELETE", uri, nil)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
return nil
}
// DeleteFilters deletes multiple filters.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-filters/delete/#delete-multiple-filters
func (api *API) DeleteFilters(zoneID string, filterIDs []string) error {
ids := strings.Join(filterIDs, ",")
uri := fmt.Sprintf("/zones/%s/filters?id=%s", zoneID, ids)
_, err := api.makeRequest("DELETE", uri, nil)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
return nil
}
// ValidateFilterExpression checks correctness of a filter expression.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-filters/validation/
func (api *API) ValidateFilterExpression(expression string) error {
uri := fmt.Sprintf("/filters/validate-expr")
expressionPayload := FilterValidateExpression{Expression: expression}
_, err := api.makeRequest("POST", uri, expressionPayload)
if err != nil {
var filterValidationResponse FilterValidateExpressionResponse
jsonErr := json.Unmarshal([]byte(err.Error()), &filterValidationResponse)
if jsonErr != nil {
return errors.Wrap(jsonErr, errUnmarshalError)
}
if filterValidationResponse.Success != true {
// Unsure why but the API returns `errors` as an array but it only
// ever shows the issue with one problem at a time ¯\_(ツ)_/¯
return errors.Errorf(filterValidationResponse.Errors[0].Message)
}
}
return nil
}

View File

@@ -68,6 +68,13 @@ func (api *API) CreateUserAccessRule(accessRule AccessRule) (*AccessRuleResponse
return api.createAccessRule("/user", accessRule)
}
// UserAccessRule returns the details of a user's account access rule.
//
// API reference: https://api.cloudflare.com/#user-level-firewall-access-rule-list-access-rules
func (api *API) UserAccessRule(accessRuleID string) (*AccessRuleResponse, error) {
return api.retrieveAccessRule("/user", accessRuleID)
}
// UpdateUserAccessRule updates a single access rule for the logged-in user &
// given access rule identifier.
//
@@ -102,6 +109,13 @@ func (api *API) CreateZoneAccessRule(zoneID string, accessRule AccessRule) (*Acc
return api.createAccessRule("/zones/"+zoneID, accessRule)
}
// ZoneAccessRule returns the details of a zone's access rule.
//
// API reference: https://api.cloudflare.com/#firewall-access-rule-for-a-zone-list-access-rules
func (api *API) ZoneAccessRule(zoneID string, accessRuleID string) (*AccessRuleResponse, error) {
return api.retrieveAccessRule("/zones/"+zoneID, accessRuleID)
}
// UpdateZoneAccessRule updates a single access rule for the given zone &
// access rule identifiers.
//
@@ -125,7 +139,7 @@ func (api *API) DeleteZoneAccessRule(zoneID, accessRuleID string) (*AccessRuleRe
//
// API reference: https://api.cloudflare.com/#organization-level-firewall-access-rule-list-access-rules
func (api *API) ListOrganizationAccessRules(organizationID string, accessRule AccessRule, page int) (*AccessRuleListResponse, error) {
return api.listAccessRules("/organizations/"+organizationID, accessRule, page)
return api.listAccessRules("/accounts/"+organizationID, accessRule, page)
}
// CreateOrganizationAccessRule creates a firewall access rule for the given
@@ -133,7 +147,14 @@ func (api *API) ListOrganizationAccessRules(organizationID string, accessRule Ac
//
// API reference: https://api.cloudflare.com/#organization-level-firewall-access-rule-create-access-rule
func (api *API) CreateOrganizationAccessRule(organizationID string, accessRule AccessRule) (*AccessRuleResponse, error) {
return api.createAccessRule("/organizations/"+organizationID, accessRule)
return api.createAccessRule("/accounts/"+organizationID, accessRule)
}
// OrganizationAccessRule returns the details of an organization's access rule.
//
// API reference: https://api.cloudflare.com/#account-level-firewall-access-rule-access-rule-details
func (api *API) OrganizationAccessRule(organizationID string, accessRuleID string) (*AccessRuleResponse, error) {
return api.retrieveAccessRule("/accounts/"+organizationID, accessRuleID)
}
// UpdateOrganizationAccessRule updates a single access rule for the given
@@ -141,7 +162,7 @@ func (api *API) CreateOrganizationAccessRule(organizationID string, accessRule A
//
// API reference: https://api.cloudflare.com/#organization-level-firewall-access-rule-update-access-rule
func (api *API) UpdateOrganizationAccessRule(organizationID, accessRuleID string, accessRule AccessRule) (*AccessRuleResponse, error) {
return api.updateAccessRule("/organizations/"+organizationID, accessRuleID, accessRule)
return api.updateAccessRule("/accounts/"+organizationID, accessRuleID, accessRule)
}
// DeleteOrganizationAccessRule deletes a single access rule for the given
@@ -149,7 +170,7 @@ func (api *API) UpdateOrganizationAccessRule(organizationID, accessRuleID string
//
// API reference: https://api.cloudflare.com/#organization-level-firewall-access-rule-delete-access-rule
func (api *API) DeleteOrganizationAccessRule(organizationID, accessRuleID string) (*AccessRuleResponse, error) {
return api.deleteAccessRule("/organizations/"+organizationID, accessRuleID)
return api.deleteAccessRule("/accounts/"+organizationID, accessRuleID)
}
func (api *API) listAccessRules(prefix string, accessRule AccessRule, page int) (*AccessRuleListResponse, error) {
@@ -209,6 +230,24 @@ func (api *API) createAccessRule(prefix string, accessRule AccessRule) (*AccessR
return response, nil
}
func (api *API) retrieveAccessRule(prefix, accessRuleID string) (*AccessRuleResponse, error) {
uri := prefix + "/firewall/access_rules/rules/" + accessRuleID
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return nil, errors.Wrap(err, errMakeRequestError)
}
response := &AccessRuleResponse{}
err = json.Unmarshal(res, &response)
if err != nil {
return nil, errors.Wrap(err, errUnmarshalError)
}
return response, nil
}
func (api *API) updateAccessRule(prefix, accessRuleID string, accessRule AccessRule) (*AccessRuleResponse, error) {
uri := prefix + "/firewall/access_rules/rules/" + accessRuleID
res, err := api.makeRequest("PATCH", uri, accessRule)

View File

@@ -0,0 +1,196 @@
package cloudflare
import (
"encoding/json"
"fmt"
"net/url"
"strconv"
"strings"
"time"
"github.com/pkg/errors"
)
// FirewallRule is the struct of the firewall rule.
type FirewallRule struct {
ID string `json:"id,omitempty"`
Paused bool `json:"paused"`
Description string `json:"description"`
Action string `json:"action"`
Priority interface{} `json:"priority"`
Filter Filter `json:"filter"`
CreatedOn time.Time `json:"created_on,omitempty"`
ModifiedOn time.Time `json:"modified_on,omitempty"`
}
// FirewallRulesDetailResponse is the API response for the firewall
// rules.
type FirewallRulesDetailResponse struct {
Result []FirewallRule `json:"result"`
ResultInfo `json:"result_info"`
Response
}
// FirewallRuleResponse is the API response that is returned
// for requesting a single firewall rule on a zone.
type FirewallRuleResponse struct {
Result FirewallRule `json:"result"`
ResultInfo `json:"result_info"`
Response
}
// FirewallRules returns all firewall rules.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/get/#get-all-rules
func (api *API) FirewallRules(zoneID string, pageOpts PaginationOptions) ([]FirewallRule, error) {
uri := fmt.Sprintf("/zones/%s/firewall/rules", zoneID)
v := url.Values{}
if pageOpts.PerPage > 0 {
v.Set("per_page", strconv.Itoa(pageOpts.PerPage))
}
if pageOpts.Page > 0 {
v.Set("page", strconv.Itoa(pageOpts.Page))
}
if len(v) > 0 {
uri = uri + "?" + v.Encode()
}
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return []FirewallRule{}, errors.Wrap(err, errMakeRequestError)
}
var firewallDetailResponse FirewallRulesDetailResponse
err = json.Unmarshal(res, &firewallDetailResponse)
if err != nil {
return []FirewallRule{}, errors.Wrap(err, errUnmarshalError)
}
return firewallDetailResponse.Result, nil
}
// FirewallRule returns a single firewall rule based on the ID.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/get/#get-by-rule-id
func (api *API) FirewallRule(zoneID, firewallRuleID string) (FirewallRule, error) {
uri := fmt.Sprintf("/zones/%s/firewall/rules/%s", zoneID, firewallRuleID)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return FirewallRule{}, errors.Wrap(err, errMakeRequestError)
}
var firewallRuleResponse FirewallRuleResponse
err = json.Unmarshal(res, &firewallRuleResponse)
if err != nil {
return FirewallRule{}, errors.Wrap(err, errUnmarshalError)
}
return firewallRuleResponse.Result, nil
}
// CreateFirewallRules creates new firewall rules.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/post/
func (api *API) CreateFirewallRules(zoneID string, firewallRules []FirewallRule) ([]FirewallRule, error) {
uri := fmt.Sprintf("/zones/%s/firewall/rules", zoneID)
res, err := api.makeRequest("POST", uri, firewallRules)
if err != nil {
return []FirewallRule{}, errors.Wrap(err, errMakeRequestError)
}
var firewallRulesDetailResponse FirewallRulesDetailResponse
err = json.Unmarshal(res, &firewallRulesDetailResponse)
if err != nil {
return []FirewallRule{}, errors.Wrap(err, errUnmarshalError)
}
return firewallRulesDetailResponse.Result, nil
}
// UpdateFirewallRule updates a single firewall rule.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/put/#update-a-single-rule
func (api *API) UpdateFirewallRule(zoneID string, firewallRule FirewallRule) (FirewallRule, error) {
if firewallRule.ID == "" {
return FirewallRule{}, errors.Errorf("firewall rule ID cannot be empty")
}
uri := fmt.Sprintf("/zones/%s/firewall/rules/%s", zoneID, firewallRule.ID)
res, err := api.makeRequest("PUT", uri, firewallRule)
if err != nil {
return FirewallRule{}, errors.Wrap(err, errMakeRequestError)
}
var firewallRuleResponse FirewallRuleResponse
err = json.Unmarshal(res, &firewallRuleResponse)
if err != nil {
return FirewallRule{}, errors.Wrap(err, errUnmarshalError)
}
return firewallRuleResponse.Result, nil
}
// UpdateFirewallRules updates a single firewall rule.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/put/#update-multiple-rules
func (api *API) UpdateFirewallRules(zoneID string, firewallRules []FirewallRule) ([]FirewallRule, error) {
for _, firewallRule := range firewallRules {
if firewallRule.ID == "" {
return []FirewallRule{}, errors.Errorf("firewall ID cannot be empty")
}
}
uri := fmt.Sprintf("/zones/%s/firewall/rules", zoneID)
res, err := api.makeRequest("PUT", uri, firewallRules)
if err != nil {
return []FirewallRule{}, errors.Wrap(err, errMakeRequestError)
}
var firewallRulesDetailResponse FirewallRulesDetailResponse
err = json.Unmarshal(res, &firewallRulesDetailResponse)
if err != nil {
return []FirewallRule{}, errors.Wrap(err, errUnmarshalError)
}
return firewallRulesDetailResponse.Result, nil
}
// DeleteFirewallRule updates a single firewall rule.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/delete/#delete-a-single-rule
func (api *API) DeleteFirewallRule(zoneID, firewallRuleID string) error {
if firewallRuleID == "" {
return errors.Errorf("firewall rule ID cannot be empty")
}
uri := fmt.Sprintf("/zones/%s/firewall/rules/%s", zoneID, firewallRuleID)
_, err := api.makeRequest("DELETE", uri, nil)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
return nil
}
// DeleteFirewallRules updates a single firewall rule.
//
// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/delete/#delete-multiple-rules
func (api *API) DeleteFirewallRules(zoneID string, firewallRuleIDs []string) error {
ids := strings.Join(firewallRuleIDs, ",")
uri := fmt.Sprintf("/zones/%s/firewall/rules?id=%s", zoneID, ids)
_, err := api.makeRequest("DELETE", uri, nil)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
return nil
}

View File

@@ -25,6 +25,7 @@ type LoadBalancerPool struct {
CheckRegions []string `json:"check_regions"`
}
// LoadBalancerOrigin represents a Load Balancer origin's properties.
type LoadBalancerOrigin struct {
Name string `json:"name"`
Address string `json:"address"`
@@ -34,35 +35,69 @@ type LoadBalancerOrigin struct {
// LoadBalancerMonitor represents a load balancer monitor's properties.
type LoadBalancerMonitor struct {
ID string `json:"id,omitempty"`
CreatedOn *time.Time `json:"created_on,omitempty"`
ModifiedOn *time.Time `json:"modified_on,omitempty"`
Type string `json:"type"`
Description string `json:"description"`
Method string `json:"method"`
Path string `json:"path"`
Header map[string][]string `json:"header"`
Timeout int `json:"timeout"`
Retries int `json:"retries"`
Interval int `json:"interval"`
ExpectedBody string `json:"expected_body"`
ExpectedCodes string `json:"expected_codes"`
ID string `json:"id,omitempty"`
CreatedOn *time.Time `json:"created_on,omitempty"`
ModifiedOn *time.Time `json:"modified_on,omitempty"`
Type string `json:"type"`
Description string `json:"description"`
Method string `json:"method"`
Path string `json:"path"`
Header map[string][]string `json:"header"`
Timeout int `json:"timeout"`
Retries int `json:"retries"`
Interval int `json:"interval"`
Port uint16 `json:"port,omitempty"`
ExpectedBody string `json:"expected_body"`
ExpectedCodes string `json:"expected_codes"`
FollowRedirects bool `json:"follow_redirects"`
AllowInsecure bool `json:"allow_insecure"`
ProbeZone string `json:"probe_zone"`
}
// LoadBalancer represents a load balancer's properties.
type LoadBalancer struct {
ID string `json:"id,omitempty"`
CreatedOn *time.Time `json:"created_on,omitempty"`
ModifiedOn *time.Time `json:"modified_on,omitempty"`
Description string `json:"description"`
Name string `json:"name"`
TTL int `json:"ttl,omitempty"`
FallbackPool string `json:"fallback_pool"`
DefaultPools []string `json:"default_pools"`
RegionPools map[string][]string `json:"region_pools"`
PopPools map[string][]string `json:"pop_pools"`
Proxied bool `json:"proxied"`
Persistence string `json:"session_affinity,omitempty"`
ID string `json:"id,omitempty"`
CreatedOn *time.Time `json:"created_on,omitempty"`
ModifiedOn *time.Time `json:"modified_on,omitempty"`
Description string `json:"description"`
Name string `json:"name"`
TTL int `json:"ttl,omitempty"`
FallbackPool string `json:"fallback_pool"`
DefaultPools []string `json:"default_pools"`
RegionPools map[string][]string `json:"region_pools"`
PopPools map[string][]string `json:"pop_pools"`
Proxied bool `json:"proxied"`
Enabled *bool `json:"enabled,omitempty"`
Persistence string `json:"session_affinity,omitempty"`
PersistenceTTL int `json:"session_affinity_ttl,omitempty"`
// SteeringPolicy controls pool selection logic.
// "off" select pools in DefaultPools order
// "geo" select pools based on RegionPools/PopPools
// "dynamic_latency" select pools based on RTT (requires health checks)
// "random" selects pools in a random order
// "" maps to "geo" if RegionPools or PopPools have entries otherwise "off"
SteeringPolicy string `json:"steering_policy,omitempty"`
}
// LoadBalancerOriginHealth represents the health of the origin.
type LoadBalancerOriginHealth struct {
Healthy bool `json:"healthy,omitempty"`
RTT Duration `json:"rtt,omitempty"`
FailureReason string `json:"failure_reason,omitempty"`
ResponseCode int `json:"response_code,omitempty"`
}
// LoadBalancerPoolPopHealth represents the health of the pool for given PoP.
type LoadBalancerPoolPopHealth struct {
Healthy bool `json:"healthy,omitempty"`
Origins []map[string]LoadBalancerOriginHealth `json:"origins,omitempty"`
}
// LoadBalancerPoolHealth represents the healthchecks from different PoPs for a pool.
type LoadBalancerPoolHealth struct {
ID string `json:"pool_id,omitempty"`
PopHealth map[string]LoadBalancerPoolPopHealth `json:"pop_health,omitempty"`
}
// loadBalancerPoolResponse represents the response from the load balancer pool endpoints.
@@ -104,6 +139,12 @@ type loadBalancerListResponse struct {
ResultInfo ResultInfo `json:"result_info"`
}
// loadBalancerPoolHealthResponse represents the response from the Pool Health Details endpoint.
type loadBalancerPoolHealthResponse struct {
Response
Result LoadBalancerPoolHealth `json:"result"`
}
// CreateLoadBalancerPool creates a new load balancer pool.
//
// API reference: https://api.cloudflare.com/#load-balancer-pools-create-a-pool
@@ -328,3 +369,19 @@ func (api *API) ModifyLoadBalancer(zoneID string, lb LoadBalancer) (LoadBalancer
}
return r.Result, nil
}
// PoolHealthDetails fetches the latest healtcheck details for a single pool.
//
// API reference: https://api.cloudflare.com/#load-balancer-pools-pool-health-details
func (api *API) PoolHealthDetails(poolID string) (LoadBalancerPoolHealth, error) {
uri := api.userBaseURL("/user") + "/load_balancers/pools/" + poolID + "/health"
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return LoadBalancerPoolHealth{}, errors.Wrap(err, errMakeRequestError)
}
var r loadBalancerPoolHealthResponse
if err := json.Unmarshal(res, &r); err != nil {
return LoadBalancerPoolHealth{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}

View File

@@ -16,6 +16,7 @@ type ZoneLockdown struct {
URLs []string `json:"urls"`
Configurations []ZoneLockdownConfig `json:"configurations"`
Paused bool `json:"paused"`
Priority int `json:"priority,omitempty"`
}
// ZoneLockdownConfig represents a Zone Lockdown config, which comprises
@@ -65,7 +66,7 @@ func (api *API) CreateZoneLockdown(zoneID string, ld ZoneLockdown) (*ZoneLockdow
//
// API reference: https://api.cloudflare.com/#zone-ZoneLockdown-update-ZoneLockdown-rule
func (api *API) UpdateZoneLockdown(zoneID string, id string, ld ZoneLockdown) (*ZoneLockdownResponse, error) {
uri := "/zones/" + zoneID + "/firewall/lockdowns"
uri := "/zones/" + zoneID + "/firewall/lockdowns/" + id
res, err := api.makeRequest("PUT", uri, ld)
if err != nil {
return nil, errors.Wrap(err, errMakeRequestError)

224
vendor/github.com/cloudflare/cloudflare-go/logpush.go generated vendored Normal file
View File

@@ -0,0 +1,224 @@
package cloudflare
import (
"encoding/json"
"strconv"
"time"
"github.com/pkg/errors"
)
// LogpushJob describes a Logpush job.
type LogpushJob struct {
ID int `json:"id,omitempty"`
Enabled bool `json:"enabled"`
Name string `json:"name"`
LogpullOptions string `json:"logpull_options"`
DestinationConf string `json:"destination_conf"`
OwnershipChallenge string `json:"ownership_challenge,omitempty"`
LastComplete *time.Time `json:"last_complete,omitempty"`
LastError *time.Time `json:"last_error,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
}
// LogpushJobsResponse is the API response, containing an array of Logpush Jobs.
type LogpushJobsResponse struct {
Response
Result []LogpushJob `json:"result"`
}
// LogpushJobDetailsResponse is the API response, containing a single Logpush Job.
type LogpushJobDetailsResponse struct {
Response
Result LogpushJob `json:"result"`
}
// LogpushGetOwnershipChallenge describes a ownership validation.
type LogpushGetOwnershipChallenge struct {
Filename string `json:"filename"`
Valid bool `json:"valid"`
Message string `json:"message"`
}
// LogpushGetOwnershipChallengeResponse is the API response, containing a ownership challenge.
type LogpushGetOwnershipChallengeResponse struct {
Response
Result LogpushGetOwnershipChallenge `json:"result"`
}
// LogpushGetOwnershipChallengeRequest is the API request for get ownership challenge.
type LogpushGetOwnershipChallengeRequest struct {
DestinationConf string `json:"destination_conf"`
}
// LogpushOwnershipChallangeValidationResponse is the API response,
// containing a ownership challenge validation result.
type LogpushOwnershipChallangeValidationResponse struct {
Response
Result struct {
Valid bool `json:"valid"`
}
}
// LogpushValidateOwnershipChallengeRequest is the API request for validate ownership challenge.
type LogpushValidateOwnershipChallengeRequest struct {
DestinationConf string `json:"destination_conf"`
OwnershipChallenge string `json:"ownership_challenge"`
}
// LogpushDestinationExistsResponse is the API response,
// containing a destination exists check result.
type LogpushDestinationExistsResponse struct {
Response
Result struct {
Exists bool `json:"exists"`
}
}
// LogpushDestinationExistsRequest is the API request for check destination exists.
type LogpushDestinationExistsRequest struct {
DestinationConf string `json:"destination_conf"`
}
// CreateLogpushJob creates a new LogpushJob for a zone.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-create-logpush-job
func (api *API) CreateLogpushJob(zoneID string, job LogpushJob) (*LogpushJob, error) {
uri := "/zones/" + zoneID + "/logpush/jobs"
res, err := api.makeRequest("POST", uri, job)
if err != nil {
return nil, errors.Wrap(err, errMakeRequestError)
}
var r LogpushJobDetailsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return nil, errors.Wrap(err, errUnmarshalError)
}
return &r.Result, nil
}
// LogpushJobs returns all Logpush Jobs for a zone.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-list-logpush-jobs
func (api *API) LogpushJobs(zoneID string) ([]LogpushJob, error) {
uri := "/zones/" + zoneID + "/logpush/jobs"
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return []LogpushJob{}, errors.Wrap(err, errMakeRequestError)
}
var r LogpushJobsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return []LogpushJob{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}
// LogpushJob fetches detail about one Logpush Job for a zone.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-logpush-job-details
func (api *API) LogpushJob(zoneID string, jobID int) (LogpushJob, error) {
uri := "/zones/" + zoneID + "/logpush/jobs/" + strconv.Itoa(jobID)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return LogpushJob{}, errors.Wrap(err, errMakeRequestError)
}
var r LogpushJobDetailsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return LogpushJob{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}
// UpdateLogpushJob lets you update a Logpush Job.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-update-logpush-job
func (api *API) UpdateLogpushJob(zoneID string, jobID int, job LogpushJob) error {
uri := "/zones/" + zoneID + "/logpush/jobs/" + strconv.Itoa(jobID)
res, err := api.makeRequest("PUT", uri, job)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
var r LogpushJobDetailsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return errors.Wrap(err, errUnmarshalError)
}
return nil
}
// DeleteLogpushJob deletes a Logpush Job for a zone.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-delete-logpush-job
func (api *API) DeleteLogpushJob(zoneID string, jobID int) error {
uri := "/zones/" + zoneID + "/logpush/jobs/" + strconv.Itoa(jobID)
res, err := api.makeRequest("DELETE", uri, nil)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
var r LogpushJobDetailsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return errors.Wrap(err, errUnmarshalError)
}
return nil
}
// GetLogpushOwnershipChallenge returns ownership challenge.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-get-ownership-challenge
func (api *API) GetLogpushOwnershipChallenge(zoneID, destinationConf string) (*LogpushGetOwnershipChallenge, error) {
uri := "/zones/" + zoneID + "/logpush/ownership"
res, err := api.makeRequest("POST", uri, LogpushGetOwnershipChallengeRequest{
DestinationConf: destinationConf,
})
if err != nil {
return nil, errors.Wrap(err, errMakeRequestError)
}
var r LogpushGetOwnershipChallengeResponse
err = json.Unmarshal(res, &r)
if err != nil {
return nil, errors.Wrap(err, errUnmarshalError)
}
return &r.Result, nil
}
// ValidateLogpushOwnershipChallenge returns ownership challenge validation result.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-validate-ownership-challenge
func (api *API) ValidateLogpushOwnershipChallenge(zoneID, destinationConf, ownershipChallenge string) (bool, error) {
uri := "/zones/" + zoneID + "/logpush/ownership/validate"
res, err := api.makeRequest("POST", uri, LogpushValidateOwnershipChallengeRequest{
DestinationConf: destinationConf,
OwnershipChallenge: ownershipChallenge,
})
if err != nil {
return false, errors.Wrap(err, errMakeRequestError)
}
var r LogpushGetOwnershipChallengeResponse
err = json.Unmarshal(res, &r)
if err != nil {
return false, errors.Wrap(err, errUnmarshalError)
}
return r.Result.Valid, nil
}
// CheckLogpushDestinationExists returns destination exists check result.
//
// API reference: https://api.cloudflare.com/#logpush-jobs-check-destination-exists
func (api *API) CheckLogpushDestinationExists(zoneID, destinationConf string) (bool, error) {
uri := "/zones/" + zoneID + "/logpush/validate/destination/exists"
res, err := api.makeRequest("POST", uri, LogpushDestinationExistsRequest{
DestinationConf: destinationConf,
})
if err != nil {
return false, errors.Wrap(err, errMakeRequestError)
}
var r LogpushDestinationExistsResponse
err = json.Unmarshal(res, &r)
if err != nil {
return false, errors.Wrap(err, errUnmarshalError)
}
return r.Result.Exists, nil
}

View File

@@ -28,11 +28,11 @@ func Headers(headers http.Header) Option {
}
}
// Organization allows you to apply account-level changes (Load Balancing, Railguns)
// to an organization instead.
// UsingOrganization allows you to apply account-level changes (Load Balancing,
// Railguns) to an organization instead.
func UsingOrganization(orgID string) Option {
return func(api *API) error {
api.organizationID = orgID
api.OrganizationID = orgID
return nil
}
}
@@ -73,6 +73,17 @@ func UsingLogger(logger Logger) Option {
}
}
// UserAgent can be set if you want to send a software name and version for HTTP access logs.
// It is recommended to set it in order to help future Customer Support diagnostics
// and prevent collateral damage by sharing generic User-Agent string with abusive users.
// E.g. "my-software/1.2.3". By default generic Go User-Agent is used.
func UserAgent(userAgent string) Option {
return func(api *API) error {
api.UserAgent = userAgent
return nil
}
}
// parseOptions parses the supplied options functions and returns a configured
// *API instance.
func (api *API) parseOptions(opts ...Option) error {

View File

@@ -139,7 +139,8 @@ type organizationInvitesResponse struct {
ResultInfo `json:"result_info"`
}
// OrganizationMembers returns list of invites for specified organization of the logged-in user.
// OrganizationInvites returns list of invites for specified organization of
// the logged-in user.
//
// API reference: https://api.cloudflare.com/#organization-invites
func (api *API) OrganizationInvites(organizationID string) ([]OrganizationInvite, ResultInfo, error) {

View File

@@ -1,6 +1,7 @@
package cloudflare
import (
"context"
"encoding/json"
"net/url"
"time"
@@ -57,7 +58,7 @@ type originCACertificateResponseRevoke struct {
// API reference: https://api.cloudflare.com/#cloudflare-ca-create-certificate
func (api *API) CreateOriginCertificate(certificate OriginCACertificate) (*OriginCACertificate, error) {
uri := "/certificates"
res, err := api.makeRequestWithAuthType("POST", uri, certificate, AuthUserService)
res, err := api.makeRequestWithAuthType(context.TODO(), "POST", uri, certificate, AuthUserService)
if err != nil {
return nil, errors.Wrap(err, errMakeRequestError)
@@ -89,7 +90,7 @@ func (api *API) OriginCertificates(options OriginCACertificateListOptions) ([]Or
v.Set("zone_id", options.ZoneID)
}
uri := "/certificates" + "?" + v.Encode()
res, err := api.makeRequestWithAuthType("GET", uri, nil, AuthUserService)
res, err := api.makeRequestWithAuthType(context.TODO(), "GET", uri, nil, AuthUserService)
if err != nil {
return nil, errors.Wrap(err, errMakeRequestError)
@@ -117,7 +118,7 @@ func (api *API) OriginCertificates(options OriginCACertificateListOptions) ([]Or
// API reference: https://api.cloudflare.com/#cloudflare-ca-certificate-details
func (api *API) OriginCertificate(certificateID string) (*OriginCACertificate, error) {
uri := "/certificates/" + certificateID
res, err := api.makeRequestWithAuthType("GET", uri, nil, AuthUserService)
res, err := api.makeRequestWithAuthType(context.TODO(), "GET", uri, nil, AuthUserService)
if err != nil {
return nil, errors.Wrap(err, errMakeRequestError)
@@ -145,7 +146,7 @@ func (api *API) OriginCertificate(certificateID string) (*OriginCACertificate, e
// API reference: https://api.cloudflare.com/#cloudflare-ca-revoke-certificate
func (api *API) RevokeOriginCertificate(certificateID string) (*OriginCACertificateID, error) {
uri := "/certificates/" + certificateID
res, err := api.makeRequestWithAuthType("DELETE", uri, nil, AuthUserService)
res, err := api.makeRequestWithAuthType(context.TODO(), "DELETE", uri, nil, AuthUserService)
if err != nil {
return nil, errors.Wrap(err, errMakeRequestError)

View File

@@ -23,26 +23,40 @@ type PageRuleTarget struct {
PageRuleAction is the action to take when the target is matched.
Valid IDs are:
always_online
always_use_https
automatic_https_rewrites
browser_cache_ttl
browser_check
bypass_cache_on_cookie
cache_by_device_type
cache_deception_armor
cache_level
cache_on_cookie
disable_apps
disable_performance
disable_railgun
disable_security
edge_cache_ttl
email_obfuscation
explicit_cache_control
forwarding_url
host_header_override
ip_geolocation
minify
mirage
opportunistic_encryption
origin_error_page_pass_thru
polish
resolve_override
respect_strong_etag
response_buffering
rocket_loader
security_level
server_side_exclude
smart_errors
sort_query_string_for_cache
ssl
true_client_ip_header
waf
*/
type PageRuleAction struct {
@@ -52,26 +66,41 @@ type PageRuleAction struct {
// 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
"always_online": "Always Online", // Value of type string
"always_use_https": "Always Use HTTPS", // Value of type interface{}
"automatic_https_rewrites": "Automatic HTTPS Rewrites", // Value of type string
"browser_cache_ttl": "Browser Cache TTL", // Value of type int
"browser_check": "Browser Integrity Check", // Value of type string
"bypass_cache_on_cookie": "Bypass Cache on Cookie", // Value of type string
"cache_by_device_type": "Cache By Device Type", // Value of type string
"cache_deception_armor": "Cache Deception Armor", // Value of type string
"cache_level": "Cache Level", // Value of type string
"cache_on_cookie": "Cache On Cookie", // 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
"explicit_cache_control": "Origin Cache Control", // Value of type string
"forwarding_url": "Forwarding URL", // Value of type map[string]interface
"host_header_override": "Host Header Override", // Value of type string
"ip_geolocation": "IP Geolocation Header", // Value of type string
"minify": "Minify", // Value of type map[string]interface
"mirage": "Mirage", // Value of type string
"opportunistic_encryption": "Opportunistic Encryption", // Value of type string
"origin_error_page_pass_thru": "Origin Error Page Pass-thru", // Value of type string
"polish": "Polish", // Value of type string
"resolve_override": "Resolve Override", // Value of type string
"respect_strong_etag": "Respect Strong ETags", // Value of type string
"response_buffering": "Response Buffering", // 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
"sort_query_string_for_cache": "Query String Sort", // Value of type string
"ssl": "SSL", // Value of type string
"true_client_ip_header": "True Client IP Header", // Value of type string
"waf": "Web Application Firewall", // Value of type string
}
// PageRule describes a Page Rule.
@@ -176,7 +205,7 @@ func (api *API) ChangePageRule(zoneID, ruleID string, rule PageRule) error {
// API reference: https://api.cloudflare.com/#page-rules-for-a-zone-update-a-page-rule
func (api *API) UpdatePageRule(zoneID, ruleID string, rule PageRule) error {
uri := "/zones/" + zoneID + "/pagerules/" + ruleID
res, err := api.makeRequest("PUT", uri, nil)
res, err := api.makeRequest("PUT", uri, rule)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}

View File

@@ -18,6 +18,7 @@ type RateLimit struct {
Threshold int `json:"threshold"`
Period int `json:"period"`
Action RateLimitAction `json:"action"`
Correlate *RateLimitCorrelate `json:"correlate,omitempty"`
}
// RateLimitTrafficMatcher contains the rules that will be used to apply a rate limit to traffic
@@ -35,8 +36,17 @@ type RateLimitRequestMatcher struct {
// RateLimitResponseMatcher contains the matching rules pertaining to responses
type RateLimitResponseMatcher struct {
Statuses []int `json:"status,omitempty"`
OriginTraffic *bool `json:"origin_traffic,omitempty"` // api defaults to true so we need an explicit empty value
Statuses []int `json:"status,omitempty"`
OriginTraffic *bool `json:"origin_traffic,omitempty"` // api defaults to true so we need an explicit empty value
Headers []RateLimitResponseMatcherHeader `json:"headers,omitempty"`
}
// RateLimitResponseMatcherHeader contains the structure of the origin
// HTTP headers used in request matcher checks.
type RateLimitResponseMatcherHeader struct {
Name string `json:"name"`
Op string `json:"op"`
Value string `json:"value"`
}
// RateLimitKeyValue is k-v formatted as expected in the rate limit description
@@ -58,6 +68,11 @@ type RateLimitActionResponse struct {
Body string `json:"body"`
}
// RateLimitCorrelate pertainings to NAT support
type RateLimitCorrelate struct {
By string `json:"by"`
}
type rateLimitResponse struct {
Response
Result RateLimit `json:"result"`

175
vendor/github.com/cloudflare/cloudflare-go/registrar.go generated vendored Normal file
View File

@@ -0,0 +1,175 @@
package cloudflare
import (
"encoding/json"
"fmt"
"time"
"github.com/pkg/errors"
)
// RegistrarDomain is the structure of the API response for a new
// Cloudflare Registrar domain.
type RegistrarDomain struct {
ID string `json:"id"`
Available bool `json:"available"`
SupportedTLD bool `json:"supported_tld"`
CanRegister bool `json:"can_register"`
TransferIn RegistrarTransferIn `json:"transfer_in"`
CurrentRegistrar string `json:"current_registrar"`
ExpiresAt time.Time `json:"expires_at"`
RegistryStatuses string `json:"registry_statuses"`
Locked bool `json:"locked"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
RegistrantContact RegistrantContact `json:"registrant_contact"`
}
// RegistrarTransferIn contains the structure for a domain transfer in
// request.
type RegistrarTransferIn struct {
UnlockDomain string `json:"unlock_domain"`
DisablePrivacy string `json:"disable_privacy"`
EnterAuthCode string `json:"enter_auth_code"`
ApproveTransfer string `json:"approve_transfer"`
AcceptFoa string `json:"accept_foa"`
CanCancelTransfer bool `json:"can_cancel_transfer"`
}
// RegistrantContact is the contact details for the domain registration.
type RegistrantContact struct {
ID string `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Organization string `json:"organization"`
Address string `json:"address"`
Address2 string `json:"address2"`
City string `json:"city"`
State string `json:"state"`
Zip string `json:"zip"`
Country string `json:"country"`
Phone string `json:"phone"`
Email string `json:"email"`
Fax string `json:"fax"`
}
// RegistrarDomainConfiguration is the structure for making updates to
// and existing domain.
type RegistrarDomainConfiguration struct {
NameServers []string `json:"name_servers"`
Privacy bool `json:"privacy"`
Locked bool `json:"locked"`
AutoRenew bool `json:"auto_renew"`
}
// RegistrarDomainDetailResponse is the structure of the detailed
// response from the API for a single domain.
type RegistrarDomainDetailResponse struct {
Response
Result RegistrarDomain `json:"result"`
}
// RegistrarDomainsDetailResponse is the structure of the detailed
// response from the API.
type RegistrarDomainsDetailResponse struct {
Response
Result []RegistrarDomain `json:"result"`
}
// RegistrarDomain returns a single domain based on the account ID and
// domain name.
//
// API reference: https://api.cloudflare.com/#registrar-domains-get-domain
func (api *API) RegistrarDomain(accountID, domainName string) (RegistrarDomain, error) {
uri := fmt.Sprintf("/accounts/%s/registrar/domains/%s", accountID, domainName)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return RegistrarDomain{}, errors.Wrap(err, errMakeRequestError)
}
var r RegistrarDomainDetailResponse
err = json.Unmarshal(res, &r)
if err != nil {
return RegistrarDomain{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}
// RegistrarDomains returns all registrar domains based on the account
// ID.
//
// API reference: https://api.cloudflare.com/#registrar-domains-list-domains
func (api *API) RegistrarDomains(accountID string) ([]RegistrarDomain, error) {
uri := "/accounts/" + accountID + "/registrar/domains"
res, err := api.makeRequest("POST", uri, nil)
if err != nil {
return []RegistrarDomain{}, errors.Wrap(err, errMakeRequestError)
}
var r RegistrarDomainsDetailResponse
err = json.Unmarshal(res, &r)
if err != nil {
return []RegistrarDomain{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}
// TransferRegistrarDomain initiates the transfer from another registrar
// to Cloudflare Registrar.
//
// API reference: https://api.cloudflare.com/#registrar-domains-transfer-domain
func (api *API) TransferRegistrarDomain(accountID, domainName string) ([]RegistrarDomain, error) {
uri := fmt.Sprintf("/accounts/%s/registrar/domains/%s/transfer", accountID, domainName)
res, err := api.makeRequest("POST", uri, nil)
if err != nil {
return []RegistrarDomain{}, errors.Wrap(err, errMakeRequestError)
}
var r RegistrarDomainsDetailResponse
err = json.Unmarshal(res, &r)
if err != nil {
return []RegistrarDomain{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}
// CancelRegistrarDomainTransfer cancels a pending domain transfer.
//
// API reference: https://api.cloudflare.com/#registrar-domains-cancel-transfer
func (api *API) CancelRegistrarDomainTransfer(accountID, domainName string) ([]RegistrarDomain, error) {
uri := fmt.Sprintf("/accounts/%s/registrar/domains/%s/cancel_transfer", accountID, domainName)
res, err := api.makeRequest("POST", uri, nil)
if err != nil {
return []RegistrarDomain{}, errors.Wrap(err, errMakeRequestError)
}
var r RegistrarDomainsDetailResponse
err = json.Unmarshal(res, &r)
if err != nil {
return []RegistrarDomain{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}
// UpdateRegistrarDomain updates an existing Registrar Domain configuration.
//
// API reference: https://api.cloudflare.com/#registrar-domains-update-domain
func (api *API) UpdateRegistrarDomain(accountID, domainName string, domainConfiguration RegistrarDomainConfiguration) (RegistrarDomain, error) {
uri := fmt.Sprintf("/accounts/%s/registrar/domains/%s", accountID, domainName)
res, err := api.makeRequest("PUT", uri, domainConfiguration)
if err != nil {
return RegistrarDomain{}, errors.Wrap(err, errMakeRequestError)
}
var r RegistrarDomainDetailResponse
err = json.Unmarshal(res, &r)
if err != nil {
return RegistrarDomain{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}

158
vendor/github.com/cloudflare/cloudflare-go/spectrum.go generated vendored Normal file
View File

@@ -0,0 +1,158 @@
package cloudflare
import (
"encoding/json"
"fmt"
"time"
"github.com/pkg/errors"
)
// SpectrumApplication defines a single Spectrum Application.
type SpectrumApplication struct {
ID string `json:"id,omitempty"`
Protocol string `json:"protocol,omitempty"`
IPv4 bool `json:"ipv4,omitempty"`
DNS SpectrumApplicationDNS `json:"dns,omitempty"`
OriginDirect []string `json:"origin_direct,omitempty"`
OriginPort int `json:"origin_port,omitempty"`
OriginDNS *SpectrumApplicationOriginDNS `json:"origin_dns,omitempty"`
IPFirewall bool `json:"ip_firewall,omitempty"`
ProxyProtocol bool `json:"proxy_protocol,omitempty"`
TLS string `json:"tls,omitempty"`
CreatedOn *time.Time `json:"created_on,omitempty"`
ModifiedOn *time.Time `json:"modified_on,omitempty"`
}
// SpectrumApplicationDNS holds the external DNS configuration for a Spectrum
// Application.
type SpectrumApplicationDNS struct {
Type string `json:"type"`
Name string `json:"name"`
}
// SpectrumApplicationOriginDNS holds the origin DNS configuration for a Spectrum
// Application.
type SpectrumApplicationOriginDNS struct {
Name string `json:"name"`
}
// SpectrumApplicationDetailResponse is the structure of the detailed response
// from the API.
type SpectrumApplicationDetailResponse struct {
Response
Result SpectrumApplication `json:"result"`
}
// SpectrumApplicationsDetailResponse is the structure of the detailed response
// from the API.
type SpectrumApplicationsDetailResponse struct {
Response
Result []SpectrumApplication `json:"result"`
}
// SpectrumApplications fetches all of the Spectrum applications for a zone.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#list-spectrum-applications
func (api *API) SpectrumApplications(zoneID string) ([]SpectrumApplication, error) {
uri := "/zones/" + zoneID + "/spectrum/apps"
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return []SpectrumApplication{}, errors.Wrap(err, errMakeRequestError)
}
var spectrumApplications SpectrumApplicationsDetailResponse
err = json.Unmarshal(res, &spectrumApplications)
if err != nil {
return []SpectrumApplication{}, errors.Wrap(err, errUnmarshalError)
}
return spectrumApplications.Result, nil
}
// SpectrumApplication fetches a single Spectrum application based on the ID.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#list-spectrum-applications
func (api *API) SpectrumApplication(zoneID string, applicationID string) (SpectrumApplication, error) {
uri := fmt.Sprintf(
"/zones/%s/spectrum/apps/%s",
zoneID,
applicationID,
)
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return SpectrumApplication{}, errors.Wrap(err, errMakeRequestError)
}
var spectrumApplication SpectrumApplicationDetailResponse
err = json.Unmarshal(res, &spectrumApplication)
if err != nil {
return SpectrumApplication{}, errors.Wrap(err, errUnmarshalError)
}
return spectrumApplication.Result, nil
}
// CreateSpectrumApplication creates a new Spectrum application.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#create-a-spectrum-application
func (api *API) CreateSpectrumApplication(zoneID string, appDetails SpectrumApplication) (SpectrumApplication, error) {
uri := "/zones/" + zoneID + "/spectrum/apps"
res, err := api.makeRequest("POST", uri, appDetails)
if err != nil {
return SpectrumApplication{}, errors.Wrap(err, errMakeRequestError)
}
var spectrumApplication SpectrumApplicationDetailResponse
err = json.Unmarshal(res, &spectrumApplication)
if err != nil {
return SpectrumApplication{}, errors.Wrap(err, errUnmarshalError)
}
return spectrumApplication.Result, nil
}
// UpdateSpectrumApplication updates an existing Spectrum application.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#update-a-spectrum-application
func (api *API) UpdateSpectrumApplication(zoneID, appID string, appDetails SpectrumApplication) (SpectrumApplication, error) {
uri := fmt.Sprintf(
"/zones/%s/spectrum/apps/%s",
zoneID,
appID,
)
res, err := api.makeRequest("PUT", uri, appDetails)
if err != nil {
return SpectrumApplication{}, errors.Wrap(err, errMakeRequestError)
}
var spectrumApplication SpectrumApplicationDetailResponse
err = json.Unmarshal(res, &spectrumApplication)
if err != nil {
return SpectrumApplication{}, errors.Wrap(err, errUnmarshalError)
}
return spectrumApplication.Result, nil
}
// DeleteSpectrumApplication removes a Spectrum application based on the ID.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#delete-a-spectrum-application
func (api *API) DeleteSpectrumApplication(zoneID string, applicationID string) error {
uri := fmt.Sprintf(
"/zones/%s/spectrum/apps/%s",
zoneID,
applicationID,
)
_, err := api.makeRequest("DELETE", uri, nil)
if err != nil {
return errors.Wrap(err, errMakeRequestError)
}
return nil
}

View File

@@ -9,18 +9,25 @@ import (
// 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"`
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"`
GeoRestrictions ZoneCustomSSLGeoRestrictions `json:"geo_restrictions"`
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"`
}
// ZoneCustomSSLGeoRestrictions represents the parameter to create or update
// geographic restrictions on a custom ssl certificate.
type ZoneCustomSSLGeoRestrictions struct {
Label string `json:"label"`
}
// zoneCustomSSLResponse represents the response from the zone SSL details endpoint.
@@ -38,9 +45,11 @@ type zoneCustomSSLsResponse struct {
// 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"`
Certificate string `json:"certificate"`
PrivateKey string `json:"private_key"`
BundleMethod string `json:"bundle_method,omitempty"`
GeoRestrictions ZoneCustomSSLGeoRestrictions `json:"geo_restrictions,omitempty"`
Type string `json:"type,omitempty"`
}
// ZoneCustomSSLPriority represents a certificate's ID and priority. It is a

View File

@@ -0,0 +1,50 @@
package cloudflare
import (
"encoding/json"
"github.com/pkg/errors"
)
// UniversalSSLSetting represents a universal ssl setting's properties.
type UniversalSSLSetting struct {
Enabled bool `json:"enabled"`
}
type universalSSLSettingResponse struct {
Response
Result UniversalSSLSetting `json:"result"`
}
// UniversalSSLSettingDetails returns the details for a universal ssl setting
//
// API reference: https://api.cloudflare.com/#universal-ssl-settings-for-a-zone-universal-ssl-settings-details
func (api *API) UniversalSSLSettingDetails(zoneID string) (UniversalSSLSetting, error) {
uri := "/zones/" + zoneID + "/ssl/universal/settings"
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return UniversalSSLSetting{}, errors.Wrap(err, errMakeRequestError)
}
var r universalSSLSettingResponse
if err := json.Unmarshal(res, &r); err != nil {
return UniversalSSLSetting{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}
// EditUniversalSSLSetting edits the uniersal ssl setting for a zone
//
// API reference: https://api.cloudflare.com/#universal-ssl-settings-for-a-zone-edit-universal-ssl-settings
func (api *API) EditUniversalSSLSetting(zoneID string, setting UniversalSSLSetting) (UniversalSSLSetting, error) {
uri := "/zones/" + zoneID + "/ssl/universal/settings"
res, err := api.makeRequest("PATCH", uri, setting)
if err != nil {
return UniversalSSLSetting{}, errors.Wrap(err, errMakeRequestError)
}
var r universalSSLSettingResponse
if err := json.Unmarshal(res, &r); err != nil {
return UniversalSSLSetting{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}

View File

@@ -2,6 +2,9 @@ package cloudflare
import (
"encoding/json"
"net/url"
"strings"
"time"
"github.com/pkg/errors"
)
@@ -18,6 +21,32 @@ type VirtualDNS struct {
ModifiedOn string `json:"modified_on"`
}
// VirtualDNSAnalyticsMetrics respresents a group of aggregated Virtual DNS metrics.
type VirtualDNSAnalyticsMetrics struct {
QueryCount *int64 `json:"queryCount"`
UncachedCount *int64 `json:"uncachedCount"`
StaleCount *int64 `json:"staleCount"`
ResponseTimeAvg *float64 `json:"responseTimeAvg"`
ResponseTimeMedian *float64 `json:"responseTimeMedian"`
ResponseTime90th *float64 `json:"responseTime90th"`
ResponseTime99th *float64 `json:"responseTime99th"`
}
// VirtualDNSAnalytics represents a set of aggregated Virtual DNS metrics.
// TODO: Add the queried data and not only the aggregated values.
type VirtualDNSAnalytics struct {
Totals VirtualDNSAnalyticsMetrics `json:"totals"`
Min VirtualDNSAnalyticsMetrics `json:"min"`
Max VirtualDNSAnalyticsMetrics `json:"max"`
}
// VirtualDNSUserAnalyticsOptions represents range and dimension selection on analytics endpoint
type VirtualDNSUserAnalyticsOptions struct {
Metrics []string
Since *time.Time
Until *time.Time
}
// VirtualDNSResponse represents a Virtual DNS response.
type VirtualDNSResponse struct {
Response
@@ -30,6 +59,12 @@ type VirtualDNSListResponse struct {
Result []*VirtualDNS `json:"result"`
}
// VirtualDNSAnalyticsResponse represents a Virtual DNS analytics response.
type VirtualDNSAnalyticsResponse struct {
Response
Result VirtualDNSAnalytics `json:"result"`
}
// CreateVirtualDNS creates a new Virtual DNS cluster.
//
// API reference: https://api.cloudflare.com/#virtual-dns-users--create-a-virtual-dns-cluster
@@ -123,3 +158,35 @@ func (api *API) DeleteVirtualDNS(virtualDNSID string) error {
return nil
}
// encode encodes non-nil fields into URL encoded form.
func (o VirtualDNSUserAnalyticsOptions) encode() string {
v := url.Values{}
if o.Since != nil {
v.Set("since", (*o.Since).UTC().Format(time.RFC3339))
}
if o.Until != nil {
v.Set("until", (*o.Until).UTC().Format(time.RFC3339))
}
if o.Metrics != nil {
v.Set("metrics", strings.Join(o.Metrics, ","))
}
return v.Encode()
}
// VirtualDNSUserAnalytics retrieves analytics report for a specified dimension and time range
func (api *API) VirtualDNSUserAnalytics(virtualDNSID string, o VirtualDNSUserAnalyticsOptions) (VirtualDNSAnalytics, error) {
uri := "/user/virtual_dns/" + virtualDNSID + "/dns_analytics/report?" + o.encode()
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return VirtualDNSAnalytics{}, errors.Wrap(err, errMakeRequestError)
}
response := VirtualDNSAnalyticsResponse{}
err = json.Unmarshal(res, &response)
if err != nil {
return VirtualDNSAnalytics{}, errors.Wrap(err, errUnmarshalError)
}
return response.Result, nil
}

View File

@@ -39,14 +39,28 @@ type WAFRule struct {
AllowedModes []string `json:"allowed_modes"`
}
// WAFRulesResponse represents the response from the WAF rule endpoint.
// WAFRulesResponse represents the response from the WAF rules endpoint.
type WAFRulesResponse struct {
Response
Result []WAFRule `json:"result"`
ResultInfo ResultInfo `json:"result_info"`
}
// WAFRuleResponse represents the response from the WAF rule endpoint.
type WAFRuleResponse struct {
Response
Result WAFRule `json:"result"`
ResultInfo ResultInfo `json:"result_info"`
}
// WAFRuleOptions is a subset of WAFRule, for editable options.
type WAFRuleOptions struct {
Mode string `json:"mode"`
}
// ListWAFPackages returns a slice of the WAF packages for the given zone.
//
// API Reference: https://api.cloudflare.com/#waf-rule-packages-list-firewall-packages
func (api *API) ListWAFPackages(zoneID string) ([]WAFPackage, error) {
var p WAFPackagesResponse
var packages []WAFPackage
@@ -72,26 +86,70 @@ func (api *API) ListWAFPackages(zoneID string) ([]WAFPackage, error) {
}
// ListWAFRules returns a slice of the WAF rules for the given WAF package.
//
// API Reference: https://api.cloudflare.com/#waf-rules-list-rules
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)
}
var r WAFRulesResponse
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
}
// WAFRule returns a WAF rule from the given WAF package.
//
// API Reference: https://api.cloudflare.com/#waf-rules-rule-details
func (api *API) WAFRule(zoneID, packageID, ruleID string) (WAFRule, error) {
uri := "/zones/" + zoneID + "/firewall/waf/packages/" + packageID + "/rules/" + ruleID
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return WAFRule{}, errors.Wrap(err, errMakeRequestError)
}
var r WAFRuleResponse
err = json.Unmarshal(res, &r)
if err != nil {
return WAFRule{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}
// UpdateWAFRule lets you update the mode of a WAF Rule.
//
// API Reference: https://api.cloudflare.com/#waf-rules-edit-rule
func (api *API) UpdateWAFRule(zoneID, packageID, ruleID, mode string) (WAFRule, error) {
opts := WAFRuleOptions{Mode: mode}
uri := "/zones/" + zoneID + "/firewall/waf/packages/" + packageID + "/rules/" + ruleID
res, err := api.makeRequest("PATCH", uri, opts)
if err != nil {
return WAFRule{}, errors.Wrap(err, errMakeRequestError)
}
var r WAFRuleResponse
err = json.Unmarshal(res, &r)
if err != nil {
return WAFRule{}, errors.Wrap(err, errUnmarshalError)
}
return r.Result, nil
}

312
vendor/github.com/cloudflare/cloudflare-go/workers.go generated vendored Normal file
View File

@@ -0,0 +1,312 @@
package cloudflare
import (
"encoding/json"
"net/http"
"time"
"github.com/pkg/errors"
)
// WorkerRequestParams provides parameters for worker requests for both enterprise and standard requests
type WorkerRequestParams struct {
ZoneID string
ScriptName string
}
// WorkerRoute aka filters are patterns used to enable or disable workers that match requests.
//
// API reference: https://api.cloudflare.com/#worker-filters-properties
type WorkerRoute struct {
ID string `json:"id,omitempty"`
Pattern string `json:"pattern"`
Enabled bool `json:"enabled"`
Script string `json:"script,omitempty"`
}
// WorkerRoutesResponse embeds Response struct and slice of WorkerRoutes
type WorkerRoutesResponse struct {
Response
Routes []WorkerRoute `json:"result"`
}
// WorkerRouteResponse embeds Response struct and a single WorkerRoute
type WorkerRouteResponse struct {
Response
WorkerRoute `json:"result"`
}
// WorkerScript Cloudflare Worker struct with metadata
type WorkerScript struct {
WorkerMetaData
Script string `json:"script"`
}
// WorkerMetaData contains worker script information such as size, creation & modification dates
type WorkerMetaData struct {
ID string `json:"id,omitempty"`
ETAG string `json:"etag,omitempty"`
Size int `json:"size,omitempty"`
CreatedOn time.Time `json:"created_on,omitempty"`
ModifiedOn time.Time `json:"modified_on,omitempty"`
}
// WorkerListResponse wrapper struct for API response to worker script list API call
type WorkerListResponse struct {
Response
WorkerList []WorkerMetaData `json:"result"`
}
// WorkerScriptResponse wrapper struct for API response to worker script calls
type WorkerScriptResponse struct {
Response
WorkerScript `json:"result"`
}
// DeleteWorker deletes worker for a zone.
//
// API reference: https://api.cloudflare.com/#worker-script-delete-worker
func (api *API) DeleteWorker(requestParams *WorkerRequestParams) (WorkerScriptResponse, error) {
// if ScriptName is provided we will treat as org request
if requestParams.ScriptName != "" {
return api.deleteWorkerWithName(requestParams.ScriptName)
}
uri := "/zones/" + requestParams.ZoneID + "/workers/script"
res, err := api.makeRequest("DELETE", uri, nil)
var r WorkerScriptResponse
if err != nil {
return r, errors.Wrap(err, errMakeRequestError)
}
err = json.Unmarshal(res, &r)
if err != nil {
return r, errors.Wrap(err, errUnmarshalError)
}
return r, nil
}
// DeleteWorkerWithName deletes worker for a zone.
// This is an enterprise only feature https://developers.cloudflare.com/workers/api/config-api-for-enterprise
// organizationID must be specified as api option https://godoc.org/github.com/cloudflare/cloudflare-go#UsingOrganization
//
// API reference: https://api.cloudflare.com/#worker-script-delete-worker
func (api *API) deleteWorkerWithName(scriptName string) (WorkerScriptResponse, error) {
if api.OrganizationID == "" {
return WorkerScriptResponse{}, errors.New("organization ID required for enterprise only request")
}
uri := "/accounts/" + api.OrganizationID + "/workers/scripts/" + scriptName
res, err := api.makeRequest("DELETE", uri, nil)
var r WorkerScriptResponse
if err != nil {
return r, errors.Wrap(err, errMakeRequestError)
}
err = json.Unmarshal(res, &r)
if err != nil {
return r, errors.Wrap(err, errUnmarshalError)
}
return r, nil
}
// DownloadWorker fetch raw script content for your worker returns []byte containing worker code js
//
// API reference: https://api.cloudflare.com/#worker-script-download-worker
func (api *API) DownloadWorker(requestParams *WorkerRequestParams) (WorkerScriptResponse, error) {
if requestParams.ScriptName != "" {
return api.downloadWorkerWithName(requestParams.ScriptName)
}
uri := "/zones/" + requestParams.ZoneID + "/workers/script"
res, err := api.makeRequest("GET", uri, nil)
var r WorkerScriptResponse
if err != nil {
return r, errors.Wrap(err, errMakeRequestError)
}
r.Script = string(res)
r.Success = true
return r, nil
}
// DownloadWorkerWithName fetch raw script content for your worker returns string containing worker code js
// This is an enterprise only feature https://developers.cloudflare.com/workers/api/config-api-for-enterprise/
//
// API reference: https://api.cloudflare.com/#worker-script-download-worker
func (api *API) downloadWorkerWithName(scriptName string) (WorkerScriptResponse, error) {
if api.OrganizationID == "" {
return WorkerScriptResponse{}, errors.New("organization ID required for enterprise only request")
}
uri := "/accounts/" + api.OrganizationID + "/workers/scripts/" + scriptName
res, err := api.makeRequest("GET", uri, nil)
var r WorkerScriptResponse
if err != nil {
return r, errors.Wrap(err, errMakeRequestError)
}
r.Script = string(res)
r.Success = true
return r, nil
}
// ListWorkerScripts returns list of worker scripts for given organization
// This is an enterprise only feature https://developers.cloudflare.com/workers/api/config-api-for-enterprise
//
// API reference: https://developers.cloudflare.com/workers/api/config-api-for-enterprise/
func (api *API) ListWorkerScripts() (WorkerListResponse, error) {
if api.OrganizationID == "" {
return WorkerListResponse{}, errors.New("organization ID required for enterprise only request")
}
uri := "/accounts/" + api.OrganizationID + "/workers/scripts"
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return WorkerListResponse{}, errors.Wrap(err, errMakeRequestError)
}
var r WorkerListResponse
err = json.Unmarshal(res, &r)
if err != nil {
return WorkerListResponse{}, errors.Wrap(err, errUnmarshalError)
}
return r, nil
}
// UploadWorker push raw script content for your worker
//
// API reference: https://api.cloudflare.com/#worker-script-upload-worker
func (api *API) UploadWorker(requestParams *WorkerRequestParams, data string) (WorkerScriptResponse, error) {
if requestParams.ScriptName != "" {
return api.uploadWorkerWithName(requestParams.ScriptName, data)
}
uri := "/zones/" + requestParams.ZoneID + "/workers/script"
headers := make(http.Header)
headers.Set("Content-Type", "application/javascript")
res, err := api.makeRequestWithHeaders("PUT", uri, []byte(data), headers)
var r WorkerScriptResponse
if err != nil {
return r, errors.Wrap(err, errMakeRequestError)
}
err = json.Unmarshal(res, &r)
if err != nil {
return r, errors.Wrap(err, errUnmarshalError)
}
return r, nil
}
// UploadWorkerWithName push raw script content for your worker
// This is an enterprise only feature https://developers.cloudflare.com/workers/api/config-api-for-enterprise/
//
// API reference: https://api.cloudflare.com/#worker-script-upload-worker
func (api *API) uploadWorkerWithName(scriptName string, data string) (WorkerScriptResponse, error) {
if api.OrganizationID == "" {
return WorkerScriptResponse{}, errors.New("organization ID required for enterprise only request")
}
uri := "/accounts/" + api.OrganizationID + "/workers/scripts/" + scriptName
headers := make(http.Header)
headers.Set("Content-Type", "application/javascript")
res, err := api.makeRequestWithHeaders("PUT", uri, []byte(data), headers)
var r WorkerScriptResponse
if err != nil {
return r, errors.Wrap(err, errMakeRequestError)
}
err = json.Unmarshal(res, &r)
if err != nil {
return r, errors.Wrap(err, errUnmarshalError)
}
return r, nil
}
// CreateWorkerRoute creates worker route for a zone
//
// API reference: https://api.cloudflare.com/#worker-filters-create-filter
func (api *API) CreateWorkerRoute(zoneID string, route WorkerRoute) (WorkerRouteResponse, error) {
// Check whether a script name is defined in order to determine whether
// to use the single-script or multi-script endpoint.
pathComponent := "filters"
if route.Script != "" {
if api.OrganizationID == "" {
return WorkerRouteResponse{}, errors.New("organization ID required for enterprise only request")
}
pathComponent = "routes"
}
uri := "/zones/" + zoneID + "/workers/" + pathComponent
res, err := api.makeRequest("POST", uri, route)
if err != nil {
return WorkerRouteResponse{}, errors.Wrap(err, errMakeRequestError)
}
var r WorkerRouteResponse
err = json.Unmarshal(res, &r)
if err != nil {
return WorkerRouteResponse{}, errors.Wrap(err, errUnmarshalError)
}
return r, nil
}
// DeleteWorkerRoute deletes worker route for a zone
//
// API reference: https://api.cloudflare.com/#worker-filters-delete-filter
func (api *API) DeleteWorkerRoute(zoneID string, routeID string) (WorkerRouteResponse, error) {
// For deleting a route, it doesn't matter whether we use the
// single-script or multi-script endpoint
uri := "/zones/" + zoneID + "/workers/filters/" + routeID
res, err := api.makeRequest("DELETE", uri, nil)
if err != nil {
return WorkerRouteResponse{}, errors.Wrap(err, errMakeRequestError)
}
var r WorkerRouteResponse
err = json.Unmarshal(res, &r)
if err != nil {
return WorkerRouteResponse{}, errors.Wrap(err, errUnmarshalError)
}
return r, nil
}
// ListWorkerRoutes returns list of worker routes
//
// API reference: https://api.cloudflare.com/#worker-filters-list-filters
func (api *API) ListWorkerRoutes(zoneID string) (WorkerRoutesResponse, error) {
pathComponent := "filters"
if api.OrganizationID != "" {
pathComponent = "routes"
}
uri := "/zones/" + zoneID + "/workers/" + pathComponent
res, err := api.makeRequest("GET", uri, nil)
if err != nil {
return WorkerRoutesResponse{}, errors.Wrap(err, errMakeRequestError)
}
var r WorkerRoutesResponse
err = json.Unmarshal(res, &r)
if err != nil {
return WorkerRoutesResponse{}, errors.Wrap(err, errUnmarshalError)
}
for i := range r.Routes {
route := &r.Routes[i]
// The Enabled flag will not be set in the multi-script API response
// so we manually set it to true if the script name is not empty
// in case any multi-script customers rely on the Enabled field
if route.Script != "" {
route.Enabled = true
}
}
return r, nil
}
// UpdateWorkerRoute updates worker route for a zone.
//
// API reference: https://api.cloudflare.com/#worker-filters-update-filter
func (api *API) UpdateWorkerRoute(zoneID string, routeID string, route WorkerRoute) (WorkerRouteResponse, error) {
// Check whether a script name is defined in order to determine whether
// to use the single-script or multi-script endpoint.
pathComponent := "filters"
if route.Script != "" {
if api.OrganizationID == "" {
return WorkerRouteResponse{}, errors.New("organization ID required for enterprise only request")
}
pathComponent = "routes"
}
uri := "/zones/" + zoneID + "/workers/" + pathComponent + "/" + routeID
res, err := api.makeRequest("PUT", uri, route)
if err != nil {
return WorkerRouteResponse{}, errors.Wrap(err, errMakeRequestError)
}
var r WorkerRouteResponse
err = json.Unmarshal(res, &r)
if err != nil {
return WorkerRouteResponse{}, errors.Wrap(err, errUnmarshalError)
}
return r, nil
}

View File

@@ -0,0 +1,192 @@
package cloudflare
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"github.com/pkg/errors"
)
// WorkersKVNamespaceRequest provides parameters for creating and updating storage namespaces
type WorkersKVNamespaceRequest struct {
Title string `json:"title"`
}
// WorkersKVNamespaceResponse is the response received when creating storage namespaces
type WorkersKVNamespaceResponse struct {
Response
Result WorkersKVNamespace `json:"result"`
}
// WorkersKVNamespace contains the unique identifier and title of a storage namespace
type WorkersKVNamespace struct {
ID string `json:"id"`
Title string `json:"title"`
}
// ListWorkersKVNamespacesResponse contains a slice of storage namespaces associated with an
// account, pagination information, and an embedded response struct
type ListWorkersKVNamespacesResponse struct {
Response
Result []WorkersKVNamespace `json:"result"`
ResultInfo `json:"result_info"`
}
// StorageKey is a key name used to identify a storage value
type StorageKey struct {
Name string `json:"name"`
}
// ListStorageKeysResponse contains a slice of keys belonging to a storage namespace,
// pagination information, and an embedded response struct
type ListStorageKeysResponse struct {
Response
Result []StorageKey `json:"result"`
ResultInfo `json:"result_info"`
}
// CreateWorkersKVNamespace creates a namespace under the given title.
// A 400 is returned if the account already owns a namespace with this title.
// A namespace must be explicitly deleted to be replaced.
//
// API reference: https://api.cloudflare.com/#workers-kv-namespace-create-a-namespace
func (api *API) CreateWorkersKVNamespace(ctx context.Context, req *WorkersKVNamespaceRequest) (WorkersKVNamespaceResponse, error) {
uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces", api.OrganizationID)
res, err := api.makeRequestContext(ctx, http.MethodPost, uri, req)
if err != nil {
return WorkersKVNamespaceResponse{}, errors.Wrap(err, errMakeRequestError)
}
result := WorkersKVNamespaceResponse{}
if err := json.Unmarshal(res, &result); err != nil {
return result, errors.Wrap(err, errUnmarshalError)
}
return result, err
}
// ListWorkersKVNamespaces lists storage namespaces
//
// API reference: https://api.cloudflare.com/#workers-kv-namespace-list-namespaces
func (api *API) ListWorkersKVNamespaces(ctx context.Context) (ListWorkersKVNamespacesResponse, error) {
uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces", api.OrganizationID)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return ListWorkersKVNamespacesResponse{}, errors.Wrap(err, errMakeRequestError)
}
result := ListWorkersKVNamespacesResponse{}
if err := json.Unmarshal(res, &result); err != nil {
return result, errors.Wrap(err, errUnmarshalError)
}
return result, err
}
// DeleteWorkersKVNamespace deletes the namespace corresponding to the given ID
//
// API reference: https://api.cloudflare.com/#workers-kv-namespace-remove-a-namespace
func (api *API) DeleteWorkersKVNamespace(ctx context.Context, namespaceID string) (Response, error) {
uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s", api.OrganizationID, namespaceID)
res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
if err != nil {
return Response{}, errors.Wrap(err, errMakeRequestError)
}
result := Response{}
if err := json.Unmarshal(res, &result); err != nil {
return result, errors.Wrap(err, errUnmarshalError)
}
return result, err
}
// UpdateWorkersKVNamespace modifies a namespace's title
//
// API reference: https://api.cloudflare.com/#workers-kv-namespace-rename-a-namespace
func (api *API) UpdateWorkersKVNamespace(ctx context.Context, namespaceID string, req *WorkersKVNamespaceRequest) (Response, error) {
uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s", api.OrganizationID, namespaceID)
res, err := api.makeRequestContext(ctx, http.MethodPut, uri, req)
if err != nil {
return Response{}, errors.Wrap(err, errMakeRequestError)
}
result := Response{}
if err := json.Unmarshal(res, &result); err != nil {
return result, errors.Wrap(err, errUnmarshalError)
}
return result, err
}
// WriteWorkersKV writes a value identified by a key.
//
// API reference: https://api.cloudflare.com/#workers-kv-namespace-write-key-value-pair
func (api *API) WriteWorkersKV(ctx context.Context, namespaceID, key string, value []byte) (Response, error) {
key = url.PathEscape(key)
uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s/values/%s", api.OrganizationID, namespaceID, key)
res, err := api.makeRequestWithAuthTypeAndHeaders(
ctx, http.MethodPut, uri, value, api.authType, http.Header{"Content-Type": []string{"application/octet-stream"}},
)
if err != nil {
return Response{}, errors.Wrap(err, errMakeRequestError)
}
result := Response{}
if err := json.Unmarshal(res, &result); err != nil {
return result, errors.Wrap(err, errUnmarshalError)
}
return result, err
}
// ReadWorkersKV returns the value associated with the given key in the given namespace
//
// API reference: https://api.cloudflare.com/#workers-kv-namespace-read-key-value-pair
func (api API) ReadWorkersKV(ctx context.Context, namespaceID, key string) ([]byte, error) {
key = url.PathEscape(key)
uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s/values/%s", api.OrganizationID, namespaceID, key)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, errors.Wrap(err, errMakeRequestError)
}
return res, nil
}
// DeleteWorkersKV deletes a key and value for a provided storage namespace
//
// API reference: https://api.cloudflare.com/#workers-kv-namespace-delete-key-value-pair
func (api API) DeleteWorkersKV(ctx context.Context, namespaceID, key string) (Response, error) {
key = url.PathEscape(key)
uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s/values/%s", api.OrganizationID, namespaceID, key)
res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
if err != nil {
return Response{}, errors.Wrap(err, errMakeRequestError)
}
result := Response{}
if err := json.Unmarshal(res, &result); err != nil {
return result, errors.Wrap(err, errUnmarshalError)
}
return result, err
}
// ListWorkersKVs lists a namespace's keys
//
// API Reference: https://api.cloudflare.com/#workers-kv-namespace-list-a-namespace-s-keys
func (api API) ListWorkersKVs(ctx context.Context, namespaceID string) (ListStorageKeysResponse, error) {
uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s/keys", api.OrganizationID, namespaceID)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return ListStorageKeysResponse{}, errors.Wrap(err, errMakeRequestError)
}
result := ListStorageKeysResponse{}
if err := json.Unmarshal(res, &result); err != nil {
return result, errors.Wrap(err, errUnmarshalError)
}
return result, err
}

View File

@@ -1,9 +1,11 @@
package cloudflare
import (
"context"
"encoding/json"
"fmt"
"net/url"
"sync"
"time"
"github.com/pkg/errors"
@@ -13,7 +15,8 @@ import (
type Owner struct {
ID string `json:"id"`
Email string `json:"email"`
OwnerType string `json:"owner_type"`
Name string `json:"name"`
OwnerType string `json:"type"`
}
// Zone describes a Cloudflare zone.
@@ -22,20 +25,20 @@ type Zone struct {
Name string `json:"name"`
// DevMode contains the time in seconds until development expires (if
// positive) or since it expired (if negative). It will be 0 if never used.
DevMode int `json:"development_mode"`
OriginalNS []string `json:"original_name_servers"`
OriginalRegistrar string `json:"original_registrar"`
OriginalDNSHost string `json:"original_dnshost"`
CreatedOn time.Time `json:"created_on"`
ModifiedOn time.Time `json:"modified_on"`
NameServers []string `json:"name_servers"`
Owner Owner `json:"owner"`
Permissions []string `json:"permissions"`
Plan ZoneRatePlan `json:"plan"`
PlanPending ZoneRatePlan `json:"plan_pending,omitempty"`
Status string `json:"status"`
Paused bool `json:"paused"`
Type string `json:"type"`
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
@@ -44,6 +47,7 @@ type Zone struct {
Betas []string `json:"betas"`
DeactReason string `json:"deactivation_reason"`
Meta ZoneMeta `json:"meta"`
Account Account `json:"account"`
}
// ZoneMeta describes metadata about a zone.
@@ -55,17 +59,31 @@ type ZoneMeta struct {
PhishingDetected bool `json:"phishing_detected"`
}
// ZonePlan contains the plan information for a zone.
type ZonePlan struct {
ZonePlanCommon
IsSubscribed bool `json:"is_subscribed"`
CanSubscribe bool `json:"can_subscribe"`
LegacyID string `json:"legacy_id"`
LegacyDiscount bool `json:"legacy_discount"`
ExternallyManaged bool `json:"externally_managed"`
}
// ZoneRatePlan contains the plan information for a zone.
type ZoneRatePlan struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Price int `json:"price,omitempty"`
Currency string `json:"currency,omitempty"`
Duration int `json:"duration,omitempty"`
Frequency string `json:"frequency,omitempty"`
ZonePlanCommon
Components []zoneRatePlanComponents `json:"components,omitempty"`
}
// ZonePlanCommon contains fields used by various Plan endpoints
type ZonePlanCommon 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"`
}
type zoneRatePlanComponents struct {
Name string `json:"name"`
Default int `json:"Default"`
@@ -86,7 +104,8 @@ type ZoneResponse struct {
// ZonesResponse represents the response from the Zone endpoint containing an array of zones.
type ZonesResponse struct {
Response
Result []Zone `json:"result"`
Result []Zone `json:"result"`
ResultInfo `json:"result_info"`
}
// ZoneIDResponse represents the response from the Zone endpoint, containing only a zone ID.
@@ -98,7 +117,14 @@ type ZoneIDResponse struct {
// AvailableZoneRatePlansResponse represents the response from the Available Rate Plans endpoint.
type AvailableZoneRatePlansResponse struct {
Response
Result []ZoneRatePlan `json:"result"`
Result []ZoneRatePlan `json:"result"`
ResultInfo `json:"result_info"`
}
// AvailableZonePlansResponse represents the response from the Available Plans endpoint.
type AvailableZonePlansResponse struct {
Response
Result []ZonePlan `json:"result"`
ResultInfo
}
@@ -132,7 +158,8 @@ type ZoneSSLSetting struct {
CertificateStatus string `json:"certificate_status"`
}
// ZoneSettingResponse represents the response from the Zone SSL Setting endpoint.
// ZoneSSLSettingResponse represents the response from the Zone SSL Setting
// endpoint.
type ZoneSSLSettingResponse struct {
Response
Result ZoneSSLSetting `json:"result"`
@@ -235,6 +262,7 @@ type PurgeCacheResponse struct {
type newZone struct {
Name string `json:"name"`
JumpStart bool `json:"jump_start"`
Type string `json:"type"`
// 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"`
@@ -249,7 +277,7 @@ type newZone struct {
// This will add the new zone to the specified multi-user organization.
//
// API reference: https://api.cloudflare.com/#zone-create-a-zone
func (api *API) CreateZone(name string, jumpstart bool, org Organization) (Zone, error) {
func (api *API) CreateZone(name string, jumpstart bool, org Organization, zoneType string) (Zone, error) {
var newzone newZone
newzone.Name = name
newzone.JumpStart = jumpstart
@@ -257,6 +285,12 @@ func (api *API) CreateZone(name string, jumpstart bool, org Organization) (Zone,
newzone.Organization = &org
}
if zoneType == "partial" {
newzone.Type = "partial"
} else {
newzone.Type = "full"
}
res, err := api.makeRequest("POST", "/zones", newzone)
if err != nil {
return Zone{}, errors.Wrap(err, errMakeRequestError)
@@ -316,10 +350,7 @@ func (api *API) ListZones(z ...string) ([]Zone, error) {
}
}
} 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)
res, err = api.makeRequest("GET", "/zones?per_page=50", nil)
if err != nil {
return []Zone{}, errors.Wrap(err, errMakeRequestError)
}
@@ -327,12 +358,67 @@ func (api *API) ListZones(z ...string) ([]Zone, error) {
if err != nil {
return []Zone{}, errors.Wrap(err, errUnmarshalError)
}
zones = r.Result
totalPageCount := r.TotalPages
var wg sync.WaitGroup
wg.Add(totalPageCount)
errc := make(chan error)
for i := 1; i <= totalPageCount; i++ {
go func(pageNumber int) error {
res, err = api.makeRequest("GET", fmt.Sprintf("/zones?per_page=50&page=%d", pageNumber), nil)
if err != nil {
errc <- err
}
err = json.Unmarshal(res, &r)
if err != nil {
errc <- err
}
for _, zone := range r.Result {
zones = append(zones, zone)
}
select {
case err := <-errc:
return err
default:
wg.Done()
}
return nil
}(i)
}
wg.Wait()
}
return zones, nil
}
// ListZonesContext lists zones on an account. Optionally takes a list of ReqOptions.
func (api *API) ListZonesContext(ctx context.Context, opts ...ReqOption) (r ZonesResponse, err error) {
var res []byte
opt := reqOption{
params: url.Values{},
}
for _, of := range opts {
of(&opt)
}
res, err = api.makeRequestContext(ctx, "GET", "/zones?"+opt.params.Encode(), nil)
if err != nil {
return ZonesResponse{}, errors.Wrap(err, errMakeRequestError)
}
err = json.Unmarshal(res, &r)
if err != nil {
return ZonesResponse{}, errors.Wrap(err, errUnmarshalError)
}
return r, nil
}
// ZoneDetails fetches information about a zone.
//
// API reference: https://api.cloudflare.com/#zone-zone-details
@@ -351,9 +437,9 @@ func (api *API) ZoneDetails(zoneID string) (Zone, error) {
// ZoneOptions is a subset of Zone, for editable options.
type ZoneOptions struct {
Paused *bool `json:"paused,omitempty"`
VanityNS []string `json:"vanity_name_servers,omitempty"`
Plan *ZoneRatePlan `json:"plan,omitempty"`
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
@@ -380,8 +466,8 @@ func (api *API) ZoneSetVanityNS(zoneID string, ns []string) (Zone, error) {
return zone, nil
}
// ZoneSetRatePlan changes the zone plan.
func (api *API) ZoneSetRatePlan(zoneID string, plan ZoneRatePlan) (Zone, error) {
// 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 {
@@ -418,7 +504,7 @@ func (api *API) EditZone(zoneID string, zoneOpts ZoneOptions) (Zone, error) {
// API reference: https://api.cloudflare.com/#zone-purge-all-files
func (api *API) PurgeEverything(zoneID string) (PurgeCacheResponse, error) {
uri := "/zones/" + zoneID + "/purge_cache"
res, err := api.makeRequest("DELETE", uri, PurgeCacheRequest{true, nil, nil, nil})
res, err := api.makeRequest("POST", uri, PurgeCacheRequest{true, nil, nil, nil})
if err != nil {
return PurgeCacheResponse{}, errors.Wrap(err, errMakeRequestError)
}
@@ -435,7 +521,7 @@ func (api *API) PurgeEverything(zoneID string) (PurgeCacheResponse, error) {
// 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)
res, err := api.makeRequest("POST", uri, pcr)
if err != nil {
return PurgeCacheResponse{}, errors.Wrap(err, errMakeRequestError)
}
@@ -480,6 +566,23 @@ func (api *API) AvailableZoneRatePlans(zoneID string) ([]ZoneRatePlan, error) {
return r.Result, nil
}
// AvailableZonePlans returns information about all plans available to the specified zone.
//
// API reference: https://api.cloudflare.com/#zone-rate-plan-list-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
}
// encode encodes non-nil fields into URL encoded form.
func (o ZoneAnalyticsOptions) encode() string {
v := url.Values{}