1package cloudflare 2 3import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "net/url" 9 "strconv" 10 "time" 11 12 "github.com/pkg/errors" 13) 14 15// FirewallRule is the struct of the firewall rule. 16type FirewallRule struct { 17 ID string `json:"id,omitempty"` 18 Paused bool `json:"paused"` 19 Description string `json:"description"` 20 Action string `json:"action"` 21 Priority interface{} `json:"priority"` 22 Filter Filter `json:"filter"` 23 Products []string `json:"products,omitempty"` 24 CreatedOn time.Time `json:"created_on,omitempty"` 25 ModifiedOn time.Time `json:"modified_on,omitempty"` 26} 27 28// FirewallRulesDetailResponse is the API response for the firewall 29// rules. 30type FirewallRulesDetailResponse struct { 31 Result []FirewallRule `json:"result"` 32 ResultInfo `json:"result_info"` 33 Response 34} 35 36// FirewallRuleResponse is the API response that is returned 37// for requesting a single firewall rule on a zone. 38type FirewallRuleResponse struct { 39 Result FirewallRule `json:"result"` 40 ResultInfo `json:"result_info"` 41 Response 42} 43 44// FirewallRules returns all firewall rules. 45// 46// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/get/#get-all-rules 47func (api *API) FirewallRules(ctx context.Context, zoneID string, pageOpts PaginationOptions) ([]FirewallRule, error) { 48 uri := fmt.Sprintf("/zones/%s/firewall/rules", zoneID) 49 v := url.Values{} 50 51 if pageOpts.PerPage > 0 { 52 v.Set("per_page", strconv.Itoa(pageOpts.PerPage)) 53 } 54 55 if pageOpts.Page > 0 { 56 v.Set("page", strconv.Itoa(pageOpts.Page)) 57 } 58 59 if len(v) > 0 { 60 uri = fmt.Sprintf("%s?%s", uri, v.Encode()) 61 } 62 63 res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) 64 if err != nil { 65 return []FirewallRule{}, err 66 } 67 68 var firewallDetailResponse FirewallRulesDetailResponse 69 err = json.Unmarshal(res, &firewallDetailResponse) 70 if err != nil { 71 return []FirewallRule{}, errors.Wrap(err, errUnmarshalError) 72 } 73 74 return firewallDetailResponse.Result, nil 75} 76 77// FirewallRule returns a single firewall rule based on the ID. 78// 79// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/get/#get-by-rule-id 80func (api *API) FirewallRule(ctx context.Context, zoneID, firewallRuleID string) (FirewallRule, error) { 81 uri := fmt.Sprintf("/zones/%s/firewall/rules/%s", zoneID, firewallRuleID) 82 83 res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) 84 if err != nil { 85 return FirewallRule{}, err 86 } 87 88 var firewallRuleResponse FirewallRuleResponse 89 err = json.Unmarshal(res, &firewallRuleResponse) 90 if err != nil { 91 return FirewallRule{}, errors.Wrap(err, errUnmarshalError) 92 } 93 94 return firewallRuleResponse.Result, nil 95} 96 97// CreateFirewallRules creates new firewall rules. 98// 99// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/post/ 100func (api *API) CreateFirewallRules(ctx context.Context, zoneID string, firewallRules []FirewallRule) ([]FirewallRule, error) { 101 uri := fmt.Sprintf("/zones/%s/firewall/rules", zoneID) 102 103 res, err := api.makeRequestContext(ctx, http.MethodPost, uri, firewallRules) 104 if err != nil { 105 return []FirewallRule{}, err 106 } 107 108 var firewallRulesDetailResponse FirewallRulesDetailResponse 109 err = json.Unmarshal(res, &firewallRulesDetailResponse) 110 if err != nil { 111 return []FirewallRule{}, errors.Wrap(err, errUnmarshalError) 112 } 113 114 return firewallRulesDetailResponse.Result, nil 115} 116 117// UpdateFirewallRule updates a single firewall rule. 118// 119// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/put/#update-a-single-rule 120func (api *API) UpdateFirewallRule(ctx context.Context, zoneID string, firewallRule FirewallRule) (FirewallRule, error) { 121 if firewallRule.ID == "" { 122 return FirewallRule{}, errors.Errorf("firewall rule ID cannot be empty") 123 } 124 125 uri := fmt.Sprintf("/zones/%s/firewall/rules/%s", zoneID, firewallRule.ID) 126 127 res, err := api.makeRequestContext(ctx, http.MethodPut, uri, firewallRule) 128 if err != nil { 129 return FirewallRule{}, err 130 } 131 132 var firewallRuleResponse FirewallRuleResponse 133 err = json.Unmarshal(res, &firewallRuleResponse) 134 if err != nil { 135 return FirewallRule{}, errors.Wrap(err, errUnmarshalError) 136 } 137 138 return firewallRuleResponse.Result, nil 139} 140 141// UpdateFirewallRules updates a single firewall rule. 142// 143// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/put/#update-multiple-rules 144func (api *API) UpdateFirewallRules(ctx context.Context, zoneID string, firewallRules []FirewallRule) ([]FirewallRule, error) { 145 for _, firewallRule := range firewallRules { 146 if firewallRule.ID == "" { 147 return []FirewallRule{}, errors.Errorf("firewall ID cannot be empty") 148 } 149 } 150 151 uri := fmt.Sprintf("/zones/%s/firewall/rules", zoneID) 152 153 res, err := api.makeRequestContext(ctx, http.MethodPut, uri, firewallRules) 154 if err != nil { 155 return []FirewallRule{}, err 156 } 157 158 var firewallRulesDetailResponse FirewallRulesDetailResponse 159 err = json.Unmarshal(res, &firewallRulesDetailResponse) 160 if err != nil { 161 return []FirewallRule{}, errors.Wrap(err, errUnmarshalError) 162 } 163 164 return firewallRulesDetailResponse.Result, nil 165} 166 167// DeleteFirewallRule deletes a single firewall rule. 168// 169// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/delete/#delete-a-single-rule 170func (api *API) DeleteFirewallRule(ctx context.Context, zoneID, firewallRuleID string) error { 171 if firewallRuleID == "" { 172 return errors.Errorf("firewall rule ID cannot be empty") 173 } 174 175 uri := fmt.Sprintf("/zones/%s/firewall/rules/%s", zoneID, firewallRuleID) 176 177 _, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) 178 if err != nil { 179 return err 180 } 181 182 return nil 183} 184 185// DeleteFirewallRules deletes multiple firewall rules at once. 186// 187// API reference: https://developers.cloudflare.com/firewall/api/cf-firewall-rules/delete/#delete-multiple-rules 188func (api *API) DeleteFirewallRules(ctx context.Context, zoneID string, firewallRuleIDs []string) error { 189 v := url.Values{} 190 191 for _, ruleID := range firewallRuleIDs { 192 v.Add("id", ruleID) 193 } 194 195 uri := fmt.Sprintf("/zones/%s/firewall/rules?%s", zoneID, v.Encode()) 196 197 _, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) 198 if err != nil { 199 return err 200 } 201 202 return nil 203} 204