diff --git a/.stats.yml b/.stats.yml index 9b61bc29c92..113bc58883c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 1380 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-9c8ad1b8591db7a88106030eb20c396404f23056d1fe47ae2ae322923872606f.yml +configured_endpoints: 1416 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3f87896b62cce36e33c03f416ad98add2717ccd78f1743925c160a6c6a67ff15.yml diff --git a/api.md b/api.md index c1d6117f708..0c9f95a0d8c 100644 --- a/api.md +++ b/api.md @@ -1355,12 +1355,66 @@ Methods: # Filters +Params Types: + +- filters.FirewallFilterParam + +Response Types: + +- filters.FirewallFilter + +Methods: + +- client.Filters.New(ctx context.Context, params filters.FilterNewParams) ([]filters.FirewallFilter, error) +- client.Filters.Update(ctx context.Context, filterID string, params filters.FilterUpdateParams) (filters.FirewallFilter, error) +- client.Filters.List(ctx context.Context, params filters.FilterListParams) (pagination.V4PagePaginationArray[filters.FirewallFilter], error) +- client.Filters.Delete(ctx context.Context, filterID string, body filters.FilterDeleteParams) (filters.FirewallFilter, error) +- client.Filters.Get(ctx context.Context, filterID string, query filters.FilterGetParams) (filters.FirewallFilter, error) + # Firewall ## Lockdowns +Params Types: + +- firewall.ConfigurationParam +- firewall.LockdownCIDRConfigurationParam +- firewall.LockdownIPConfigurationParam + +Response Types: + +- firewall.Configuration +- firewall.Lockdown +- firewall.LockdownCIDRConfiguration +- firewall.LockdownIPConfiguration +- firewall.LockdownURL +- firewall.LockdownDeleteResponse + +Methods: + +- client.Firewall.Lockdowns.New(ctx context.Context, params firewall.LockdownNewParams) (firewall.Lockdown, error) +- client.Firewall.Lockdowns.Update(ctx context.Context, lockDownsID string, params firewall.LockdownUpdateParams) (firewall.Lockdown, error) +- client.Firewall.Lockdowns.List(ctx context.Context, params firewall.LockdownListParams) (pagination.V4PagePaginationArray[firewall.Lockdown], error) +- client.Firewall.Lockdowns.Delete(ctx context.Context, lockDownsID string, body firewall.LockdownDeleteParams) (firewall.LockdownDeleteResponse, error) +- client.Firewall.Lockdowns.Get(ctx context.Context, lockDownsID string, query firewall.LockdownGetParams) (firewall.Lockdown, error) + ## Rules +Response Types: + +- firewall.FirewallRule +- firewall.Product +- firewall.DeletedFilter + +Methods: + +- client.Firewall.Rules.New(ctx context.Context, params firewall.RuleNewParams) ([]firewall.FirewallRule, error) +- client.Firewall.Rules.Update(ctx context.Context, ruleID string, params firewall.RuleUpdateParams) (firewall.FirewallRule, error) +- client.Firewall.Rules.List(ctx context.Context, params firewall.RuleListParams) (pagination.V4PagePaginationArray[firewall.FirewallRule], error) +- client.Firewall.Rules.Delete(ctx context.Context, ruleID string, body firewall.RuleDeleteParams) (firewall.FirewallRule, error) +- client.Firewall.Rules.Edit(ctx context.Context, ruleID string, body firewall.RuleEditParams) ([]firewall.FirewallRule, error) +- client.Firewall.Rules.Get(ctx context.Context, ruleID string, params firewall.RuleGetParams) (firewall.FirewallRule, error) + ## AccessRules Params Types: @@ -1373,21 +1427,78 @@ Params Types: Response Types: +- firewall.AccessRuleCIDRConfiguration +- firewall.AccessRuleIPConfiguration +- firewall.ASNConfiguration +- firewall.CountryConfiguration +- firewall.IPV6Configuration +- firewall.AccessRuleNewResponse - firewall.AccessRuleListResponse +- firewall.AccessRuleDeleteResponse +- firewall.AccessRuleEditResponse +- firewall.AccessRuleGetResponse Methods: -- client.Firewall.AccessRules.New(ctx context.Context, params firewall.AccessRuleNewParams) (interface{}, error) +- client.Firewall.AccessRules.New(ctx context.Context, params firewall.AccessRuleNewParams) (firewall.AccessRuleNewResponse, error) - client.Firewall.AccessRules.List(ctx context.Context, params firewall.AccessRuleListParams) (pagination.V4PagePaginationArray[firewall.AccessRuleListResponse], error) +- client.Firewall.AccessRules.Delete(ctx context.Context, ruleID string, body firewall.AccessRuleDeleteParams) (firewall.AccessRuleDeleteResponse, error) +- client.Firewall.AccessRules.Edit(ctx context.Context, ruleID string, params firewall.AccessRuleEditParams) (firewall.AccessRuleEditResponse, error) +- client.Firewall.AccessRules.Get(ctx context.Context, ruleID string, query firewall.AccessRuleGetParams) (firewall.AccessRuleGetResponse, error) ## UARules +Response Types: + +- firewall.UARuleListResponse +- firewall.UARuleDeleteResponse + +Methods: + +- client.Firewall.UARules.New(ctx context.Context, params firewall.UARuleNewParams) (interface{}, error) +- client.Firewall.UARules.Update(ctx context.Context, uaRuleID string, params firewall.UARuleUpdateParams) (interface{}, error) +- client.Firewall.UARules.List(ctx context.Context, params firewall.UARuleListParams) (pagination.V4PagePaginationArray[firewall.UARuleListResponse], error) +- client.Firewall.UARules.Delete(ctx context.Context, uaRuleID string, body firewall.UARuleDeleteParams) (firewall.UARuleDeleteResponse, error) +- client.Firewall.UARules.Get(ctx context.Context, uaRuleID string, query firewall.UARuleGetParams) (interface{}, error) + ## WAF ### Overrides +Params Types: + +- firewall.OverrideURLParam +- firewall.RewriteActionParam +- firewall.WAFRuleParam + +Response Types: + +- firewall.Override +- firewall.OverrideURL +- firewall.RewriteAction +- firewall.WAFRule +- firewall.WAFOverrideDeleteResponse + +Methods: + +- client.Firewall.WAF.Overrides.New(ctx context.Context, params firewall.WAFOverrideNewParams) (firewall.Override, error) +- client.Firewall.WAF.Overrides.Update(ctx context.Context, overridesID string, params firewall.WAFOverrideUpdateParams) (firewall.Override, error) +- client.Firewall.WAF.Overrides.List(ctx context.Context, params firewall.WAFOverrideListParams) (pagination.V4PagePaginationArray[firewall.Override], error) +- client.Firewall.WAF.Overrides.Delete(ctx context.Context, overridesID string, body firewall.WAFOverrideDeleteParams) (firewall.WAFOverrideDeleteResponse, error) +- client.Firewall.WAF.Overrides.Get(ctx context.Context, overridesID string, query firewall.WAFOverrideGetParams) (firewall.Override, error) + ### Packages +Response Types: + +- firewall.WAFPackageListResponse +- firewall.WAFPackageGetResponse + +Methods: + +- client.Firewall.WAF.Packages.List(ctx context.Context, params firewall.WAFPackageListParams) (pagination.V4PagePaginationArray[firewall.WAFPackageListResponse], error) +- client.Firewall.WAF.Packages.Get(ctx context.Context, packageID string, query firewall.WAFPackageGetParams) (firewall.WAFPackageGetResponse, error) + #### Groups Response Types: @@ -1691,6 +1802,25 @@ Methods: # RateLimits +Params Types: + +- rate_limits.Methods + +Response Types: + +- rate_limits.Action +- rate_limits.Methods +- rate_limits.RateLimit +- rate_limits.RateLimitDeleteResponse + +Methods: + +- client.RateLimits.New(ctx context.Context, params rate_limits.RateLimitNewParams) (rate_limits.RateLimit, error) +- client.RateLimits.List(ctx context.Context, params rate_limits.RateLimitListParams) (pagination.V4PagePaginationArray[rate_limits.RateLimit], error) +- client.RateLimits.Delete(ctx context.Context, rateLimitID string, body rate_limits.RateLimitDeleteParams) (rate_limits.RateLimitDeleteResponse, error) +- client.RateLimits.Edit(ctx context.Context, rateLimitID string, params rate_limits.RateLimitEditParams) (rate_limits.RateLimit, error) +- client.RateLimits.Get(ctx context.Context, rateLimitID string, query rate_limits.RateLimitGetParams) (rate_limits.RateLimit, error) + # SecondaryDNS ## ForceAXFR diff --git a/filters/filter.go b/filters/filter.go index 755b9c87d8f..095a57a18f6 100644 --- a/filters/filter.go +++ b/filters/filter.go @@ -3,7 +3,19 @@ package filters import ( + "context" + "errors" + "fmt" + "net/http" + "net/url" + + "github.com/cloudflare/cloudflare-go/v3/internal/apijson" + "github.com/cloudflare/cloudflare-go/v3/internal/apiquery" + "github.com/cloudflare/cloudflare-go/v3/internal/param" + "github.com/cloudflare/cloudflare-go/v3/internal/requestconfig" "github.com/cloudflare/cloudflare-go/v3/option" + "github.com/cloudflare/cloudflare-go/v3/packages/pagination" + "github.com/cloudflare/cloudflare-go/v3/shared" ) // FilterService contains methods and other services that help with interacting @@ -24,3 +36,458 @@ func NewFilterService(opts ...option.RequestOption) (r *FilterService) { r.Options = opts return } + +// Creates one or more filters. +// +// Deprecated: The Filters API is deprecated in favour of using the Ruleset Engine. +// See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *FilterService) New(ctx context.Context, params FilterNewParams, opts ...option.RequestOption) (res *[]FirewallFilter, err error) { + var env FilterNewResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/filters", params.ZoneID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Updates an existing filter. +// +// Deprecated: The Filters API is deprecated in favour of using the Ruleset Engine. +// See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *FilterService) Update(ctx context.Context, filterID string, params FilterUpdateParams, opts ...option.RequestOption) (res *FirewallFilter, err error) { + var env FilterUpdateResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if filterID == "" { + err = errors.New("missing required filter_id parameter") + return + } + path := fmt.Sprintf("zones/%s/filters/%s", params.ZoneID, filterID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches filters in a zone. You can filter the results using several optional +// parameters. +// +// Deprecated: The Filters API is deprecated in favour of using the Ruleset Engine. +// See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *FilterService) List(ctx context.Context, params FilterListParams, opts ...option.RequestOption) (res *pagination.V4PagePaginationArray[FirewallFilter], err error) { + var raw *http.Response + opts = append(r.Options[:], opts...) + opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/filters", params.ZoneID) + cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...) + if err != nil { + return nil, err + } + err = cfg.Execute() + if err != nil { + return nil, err + } + res.SetPageConfig(cfg, raw) + return res, nil +} + +// Fetches filters in a zone. You can filter the results using several optional +// parameters. +// +// Deprecated: The Filters API is deprecated in favour of using the Ruleset Engine. +// See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *FilterService) ListAutoPaging(ctx context.Context, params FilterListParams, opts ...option.RequestOption) *pagination.V4PagePaginationArrayAutoPager[FirewallFilter] { + return pagination.NewV4PagePaginationArrayAutoPager(r.List(ctx, params, opts...)) +} + +// Deletes an existing filter. +// +// Deprecated: The Filters API is deprecated in favour of using the Ruleset Engine. +// See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *FilterService) Delete(ctx context.Context, filterID string, body FilterDeleteParams, opts ...option.RequestOption) (res *FirewallFilter, err error) { + var env FilterDeleteResponseEnvelope + opts = append(r.Options[:], opts...) + if body.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if filterID == "" { + err = errors.New("missing required filter_id parameter") + return + } + path := fmt.Sprintf("zones/%s/filters/%s", body.ZoneID, filterID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches the details of a filter. +// +// Deprecated: The Filters API is deprecated in favour of using the Ruleset Engine. +// See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *FilterService) Get(ctx context.Context, filterID string, query FilterGetParams, opts ...option.RequestOption) (res *FirewallFilter, err error) { + var env FilterGetResponseEnvelope + opts = append(r.Options[:], opts...) + if query.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if filterID == "" { + err = errors.New("missing required filter_id parameter") + return + } + path := fmt.Sprintf("zones/%s/filters/%s", query.ZoneID, filterID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +type FirewallFilter struct { + // The unique identifier of the filter. + ID string `json:"id"` + // An informative summary of the filter. + Description string `json:"description"` + // The filter expression. For more information, refer to + // [Expressions](https://developers.cloudflare.com/ruleset-engine/rules-language/expressions/). + Expression string `json:"expression"` + // When true, indicates that the filter is currently paused. + Paused bool `json:"paused"` + // A short reference tag. Allows you to select related filters. + Ref string `json:"ref"` + JSON firewallFilterJSON `json:"-"` +} + +// firewallFilterJSON contains the JSON metadata for the struct [FirewallFilter] +type firewallFilterJSON struct { + ID apijson.Field + Description apijson.Field + Expression apijson.Field + Paused apijson.Field + Ref apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *FirewallFilter) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r firewallFilterJSON) RawJSON() string { + return r.raw +} + +func (r FirewallFilter) ImplementsFirewallFirewallRuleFilter() {} + +type FirewallFilterParam struct { + // An informative summary of the filter. + Description param.Field[string] `json:"description"` + // The filter expression. For more information, refer to + // [Expressions](https://developers.cloudflare.com/ruleset-engine/rules-language/expressions/). + Expression param.Field[string] `json:"expression"` + // When true, indicates that the filter is currently paused. + Paused param.Field[bool] `json:"paused"` + // A short reference tag. Allows you to select related filters. + Ref param.Field[string] `json:"ref"` +} + +func (r FirewallFilterParam) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type FilterNewParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The filter expression. For more information, refer to + // [Expressions](https://developers.cloudflare.com/ruleset-engine/rules-language/expressions/). + Expression param.Field[string] `json:"expression,required"` +} + +func (r FilterNewParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type FilterNewResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result []FirewallFilter `json:"result,required,nullable"` + // Whether the API call was successful + Success FilterNewResponseEnvelopeSuccess `json:"success,required"` + ResultInfo FilterNewResponseEnvelopeResultInfo `json:"result_info"` + JSON filterNewResponseEnvelopeJSON `json:"-"` +} + +// filterNewResponseEnvelopeJSON contains the JSON metadata for the struct +// [FilterNewResponseEnvelope] +type filterNewResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + ResultInfo apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *FilterNewResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r filterNewResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type FilterNewResponseEnvelopeSuccess bool + +const ( + FilterNewResponseEnvelopeSuccessTrue FilterNewResponseEnvelopeSuccess = true +) + +func (r FilterNewResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case FilterNewResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type FilterNewResponseEnvelopeResultInfo struct { + // Total number of results for the requested service + Count float64 `json:"count"` + // Current page within paginated list of results + Page float64 `json:"page"` + // Number of results per page of results + PerPage float64 `json:"per_page"` + // Total results available without any search parameters + TotalCount float64 `json:"total_count"` + JSON filterNewResponseEnvelopeResultInfoJSON `json:"-"` +} + +// filterNewResponseEnvelopeResultInfoJSON contains the JSON metadata for the +// struct [FilterNewResponseEnvelopeResultInfo] +type filterNewResponseEnvelopeResultInfoJSON struct { + Count apijson.Field + Page apijson.Field + PerPage apijson.Field + TotalCount apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *FilterNewResponseEnvelopeResultInfo) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r filterNewResponseEnvelopeResultInfoJSON) RawJSON() string { + return r.raw +} + +type FilterUpdateParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + Body interface{} `json:"body,required"` +} + +func (r FilterUpdateParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r.Body) +} + +type FilterUpdateResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result FirewallFilter `json:"result,required"` + // Whether the API call was successful + Success FilterUpdateResponseEnvelopeSuccess `json:"success,required"` + JSON filterUpdateResponseEnvelopeJSON `json:"-"` +} + +// filterUpdateResponseEnvelopeJSON contains the JSON metadata for the struct +// [FilterUpdateResponseEnvelope] +type filterUpdateResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *FilterUpdateResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r filterUpdateResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type FilterUpdateResponseEnvelopeSuccess bool + +const ( + FilterUpdateResponseEnvelopeSuccessTrue FilterUpdateResponseEnvelopeSuccess = true +) + +func (r FilterUpdateResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case FilterUpdateResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type FilterListParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The unique identifier of the filter. + ID param.Field[string] `query:"id"` + // A case-insensitive string to find in the description. + Description param.Field[string] `query:"description"` + // A case-insensitive string to find in the expression. + Expression param.Field[string] `query:"expression"` + // Page number of paginated results. + Page param.Field[float64] `query:"page"` + // When true, indicates that the filter is currently paused. + Paused param.Field[bool] `query:"paused"` + // Number of filters per page. + PerPage param.Field[float64] `query:"per_page"` + // The filter ref (a short reference tag) to search for. Must be an exact match. + Ref param.Field[string] `query:"ref"` +} + +// URLQuery serializes [FilterListParams]'s query parameters as `url.Values`. +func (r FilterListParams) URLQuery() (v url.Values) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatRepeat, + NestedFormat: apiquery.NestedQueryFormatDots, + }) +} + +type FilterDeleteParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} + +type FilterDeleteResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result FirewallFilter `json:"result,required"` + // Whether the API call was successful + Success FilterDeleteResponseEnvelopeSuccess `json:"success,required"` + JSON filterDeleteResponseEnvelopeJSON `json:"-"` +} + +// filterDeleteResponseEnvelopeJSON contains the JSON metadata for the struct +// [FilterDeleteResponseEnvelope] +type filterDeleteResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *FilterDeleteResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r filterDeleteResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type FilterDeleteResponseEnvelopeSuccess bool + +const ( + FilterDeleteResponseEnvelopeSuccessTrue FilterDeleteResponseEnvelopeSuccess = true +) + +func (r FilterDeleteResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case FilterDeleteResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type FilterGetParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} + +type FilterGetResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result FirewallFilter `json:"result,required"` + // Whether the API call was successful + Success FilterGetResponseEnvelopeSuccess `json:"success,required"` + JSON filterGetResponseEnvelopeJSON `json:"-"` +} + +// filterGetResponseEnvelopeJSON contains the JSON metadata for the struct +// [FilterGetResponseEnvelope] +type filterGetResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *FilterGetResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r filterGetResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type FilterGetResponseEnvelopeSuccess bool + +const ( + FilterGetResponseEnvelopeSuccessTrue FilterGetResponseEnvelopeSuccess = true +) + +func (r FilterGetResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case FilterGetResponseEnvelopeSuccessTrue: + return true + } + return false +} diff --git a/filters/filter_test.go b/filters/filter_test.go new file mode 100644 index 00000000000..9b5cc5118f6 --- /dev/null +++ b/filters/filter_test.go @@ -0,0 +1,163 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package filters_test + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/cloudflare/cloudflare-go/v3" + "github.com/cloudflare/cloudflare-go/v3/filters" + "github.com/cloudflare/cloudflare-go/v3/internal/testutil" + "github.com/cloudflare/cloudflare-go/v3/option" +) + +func TestFilterNew(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Filters.New(context.TODO(), filters.FilterNewParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Expression: cloudflare.F("(http.request.uri.path ~ \".*wp-login.php\" or http.request.uri.path ~ \".*xmlrpc.php\") and ip.addr ne 172.16.22.155"), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestFilterUpdate(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Filters.Update( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b61", + filters.FilterUpdateParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Body: map[string]interface{}{}, + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestFilterListWithOptionalParams(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Filters.List(context.TODO(), filters.FilterListParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + ID: cloudflare.F("372e67954025e0ba6aaa6d586b9e0b61"), + Description: cloudflare.F("browsers"), + Expression: cloudflare.F("php"), + Page: cloudflare.F(1.000000), + Paused: cloudflare.F(false), + PerPage: cloudflare.F(5.000000), + Ref: cloudflare.F("FIL-100"), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestFilterDelete(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Filters.Delete( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b61", + filters.FilterDeleteParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestFilterGet(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Filters.Get( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b61", + filters.FilterGetParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} diff --git a/firewall/accessrule.go b/firewall/accessrule.go index b2e1c5373dd..a032a00d487 100644 --- a/firewall/accessrule.go +++ b/firewall/accessrule.go @@ -8,6 +8,8 @@ import ( "fmt" "net/http" "net/url" + "reflect" + "time" "github.com/cloudflare/cloudflare-go/v3/internal/apijson" "github.com/cloudflare/cloudflare-go/v3/internal/apiquery" @@ -16,6 +18,7 @@ import ( "github.com/cloudflare/cloudflare-go/v3/option" "github.com/cloudflare/cloudflare-go/v3/packages/pagination" "github.com/cloudflare/cloudflare-go/v3/shared" + "github.com/tidwall/gjson" ) // AccessRuleService contains methods and other services that help with interacting @@ -42,7 +45,7 @@ func NewAccessRuleService(opts ...option.RequestOption) (r *AccessRuleService) { // // Note: To create an IP Access rule that applies to a single zone, refer to the // [IP Access rules for a zone](#ip-access-rules-for-a-zone) endpoints. -func (r *AccessRuleService) New(ctx context.Context, params AccessRuleNewParams, opts ...option.RequestOption) (res *interface{}, err error) { +func (r *AccessRuleService) New(ctx context.Context, params AccessRuleNewParams, opts ...option.RequestOption) (res *AccessRuleNewResponse, err error) { var env AccessRuleNewResponseEnvelope opts = append(r.Options[:], opts...) var accountOrZone string @@ -117,6 +120,166 @@ func (r *AccessRuleService) ListAutoPaging(ctx context.Context, params AccessRul return pagination.NewV4PagePaginationArrayAutoPager(r.List(ctx, params, opts...)) } +// Deletes an existing IP Access rule defined. +// +// Note: This operation will affect all zones in the account or zone. +func (r *AccessRuleService) Delete(ctx context.Context, ruleID string, body AccessRuleDeleteParams, opts ...option.RequestOption) (res *AccessRuleDeleteResponse, err error) { + var env AccessRuleDeleteResponseEnvelope + opts = append(r.Options[:], opts...) + var accountOrZone string + var accountOrZoneID param.Field[string] + if body.AccountID.Value != "" && body.ZoneID.Value != "" { + err = errors.New("account ID and zone ID are mutually exclusive") + return + } + if body.AccountID.Value == "" && body.ZoneID.Value == "" { + err = errors.New("either account ID or zone ID must be provided") + return + } + if body.AccountID.Value != "" { + accountOrZone = "accounts" + accountOrZoneID = body.AccountID + } + if body.ZoneID.Value != "" { + accountOrZone = "zones" + accountOrZoneID = body.ZoneID + } + if ruleID == "" { + err = errors.New("missing required rule_id parameter") + return + } + path := fmt.Sprintf("%s/%s/firewall/access_rules/rules/%s", accountOrZone, accountOrZoneID, ruleID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Updates an IP Access rule defined. +// +// Note: This operation will affect all zones in the account or zone. +func (r *AccessRuleService) Edit(ctx context.Context, ruleID string, params AccessRuleEditParams, opts ...option.RequestOption) (res *AccessRuleEditResponse, err error) { + var env AccessRuleEditResponseEnvelope + opts = append(r.Options[:], opts...) + var accountOrZone string + var accountOrZoneID param.Field[string] + if params.AccountID.Value != "" && params.ZoneID.Value != "" { + err = errors.New("account ID and zone ID are mutually exclusive") + return + } + if params.AccountID.Value == "" && params.ZoneID.Value == "" { + err = errors.New("either account ID or zone ID must be provided") + return + } + if params.AccountID.Value != "" { + accountOrZone = "accounts" + accountOrZoneID = params.AccountID + } + if params.ZoneID.Value != "" { + accountOrZone = "zones" + accountOrZoneID = params.ZoneID + } + if ruleID == "" { + err = errors.New("missing required rule_id parameter") + return + } + path := fmt.Sprintf("%s/%s/firewall/access_rules/rules/%s", accountOrZone, accountOrZoneID, ruleID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches the details of an IP Access rule defined. +func (r *AccessRuleService) Get(ctx context.Context, ruleID string, query AccessRuleGetParams, opts ...option.RequestOption) (res *AccessRuleGetResponse, err error) { + var env AccessRuleGetResponseEnvelope + opts = append(r.Options[:], opts...) + var accountOrZone string + var accountOrZoneID param.Field[string] + if query.AccountID.Value != "" && query.ZoneID.Value != "" { + err = errors.New("account ID and zone ID are mutually exclusive") + return + } + if query.AccountID.Value == "" && query.ZoneID.Value == "" { + err = errors.New("either account ID or zone ID must be provided") + return + } + if query.AccountID.Value != "" { + accountOrZone = "accounts" + accountOrZoneID = query.AccountID + } + if query.ZoneID.Value != "" { + accountOrZone = "zones" + accountOrZoneID = query.ZoneID + } + if ruleID == "" { + err = errors.New("missing required rule_id parameter") + return + } + path := fmt.Sprintf("%s/%s/firewall/access_rules/rules/%s", accountOrZone, accountOrZoneID, ruleID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +type AccessRuleCIDRConfiguration struct { + // The configuration target. You must set the target to `ip_range` when specifying + // an IP address range in the rule. + Target AccessRuleCIDRConfigurationTarget `json:"target"` + // The IP address range to match. You can only use prefix lengths `/16` and `/24` + // for IPv4 ranges, and prefix lengths `/32`, `/48`, and `/64` for IPv6 ranges. + Value string `json:"value"` + JSON accessRuleCIDRConfigurationJSON `json:"-"` +} + +// accessRuleCIDRConfigurationJSON contains the JSON metadata for the struct +// [AccessRuleCIDRConfiguration] +type accessRuleCIDRConfigurationJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleCIDRConfiguration) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleCIDRConfigurationJSON) RawJSON() string { + return r.raw +} + +func (r AccessRuleCIDRConfiguration) implementsFirewallAccessRuleNewResponseConfiguration() {} + +func (r AccessRuleCIDRConfiguration) implementsFirewallAccessRuleListResponseConfiguration() {} + +func (r AccessRuleCIDRConfiguration) implementsFirewallAccessRuleEditResponseConfiguration() {} + +func (r AccessRuleCIDRConfiguration) implementsFirewallAccessRuleGetResponseConfiguration() {} + +// The configuration target. You must set the target to `ip_range` when specifying +// an IP address range in the rule. +type AccessRuleCIDRConfigurationTarget string + +const ( + AccessRuleCIDRConfigurationTargetIPRange AccessRuleCIDRConfigurationTarget = "ip_range" +) + +func (r AccessRuleCIDRConfigurationTarget) IsKnown() bool { + switch r { + case AccessRuleCIDRConfigurationTargetIPRange: + return true + } + return false +} + type AccessRuleCIDRConfigurationParam struct { // The configuration target. You must set the target to `ip_range` when specifying // an IP address range in the rule. @@ -130,148 +293,1225 @@ func (r AccessRuleCIDRConfigurationParam) MarshalJSON() (data []byte, err error) return apijson.MarshalRoot(r) } -func (r AccessRuleCIDRConfigurationParam) implementsFirewallAccessRuleNewParamsConfigurationUnion() {} +func (r AccessRuleCIDRConfigurationParam) implementsFirewallAccessRuleNewParamsConfigurationUnion() {} + +func (r AccessRuleCIDRConfigurationParam) implementsFirewallAccessRuleEditParamsConfigurationUnion() { +} + +func (r AccessRuleCIDRConfigurationParam) implementsFirewallUARuleNewParamsConfigurationUnion() {} + +func (r AccessRuleCIDRConfigurationParam) implementsFirewallUARuleUpdateParamsConfigurationUnion() {} + +type AccessRuleIPConfiguration struct { + // The configuration target. You must set the target to `ip` when specifying an IP + // address in the rule. + Target AccessRuleIPConfigurationTarget `json:"target"` + // The IP address to match. This address will be compared to the IP address of + // incoming requests. + Value string `json:"value"` + JSON accessRuleIPConfigurationJSON `json:"-"` +} + +// accessRuleIPConfigurationJSON contains the JSON metadata for the struct +// [AccessRuleIPConfiguration] +type accessRuleIPConfigurationJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleIPConfiguration) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleIPConfigurationJSON) RawJSON() string { + return r.raw +} + +func (r AccessRuleIPConfiguration) implementsFirewallAccessRuleNewResponseConfiguration() {} + +func (r AccessRuleIPConfiguration) implementsFirewallAccessRuleListResponseConfiguration() {} + +func (r AccessRuleIPConfiguration) implementsFirewallAccessRuleEditResponseConfiguration() {} + +func (r AccessRuleIPConfiguration) implementsFirewallAccessRuleGetResponseConfiguration() {} + +// The configuration target. You must set the target to `ip` when specifying an IP +// address in the rule. +type AccessRuleIPConfigurationTarget string + +const ( + AccessRuleIPConfigurationTargetIP AccessRuleIPConfigurationTarget = "ip" +) + +func (r AccessRuleIPConfigurationTarget) IsKnown() bool { + switch r { + case AccessRuleIPConfigurationTargetIP: + return true + } + return false +} + +type AccessRuleIPConfigurationParam struct { + // The configuration target. You must set the target to `ip` when specifying an IP + // address in the rule. + Target param.Field[AccessRuleIPConfigurationTarget] `json:"target"` + // The IP address to match. This address will be compared to the IP address of + // incoming requests. + Value param.Field[string] `json:"value"` +} + +func (r AccessRuleIPConfigurationParam) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +func (r AccessRuleIPConfigurationParam) implementsFirewallAccessRuleNewParamsConfigurationUnion() {} + +func (r AccessRuleIPConfigurationParam) implementsFirewallAccessRuleEditParamsConfigurationUnion() {} + +func (r AccessRuleIPConfigurationParam) implementsFirewallUARuleNewParamsConfigurationUnion() {} + +func (r AccessRuleIPConfigurationParam) implementsFirewallUARuleUpdateParamsConfigurationUnion() {} + +type ASNConfiguration struct { + // The configuration target. You must set the target to `asn` when specifying an + // Autonomous System Number (ASN) in the rule. + Target ASNConfigurationTarget `json:"target"` + // The AS number to match. + Value string `json:"value"` + JSON asnConfigurationJSON `json:"-"` +} + +// asnConfigurationJSON contains the JSON metadata for the struct +// [ASNConfiguration] +type asnConfigurationJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ASNConfiguration) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r asnConfigurationJSON) RawJSON() string { + return r.raw +} + +func (r ASNConfiguration) implementsFirewallAccessRuleNewResponseConfiguration() {} + +func (r ASNConfiguration) implementsFirewallAccessRuleListResponseConfiguration() {} + +func (r ASNConfiguration) implementsFirewallAccessRuleEditResponseConfiguration() {} + +func (r ASNConfiguration) implementsFirewallAccessRuleGetResponseConfiguration() {} + +// The configuration target. You must set the target to `asn` when specifying an +// Autonomous System Number (ASN) in the rule. +type ASNConfigurationTarget string + +const ( + ASNConfigurationTargetASN ASNConfigurationTarget = "asn" +) + +func (r ASNConfigurationTarget) IsKnown() bool { + switch r { + case ASNConfigurationTargetASN: + return true + } + return false +} + +type ASNConfigurationParam struct { + // The configuration target. You must set the target to `asn` when specifying an + // Autonomous System Number (ASN) in the rule. + Target param.Field[ASNConfigurationTarget] `json:"target"` + // The AS number to match. + Value param.Field[string] `json:"value"` +} + +func (r ASNConfigurationParam) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +func (r ASNConfigurationParam) implementsFirewallAccessRuleNewParamsConfigurationUnion() {} + +func (r ASNConfigurationParam) implementsFirewallAccessRuleEditParamsConfigurationUnion() {} + +func (r ASNConfigurationParam) implementsFirewallUARuleNewParamsConfigurationUnion() {} + +func (r ASNConfigurationParam) implementsFirewallUARuleUpdateParamsConfigurationUnion() {} + +type CountryConfiguration struct { + // The configuration target. You must set the target to `country` when specifying a + // country code in the rule. + Target CountryConfigurationTarget `json:"target"` + // The two-letter ISO-3166-1 alpha-2 code to match. For more information, refer to + // [IP Access rules: Parameters](https://developers.cloudflare.com/waf/tools/ip-access-rules/parameters/#country). + Value string `json:"value"` + JSON countryConfigurationJSON `json:"-"` +} + +// countryConfigurationJSON contains the JSON metadata for the struct +// [CountryConfiguration] +type countryConfigurationJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *CountryConfiguration) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r countryConfigurationJSON) RawJSON() string { + return r.raw +} + +func (r CountryConfiguration) implementsFirewallAccessRuleNewResponseConfiguration() {} + +func (r CountryConfiguration) implementsFirewallAccessRuleListResponseConfiguration() {} + +func (r CountryConfiguration) implementsFirewallAccessRuleEditResponseConfiguration() {} + +func (r CountryConfiguration) implementsFirewallAccessRuleGetResponseConfiguration() {} + +// The configuration target. You must set the target to `country` when specifying a +// country code in the rule. +type CountryConfigurationTarget string + +const ( + CountryConfigurationTargetCountry CountryConfigurationTarget = "country" +) + +func (r CountryConfigurationTarget) IsKnown() bool { + switch r { + case CountryConfigurationTargetCountry: + return true + } + return false +} + +type CountryConfigurationParam struct { + // The configuration target. You must set the target to `country` when specifying a + // country code in the rule. + Target param.Field[CountryConfigurationTarget] `json:"target"` + // The two-letter ISO-3166-1 alpha-2 code to match. For more information, refer to + // [IP Access rules: Parameters](https://developers.cloudflare.com/waf/tools/ip-access-rules/parameters/#country). + Value param.Field[string] `json:"value"` +} + +func (r CountryConfigurationParam) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +func (r CountryConfigurationParam) implementsFirewallAccessRuleNewParamsConfigurationUnion() {} + +func (r CountryConfigurationParam) implementsFirewallAccessRuleEditParamsConfigurationUnion() {} + +func (r CountryConfigurationParam) implementsFirewallUARuleNewParamsConfigurationUnion() {} + +func (r CountryConfigurationParam) implementsFirewallUARuleUpdateParamsConfigurationUnion() {} + +type IPV6Configuration struct { + // The configuration target. You must set the target to `ip6` when specifying an + // IPv6 address in the rule. + Target IPV6ConfigurationTarget `json:"target"` + // The IPv6 address to match. + Value string `json:"value"` + JSON ipv6ConfigurationJSON `json:"-"` +} + +// ipv6ConfigurationJSON contains the JSON metadata for the struct +// [IPV6Configuration] +type ipv6ConfigurationJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *IPV6Configuration) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r ipv6ConfigurationJSON) RawJSON() string { + return r.raw +} + +func (r IPV6Configuration) implementsFirewallAccessRuleNewResponseConfiguration() {} + +func (r IPV6Configuration) implementsFirewallAccessRuleListResponseConfiguration() {} + +func (r IPV6Configuration) implementsFirewallAccessRuleEditResponseConfiguration() {} + +func (r IPV6Configuration) implementsFirewallAccessRuleGetResponseConfiguration() {} + +// The configuration target. You must set the target to `ip6` when specifying an +// IPv6 address in the rule. +type IPV6ConfigurationTarget string + +const ( + IPV6ConfigurationTargetIp6 IPV6ConfigurationTarget = "ip6" +) + +func (r IPV6ConfigurationTarget) IsKnown() bool { + switch r { + case IPV6ConfigurationTargetIp6: + return true + } + return false +} + +type IPV6ConfigurationParam struct { + // The configuration target. You must set the target to `ip6` when specifying an + // IPv6 address in the rule. + Target param.Field[IPV6ConfigurationTarget] `json:"target"` + // The IPv6 address to match. + Value param.Field[string] `json:"value"` +} + +func (r IPV6ConfigurationParam) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +func (r IPV6ConfigurationParam) implementsFirewallAccessRuleNewParamsConfigurationUnion() {} + +func (r IPV6ConfigurationParam) implementsFirewallAccessRuleEditParamsConfigurationUnion() {} + +func (r IPV6ConfigurationParam) implementsFirewallUARuleNewParamsConfigurationUnion() {} + +func (r IPV6ConfigurationParam) implementsFirewallUARuleUpdateParamsConfigurationUnion() {} + +type AccessRuleNewResponse struct { + // The unique identifier of the IP Access rule. + ID string `json:"id,required"` + // The available actions that a rule can apply to a matched request. + AllowedModes []AccessRuleNewResponseAllowedMode `json:"allowed_modes,required"` + // The rule configuration. + Configuration AccessRuleNewResponseConfiguration `json:"configuration,required"` + // The action to apply to a matched request. + Mode AccessRuleNewResponseMode `json:"mode,required"` + // The timestamp of when the rule was created. + CreatedOn time.Time `json:"created_on" format:"date-time"` + // The timestamp of when the rule was last modified. + ModifiedOn time.Time `json:"modified_on" format:"date-time"` + // An informative summary of the rule, typically used as a reminder or explanation. + Notes string `json:"notes"` + // All zones owned by the user will have the rule applied. + Scope AccessRuleNewResponseScope `json:"scope"` + JSON accessRuleNewResponseJSON `json:"-"` +} + +// accessRuleNewResponseJSON contains the JSON metadata for the struct +// [AccessRuleNewResponse] +type accessRuleNewResponseJSON struct { + ID apijson.Field + AllowedModes apijson.Field + Configuration apijson.Field + Mode apijson.Field + CreatedOn apijson.Field + ModifiedOn apijson.Field + Notes apijson.Field + Scope apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleNewResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleNewResponseJSON) RawJSON() string { + return r.raw +} + +// The action to apply to a matched request. +type AccessRuleNewResponseAllowedMode string + +const ( + AccessRuleNewResponseAllowedModeBlock AccessRuleNewResponseAllowedMode = "block" + AccessRuleNewResponseAllowedModeChallenge AccessRuleNewResponseAllowedMode = "challenge" + AccessRuleNewResponseAllowedModeWhitelist AccessRuleNewResponseAllowedMode = "whitelist" + AccessRuleNewResponseAllowedModeJSChallenge AccessRuleNewResponseAllowedMode = "js_challenge" + AccessRuleNewResponseAllowedModeManagedChallenge AccessRuleNewResponseAllowedMode = "managed_challenge" +) + +func (r AccessRuleNewResponseAllowedMode) IsKnown() bool { + switch r { + case AccessRuleNewResponseAllowedModeBlock, AccessRuleNewResponseAllowedModeChallenge, AccessRuleNewResponseAllowedModeWhitelist, AccessRuleNewResponseAllowedModeJSChallenge, AccessRuleNewResponseAllowedModeManagedChallenge: + return true + } + return false +} + +// The rule configuration. +type AccessRuleNewResponseConfiguration struct { + // The configuration target. You must set the target to `ip` when specifying an IP + // address in the rule. + Target AccessRuleNewResponseConfigurationTarget `json:"target"` + // The IP address to match. This address will be compared to the IP address of + // incoming requests. + Value string `json:"value"` + JSON accessRuleNewResponseConfigurationJSON `json:"-"` + union AccessRuleNewResponseConfigurationUnion +} + +// accessRuleNewResponseConfigurationJSON contains the JSON metadata for the struct +// [AccessRuleNewResponseConfiguration] +type accessRuleNewResponseConfigurationJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r accessRuleNewResponseConfigurationJSON) RawJSON() string { + return r.raw +} + +func (r *AccessRuleNewResponseConfiguration) UnmarshalJSON(data []byte) (err error) { + *r = AccessRuleNewResponseConfiguration{} + err = apijson.UnmarshalRoot(data, &r.union) + if err != nil { + return err + } + return apijson.Port(r.union, &r) +} + +// AsUnion returns a [AccessRuleNewResponseConfigurationUnion] interface which you +// can cast to the specific types for more type safety. +// +// Possible runtime types of the union are [firewall.AccessRuleIPConfiguration], +// [firewall.IPV6Configuration], [firewall.AccessRuleCIDRConfiguration], +// [firewall.ASNConfiguration], [firewall.CountryConfiguration]. +func (r AccessRuleNewResponseConfiguration) AsUnion() AccessRuleNewResponseConfigurationUnion { + return r.union +} + +// The rule configuration. +// +// Union satisfied by [firewall.AccessRuleIPConfiguration], +// [firewall.IPV6Configuration], [firewall.AccessRuleCIDRConfiguration], +// [firewall.ASNConfiguration] or [firewall.CountryConfiguration]. +type AccessRuleNewResponseConfigurationUnion interface { + implementsFirewallAccessRuleNewResponseConfiguration() +} + +func init() { + apijson.RegisterUnion( + reflect.TypeOf((*AccessRuleNewResponseConfigurationUnion)(nil)).Elem(), + "", + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(AccessRuleIPConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(IPV6Configuration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(AccessRuleCIDRConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(ASNConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(CountryConfiguration{}), + }, + ) +} + +// The configuration target. You must set the target to `ip` when specifying an IP +// address in the rule. +type AccessRuleNewResponseConfigurationTarget string + +const ( + AccessRuleNewResponseConfigurationTargetIP AccessRuleNewResponseConfigurationTarget = "ip" + AccessRuleNewResponseConfigurationTargetIp6 AccessRuleNewResponseConfigurationTarget = "ip6" + AccessRuleNewResponseConfigurationTargetIPRange AccessRuleNewResponseConfigurationTarget = "ip_range" + AccessRuleNewResponseConfigurationTargetASN AccessRuleNewResponseConfigurationTarget = "asn" + AccessRuleNewResponseConfigurationTargetCountry AccessRuleNewResponseConfigurationTarget = "country" +) + +func (r AccessRuleNewResponseConfigurationTarget) IsKnown() bool { + switch r { + case AccessRuleNewResponseConfigurationTargetIP, AccessRuleNewResponseConfigurationTargetIp6, AccessRuleNewResponseConfigurationTargetIPRange, AccessRuleNewResponseConfigurationTargetASN, AccessRuleNewResponseConfigurationTargetCountry: + return true + } + return false +} + +// The action to apply to a matched request. +type AccessRuleNewResponseMode string + +const ( + AccessRuleNewResponseModeBlock AccessRuleNewResponseMode = "block" + AccessRuleNewResponseModeChallenge AccessRuleNewResponseMode = "challenge" + AccessRuleNewResponseModeWhitelist AccessRuleNewResponseMode = "whitelist" + AccessRuleNewResponseModeJSChallenge AccessRuleNewResponseMode = "js_challenge" + AccessRuleNewResponseModeManagedChallenge AccessRuleNewResponseMode = "managed_challenge" +) + +func (r AccessRuleNewResponseMode) IsKnown() bool { + switch r { + case AccessRuleNewResponseModeBlock, AccessRuleNewResponseModeChallenge, AccessRuleNewResponseModeWhitelist, AccessRuleNewResponseModeJSChallenge, AccessRuleNewResponseModeManagedChallenge: + return true + } + return false +} + +// All zones owned by the user will have the rule applied. +type AccessRuleNewResponseScope struct { + // Identifier + ID string `json:"id"` + // The contact email address of the user. + Email string `json:"email"` + // The scope of the rule. + Type AccessRuleNewResponseScopeType `json:"type"` + JSON accessRuleNewResponseScopeJSON `json:"-"` +} + +// accessRuleNewResponseScopeJSON contains the JSON metadata for the struct +// [AccessRuleNewResponseScope] +type accessRuleNewResponseScopeJSON struct { + ID apijson.Field + Email apijson.Field + Type apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleNewResponseScope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleNewResponseScopeJSON) RawJSON() string { + return r.raw +} + +// The scope of the rule. +type AccessRuleNewResponseScopeType string + +const ( + AccessRuleNewResponseScopeTypeUser AccessRuleNewResponseScopeType = "user" + AccessRuleNewResponseScopeTypeOrganization AccessRuleNewResponseScopeType = "organization" +) + +func (r AccessRuleNewResponseScopeType) IsKnown() bool { + switch r { + case AccessRuleNewResponseScopeTypeUser, AccessRuleNewResponseScopeTypeOrganization: + return true + } + return false +} + +type AccessRuleListResponse struct { + // The unique identifier of the IP Access rule. + ID string `json:"id,required"` + // The available actions that a rule can apply to a matched request. + AllowedModes []AccessRuleListResponseAllowedMode `json:"allowed_modes,required"` + // The rule configuration. + Configuration AccessRuleListResponseConfiguration `json:"configuration,required"` + // The action to apply to a matched request. + Mode AccessRuleListResponseMode `json:"mode,required"` + // The timestamp of when the rule was created. + CreatedOn time.Time `json:"created_on" format:"date-time"` + // The timestamp of when the rule was last modified. + ModifiedOn time.Time `json:"modified_on" format:"date-time"` + // An informative summary of the rule, typically used as a reminder or explanation. + Notes string `json:"notes"` + // All zones owned by the user will have the rule applied. + Scope AccessRuleListResponseScope `json:"scope"` + JSON accessRuleListResponseJSON `json:"-"` +} + +// accessRuleListResponseJSON contains the JSON metadata for the struct +// [AccessRuleListResponse] +type accessRuleListResponseJSON struct { + ID apijson.Field + AllowedModes apijson.Field + Configuration apijson.Field + Mode apijson.Field + CreatedOn apijson.Field + ModifiedOn apijson.Field + Notes apijson.Field + Scope apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleListResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleListResponseJSON) RawJSON() string { + return r.raw +} + +// The action to apply to a matched request. +type AccessRuleListResponseAllowedMode string + +const ( + AccessRuleListResponseAllowedModeBlock AccessRuleListResponseAllowedMode = "block" + AccessRuleListResponseAllowedModeChallenge AccessRuleListResponseAllowedMode = "challenge" + AccessRuleListResponseAllowedModeWhitelist AccessRuleListResponseAllowedMode = "whitelist" + AccessRuleListResponseAllowedModeJSChallenge AccessRuleListResponseAllowedMode = "js_challenge" + AccessRuleListResponseAllowedModeManagedChallenge AccessRuleListResponseAllowedMode = "managed_challenge" +) + +func (r AccessRuleListResponseAllowedMode) IsKnown() bool { + switch r { + case AccessRuleListResponseAllowedModeBlock, AccessRuleListResponseAllowedModeChallenge, AccessRuleListResponseAllowedModeWhitelist, AccessRuleListResponseAllowedModeJSChallenge, AccessRuleListResponseAllowedModeManagedChallenge: + return true + } + return false +} + +// The rule configuration. +type AccessRuleListResponseConfiguration struct { + // The configuration target. You must set the target to `ip` when specifying an IP + // address in the rule. + Target AccessRuleListResponseConfigurationTarget `json:"target"` + // The IP address to match. This address will be compared to the IP address of + // incoming requests. + Value string `json:"value"` + JSON accessRuleListResponseConfigurationJSON `json:"-"` + union AccessRuleListResponseConfigurationUnion +} + +// accessRuleListResponseConfigurationJSON contains the JSON metadata for the +// struct [AccessRuleListResponseConfiguration] +type accessRuleListResponseConfigurationJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r accessRuleListResponseConfigurationJSON) RawJSON() string { + return r.raw +} + +func (r *AccessRuleListResponseConfiguration) UnmarshalJSON(data []byte) (err error) { + *r = AccessRuleListResponseConfiguration{} + err = apijson.UnmarshalRoot(data, &r.union) + if err != nil { + return err + } + return apijson.Port(r.union, &r) +} + +// AsUnion returns a [AccessRuleListResponseConfigurationUnion] interface which you +// can cast to the specific types for more type safety. +// +// Possible runtime types of the union are [firewall.AccessRuleIPConfiguration], +// [firewall.IPV6Configuration], [firewall.AccessRuleCIDRConfiguration], +// [firewall.ASNConfiguration], [firewall.CountryConfiguration]. +func (r AccessRuleListResponseConfiguration) AsUnion() AccessRuleListResponseConfigurationUnion { + return r.union +} + +// The rule configuration. +// +// Union satisfied by [firewall.AccessRuleIPConfiguration], +// [firewall.IPV6Configuration], [firewall.AccessRuleCIDRConfiguration], +// [firewall.ASNConfiguration] or [firewall.CountryConfiguration]. +type AccessRuleListResponseConfigurationUnion interface { + implementsFirewallAccessRuleListResponseConfiguration() +} + +func init() { + apijson.RegisterUnion( + reflect.TypeOf((*AccessRuleListResponseConfigurationUnion)(nil)).Elem(), + "", + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(AccessRuleIPConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(IPV6Configuration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(AccessRuleCIDRConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(ASNConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(CountryConfiguration{}), + }, + ) +} + +// The configuration target. You must set the target to `ip` when specifying an IP +// address in the rule. +type AccessRuleListResponseConfigurationTarget string + +const ( + AccessRuleListResponseConfigurationTargetIP AccessRuleListResponseConfigurationTarget = "ip" + AccessRuleListResponseConfigurationTargetIp6 AccessRuleListResponseConfigurationTarget = "ip6" + AccessRuleListResponseConfigurationTargetIPRange AccessRuleListResponseConfigurationTarget = "ip_range" + AccessRuleListResponseConfigurationTargetASN AccessRuleListResponseConfigurationTarget = "asn" + AccessRuleListResponseConfigurationTargetCountry AccessRuleListResponseConfigurationTarget = "country" +) + +func (r AccessRuleListResponseConfigurationTarget) IsKnown() bool { + switch r { + case AccessRuleListResponseConfigurationTargetIP, AccessRuleListResponseConfigurationTargetIp6, AccessRuleListResponseConfigurationTargetIPRange, AccessRuleListResponseConfigurationTargetASN, AccessRuleListResponseConfigurationTargetCountry: + return true + } + return false +} + +// The action to apply to a matched request. +type AccessRuleListResponseMode string + +const ( + AccessRuleListResponseModeBlock AccessRuleListResponseMode = "block" + AccessRuleListResponseModeChallenge AccessRuleListResponseMode = "challenge" + AccessRuleListResponseModeWhitelist AccessRuleListResponseMode = "whitelist" + AccessRuleListResponseModeJSChallenge AccessRuleListResponseMode = "js_challenge" + AccessRuleListResponseModeManagedChallenge AccessRuleListResponseMode = "managed_challenge" +) + +func (r AccessRuleListResponseMode) IsKnown() bool { + switch r { + case AccessRuleListResponseModeBlock, AccessRuleListResponseModeChallenge, AccessRuleListResponseModeWhitelist, AccessRuleListResponseModeJSChallenge, AccessRuleListResponseModeManagedChallenge: + return true + } + return false +} + +// All zones owned by the user will have the rule applied. +type AccessRuleListResponseScope struct { + // Identifier + ID string `json:"id"` + // The contact email address of the user. + Email string `json:"email"` + // The scope of the rule. + Type AccessRuleListResponseScopeType `json:"type"` + JSON accessRuleListResponseScopeJSON `json:"-"` +} + +// accessRuleListResponseScopeJSON contains the JSON metadata for the struct +// [AccessRuleListResponseScope] +type accessRuleListResponseScopeJSON struct { + ID apijson.Field + Email apijson.Field + Type apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleListResponseScope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleListResponseScopeJSON) RawJSON() string { + return r.raw +} + +// The scope of the rule. +type AccessRuleListResponseScopeType string + +const ( + AccessRuleListResponseScopeTypeUser AccessRuleListResponseScopeType = "user" + AccessRuleListResponseScopeTypeOrganization AccessRuleListResponseScopeType = "organization" +) + +func (r AccessRuleListResponseScopeType) IsKnown() bool { + switch r { + case AccessRuleListResponseScopeTypeUser, AccessRuleListResponseScopeTypeOrganization: + return true + } + return false +} + +type AccessRuleDeleteResponse struct { + // Identifier + ID string `json:"id,required"` + JSON accessRuleDeleteResponseJSON `json:"-"` +} + +// accessRuleDeleteResponseJSON contains the JSON metadata for the struct +// [AccessRuleDeleteResponse] +type accessRuleDeleteResponseJSON struct { + ID apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleDeleteResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleDeleteResponseJSON) RawJSON() string { + return r.raw +} + +type AccessRuleEditResponse struct { + // The unique identifier of the IP Access rule. + ID string `json:"id,required"` + // The available actions that a rule can apply to a matched request. + AllowedModes []AccessRuleEditResponseAllowedMode `json:"allowed_modes,required"` + // The rule configuration. + Configuration AccessRuleEditResponseConfiguration `json:"configuration,required"` + // The action to apply to a matched request. + Mode AccessRuleEditResponseMode `json:"mode,required"` + // The timestamp of when the rule was created. + CreatedOn time.Time `json:"created_on" format:"date-time"` + // The timestamp of when the rule was last modified. + ModifiedOn time.Time `json:"modified_on" format:"date-time"` + // An informative summary of the rule, typically used as a reminder or explanation. + Notes string `json:"notes"` + // All zones owned by the user will have the rule applied. + Scope AccessRuleEditResponseScope `json:"scope"` + JSON accessRuleEditResponseJSON `json:"-"` +} + +// accessRuleEditResponseJSON contains the JSON metadata for the struct +// [AccessRuleEditResponse] +type accessRuleEditResponseJSON struct { + ID apijson.Field + AllowedModes apijson.Field + Configuration apijson.Field + Mode apijson.Field + CreatedOn apijson.Field + ModifiedOn apijson.Field + Notes apijson.Field + Scope apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleEditResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleEditResponseJSON) RawJSON() string { + return r.raw +} + +// The action to apply to a matched request. +type AccessRuleEditResponseAllowedMode string + +const ( + AccessRuleEditResponseAllowedModeBlock AccessRuleEditResponseAllowedMode = "block" + AccessRuleEditResponseAllowedModeChallenge AccessRuleEditResponseAllowedMode = "challenge" + AccessRuleEditResponseAllowedModeWhitelist AccessRuleEditResponseAllowedMode = "whitelist" + AccessRuleEditResponseAllowedModeJSChallenge AccessRuleEditResponseAllowedMode = "js_challenge" + AccessRuleEditResponseAllowedModeManagedChallenge AccessRuleEditResponseAllowedMode = "managed_challenge" +) + +func (r AccessRuleEditResponseAllowedMode) IsKnown() bool { + switch r { + case AccessRuleEditResponseAllowedModeBlock, AccessRuleEditResponseAllowedModeChallenge, AccessRuleEditResponseAllowedModeWhitelist, AccessRuleEditResponseAllowedModeJSChallenge, AccessRuleEditResponseAllowedModeManagedChallenge: + return true + } + return false +} + +// The rule configuration. +type AccessRuleEditResponseConfiguration struct { + // The configuration target. You must set the target to `ip` when specifying an IP + // address in the rule. + Target AccessRuleEditResponseConfigurationTarget `json:"target"` + // The IP address to match. This address will be compared to the IP address of + // incoming requests. + Value string `json:"value"` + JSON accessRuleEditResponseConfigurationJSON `json:"-"` + union AccessRuleEditResponseConfigurationUnion +} + +// accessRuleEditResponseConfigurationJSON contains the JSON metadata for the +// struct [AccessRuleEditResponseConfiguration] +type accessRuleEditResponseConfigurationJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r accessRuleEditResponseConfigurationJSON) RawJSON() string { + return r.raw +} + +func (r *AccessRuleEditResponseConfiguration) UnmarshalJSON(data []byte) (err error) { + *r = AccessRuleEditResponseConfiguration{} + err = apijson.UnmarshalRoot(data, &r.union) + if err != nil { + return err + } + return apijson.Port(r.union, &r) +} + +// AsUnion returns a [AccessRuleEditResponseConfigurationUnion] interface which you +// can cast to the specific types for more type safety. +// +// Possible runtime types of the union are [firewall.AccessRuleIPConfiguration], +// [firewall.IPV6Configuration], [firewall.AccessRuleCIDRConfiguration], +// [firewall.ASNConfiguration], [firewall.CountryConfiguration]. +func (r AccessRuleEditResponseConfiguration) AsUnion() AccessRuleEditResponseConfigurationUnion { + return r.union +} + +// The rule configuration. +// +// Union satisfied by [firewall.AccessRuleIPConfiguration], +// [firewall.IPV6Configuration], [firewall.AccessRuleCIDRConfiguration], +// [firewall.ASNConfiguration] or [firewall.CountryConfiguration]. +type AccessRuleEditResponseConfigurationUnion interface { + implementsFirewallAccessRuleEditResponseConfiguration() +} + +func init() { + apijson.RegisterUnion( + reflect.TypeOf((*AccessRuleEditResponseConfigurationUnion)(nil)).Elem(), + "", + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(AccessRuleIPConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(IPV6Configuration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(AccessRuleCIDRConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(ASNConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(CountryConfiguration{}), + }, + ) +} + +// The configuration target. You must set the target to `ip` when specifying an IP +// address in the rule. +type AccessRuleEditResponseConfigurationTarget string + +const ( + AccessRuleEditResponseConfigurationTargetIP AccessRuleEditResponseConfigurationTarget = "ip" + AccessRuleEditResponseConfigurationTargetIp6 AccessRuleEditResponseConfigurationTarget = "ip6" + AccessRuleEditResponseConfigurationTargetIPRange AccessRuleEditResponseConfigurationTarget = "ip_range" + AccessRuleEditResponseConfigurationTargetASN AccessRuleEditResponseConfigurationTarget = "asn" + AccessRuleEditResponseConfigurationTargetCountry AccessRuleEditResponseConfigurationTarget = "country" +) + +func (r AccessRuleEditResponseConfigurationTarget) IsKnown() bool { + switch r { + case AccessRuleEditResponseConfigurationTargetIP, AccessRuleEditResponseConfigurationTargetIp6, AccessRuleEditResponseConfigurationTargetIPRange, AccessRuleEditResponseConfigurationTargetASN, AccessRuleEditResponseConfigurationTargetCountry: + return true + } + return false +} + +// The action to apply to a matched request. +type AccessRuleEditResponseMode string + +const ( + AccessRuleEditResponseModeBlock AccessRuleEditResponseMode = "block" + AccessRuleEditResponseModeChallenge AccessRuleEditResponseMode = "challenge" + AccessRuleEditResponseModeWhitelist AccessRuleEditResponseMode = "whitelist" + AccessRuleEditResponseModeJSChallenge AccessRuleEditResponseMode = "js_challenge" + AccessRuleEditResponseModeManagedChallenge AccessRuleEditResponseMode = "managed_challenge" +) + +func (r AccessRuleEditResponseMode) IsKnown() bool { + switch r { + case AccessRuleEditResponseModeBlock, AccessRuleEditResponseModeChallenge, AccessRuleEditResponseModeWhitelist, AccessRuleEditResponseModeJSChallenge, AccessRuleEditResponseModeManagedChallenge: + return true + } + return false +} + +// All zones owned by the user will have the rule applied. +type AccessRuleEditResponseScope struct { + // Identifier + ID string `json:"id"` + // The contact email address of the user. + Email string `json:"email"` + // The scope of the rule. + Type AccessRuleEditResponseScopeType `json:"type"` + JSON accessRuleEditResponseScopeJSON `json:"-"` +} + +// accessRuleEditResponseScopeJSON contains the JSON metadata for the struct +// [AccessRuleEditResponseScope] +type accessRuleEditResponseScopeJSON struct { + ID apijson.Field + Email apijson.Field + Type apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleEditResponseScope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleEditResponseScopeJSON) RawJSON() string { + return r.raw +} + +// The scope of the rule. +type AccessRuleEditResponseScopeType string + +const ( + AccessRuleEditResponseScopeTypeUser AccessRuleEditResponseScopeType = "user" + AccessRuleEditResponseScopeTypeOrganization AccessRuleEditResponseScopeType = "organization" +) + +func (r AccessRuleEditResponseScopeType) IsKnown() bool { + switch r { + case AccessRuleEditResponseScopeTypeUser, AccessRuleEditResponseScopeTypeOrganization: + return true + } + return false +} + +type AccessRuleGetResponse struct { + // The unique identifier of the IP Access rule. + ID string `json:"id,required"` + // The available actions that a rule can apply to a matched request. + AllowedModes []AccessRuleGetResponseAllowedMode `json:"allowed_modes,required"` + // The rule configuration. + Configuration AccessRuleGetResponseConfiguration `json:"configuration,required"` + // The action to apply to a matched request. + Mode AccessRuleGetResponseMode `json:"mode,required"` + // The timestamp of when the rule was created. + CreatedOn time.Time `json:"created_on" format:"date-time"` + // The timestamp of when the rule was last modified. + ModifiedOn time.Time `json:"modified_on" format:"date-time"` + // An informative summary of the rule, typically used as a reminder or explanation. + Notes string `json:"notes"` + // All zones owned by the user will have the rule applied. + Scope AccessRuleGetResponseScope `json:"scope"` + JSON accessRuleGetResponseJSON `json:"-"` +} + +// accessRuleGetResponseJSON contains the JSON metadata for the struct +// [AccessRuleGetResponse] +type accessRuleGetResponseJSON struct { + ID apijson.Field + AllowedModes apijson.Field + Configuration apijson.Field + Mode apijson.Field + CreatedOn apijson.Field + ModifiedOn apijson.Field + Notes apijson.Field + Scope apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleGetResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleGetResponseJSON) RawJSON() string { + return r.raw +} -// The configuration target. You must set the target to `ip_range` when specifying -// an IP address range in the rule. -type AccessRuleCIDRConfigurationTarget string +// The action to apply to a matched request. +type AccessRuleGetResponseAllowedMode string const ( - AccessRuleCIDRConfigurationTargetIPRange AccessRuleCIDRConfigurationTarget = "ip_range" + AccessRuleGetResponseAllowedModeBlock AccessRuleGetResponseAllowedMode = "block" + AccessRuleGetResponseAllowedModeChallenge AccessRuleGetResponseAllowedMode = "challenge" + AccessRuleGetResponseAllowedModeWhitelist AccessRuleGetResponseAllowedMode = "whitelist" + AccessRuleGetResponseAllowedModeJSChallenge AccessRuleGetResponseAllowedMode = "js_challenge" + AccessRuleGetResponseAllowedModeManagedChallenge AccessRuleGetResponseAllowedMode = "managed_challenge" ) -func (r AccessRuleCIDRConfigurationTarget) IsKnown() bool { +func (r AccessRuleGetResponseAllowedMode) IsKnown() bool { switch r { - case AccessRuleCIDRConfigurationTargetIPRange: + case AccessRuleGetResponseAllowedModeBlock, AccessRuleGetResponseAllowedModeChallenge, AccessRuleGetResponseAllowedModeWhitelist, AccessRuleGetResponseAllowedModeJSChallenge, AccessRuleGetResponseAllowedModeManagedChallenge: return true } return false } -type AccessRuleIPConfigurationParam struct { +// The rule configuration. +type AccessRuleGetResponseConfiguration struct { // The configuration target. You must set the target to `ip` when specifying an IP // address in the rule. - Target param.Field[AccessRuleIPConfigurationTarget] `json:"target"` + Target AccessRuleGetResponseConfigurationTarget `json:"target"` // The IP address to match. This address will be compared to the IP address of // incoming requests. - Value param.Field[string] `json:"value"` + Value string `json:"value"` + JSON accessRuleGetResponseConfigurationJSON `json:"-"` + union AccessRuleGetResponseConfigurationUnion } -func (r AccessRuleIPConfigurationParam) MarshalJSON() (data []byte, err error) { - return apijson.MarshalRoot(r) +// accessRuleGetResponseConfigurationJSON contains the JSON metadata for the struct +// [AccessRuleGetResponseConfiguration] +type accessRuleGetResponseConfigurationJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field } -func (r AccessRuleIPConfigurationParam) implementsFirewallAccessRuleNewParamsConfigurationUnion() {} - -// The configuration target. You must set the target to `ip` when specifying an IP -// address in the rule. -type AccessRuleIPConfigurationTarget string - -const ( - AccessRuleIPConfigurationTargetIP AccessRuleIPConfigurationTarget = "ip" -) +func (r accessRuleGetResponseConfigurationJSON) RawJSON() string { + return r.raw +} -func (r AccessRuleIPConfigurationTarget) IsKnown() bool { - switch r { - case AccessRuleIPConfigurationTargetIP: - return true +func (r *AccessRuleGetResponseConfiguration) UnmarshalJSON(data []byte) (err error) { + *r = AccessRuleGetResponseConfiguration{} + err = apijson.UnmarshalRoot(data, &r.union) + if err != nil { + return err } - return false + return apijson.Port(r.union, &r) } -type ASNConfigurationParam struct { - // The configuration target. You must set the target to `asn` when specifying an - // Autonomous System Number (ASN) in the rule. - Target param.Field[ASNConfigurationTarget] `json:"target"` - // The AS number to match. - Value param.Field[string] `json:"value"` +// AsUnion returns a [AccessRuleGetResponseConfigurationUnion] interface which you +// can cast to the specific types for more type safety. +// +// Possible runtime types of the union are [firewall.AccessRuleIPConfiguration], +// [firewall.IPV6Configuration], [firewall.AccessRuleCIDRConfiguration], +// [firewall.ASNConfiguration], [firewall.CountryConfiguration]. +func (r AccessRuleGetResponseConfiguration) AsUnion() AccessRuleGetResponseConfigurationUnion { + return r.union } -func (r ASNConfigurationParam) MarshalJSON() (data []byte, err error) { - return apijson.MarshalRoot(r) +// The rule configuration. +// +// Union satisfied by [firewall.AccessRuleIPConfiguration], +// [firewall.IPV6Configuration], [firewall.AccessRuleCIDRConfiguration], +// [firewall.ASNConfiguration] or [firewall.CountryConfiguration]. +type AccessRuleGetResponseConfigurationUnion interface { + implementsFirewallAccessRuleGetResponseConfiguration() } -func (r ASNConfigurationParam) implementsFirewallAccessRuleNewParamsConfigurationUnion() {} +func init() { + apijson.RegisterUnion( + reflect.TypeOf((*AccessRuleGetResponseConfigurationUnion)(nil)).Elem(), + "", + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(AccessRuleIPConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(IPV6Configuration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(AccessRuleCIDRConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(ASNConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(CountryConfiguration{}), + }, + ) +} -// The configuration target. You must set the target to `asn` when specifying an -// Autonomous System Number (ASN) in the rule. -type ASNConfigurationTarget string +// The configuration target. You must set the target to `ip` when specifying an IP +// address in the rule. +type AccessRuleGetResponseConfigurationTarget string const ( - ASNConfigurationTargetASN ASNConfigurationTarget = "asn" + AccessRuleGetResponseConfigurationTargetIP AccessRuleGetResponseConfigurationTarget = "ip" + AccessRuleGetResponseConfigurationTargetIp6 AccessRuleGetResponseConfigurationTarget = "ip6" + AccessRuleGetResponseConfigurationTargetIPRange AccessRuleGetResponseConfigurationTarget = "ip_range" + AccessRuleGetResponseConfigurationTargetASN AccessRuleGetResponseConfigurationTarget = "asn" + AccessRuleGetResponseConfigurationTargetCountry AccessRuleGetResponseConfigurationTarget = "country" ) -func (r ASNConfigurationTarget) IsKnown() bool { +func (r AccessRuleGetResponseConfigurationTarget) IsKnown() bool { switch r { - case ASNConfigurationTargetASN: + case AccessRuleGetResponseConfigurationTargetIP, AccessRuleGetResponseConfigurationTargetIp6, AccessRuleGetResponseConfigurationTargetIPRange, AccessRuleGetResponseConfigurationTargetASN, AccessRuleGetResponseConfigurationTargetCountry: return true } return false } -type CountryConfigurationParam struct { - // The configuration target. You must set the target to `country` when specifying a - // country code in the rule. - Target param.Field[CountryConfigurationTarget] `json:"target"` - // The two-letter ISO-3166-1 alpha-2 code to match. For more information, refer to - // [IP Access rules: Parameters](https://developers.cloudflare.com/waf/tools/ip-access-rules/parameters/#country). - Value param.Field[string] `json:"value"` -} - -func (r CountryConfigurationParam) MarshalJSON() (data []byte, err error) { - return apijson.MarshalRoot(r) -} - -func (r CountryConfigurationParam) implementsFirewallAccessRuleNewParamsConfigurationUnion() {} - -// The configuration target. You must set the target to `country` when specifying a -// country code in the rule. -type CountryConfigurationTarget string +// The action to apply to a matched request. +type AccessRuleGetResponseMode string const ( - CountryConfigurationTargetCountry CountryConfigurationTarget = "country" + AccessRuleGetResponseModeBlock AccessRuleGetResponseMode = "block" + AccessRuleGetResponseModeChallenge AccessRuleGetResponseMode = "challenge" + AccessRuleGetResponseModeWhitelist AccessRuleGetResponseMode = "whitelist" + AccessRuleGetResponseModeJSChallenge AccessRuleGetResponseMode = "js_challenge" + AccessRuleGetResponseModeManagedChallenge AccessRuleGetResponseMode = "managed_challenge" ) -func (r CountryConfigurationTarget) IsKnown() bool { +func (r AccessRuleGetResponseMode) IsKnown() bool { switch r { - case CountryConfigurationTargetCountry: + case AccessRuleGetResponseModeBlock, AccessRuleGetResponseModeChallenge, AccessRuleGetResponseModeWhitelist, AccessRuleGetResponseModeJSChallenge, AccessRuleGetResponseModeManagedChallenge: return true } return false } -type IPV6ConfigurationParam struct { - // The configuration target. You must set the target to `ip6` when specifying an - // IPv6 address in the rule. - Target param.Field[IPV6ConfigurationTarget] `json:"target"` - // The IPv6 address to match. - Value param.Field[string] `json:"value"` +// All zones owned by the user will have the rule applied. +type AccessRuleGetResponseScope struct { + // Identifier + ID string `json:"id"` + // The contact email address of the user. + Email string `json:"email"` + // The scope of the rule. + Type AccessRuleGetResponseScopeType `json:"type"` + JSON accessRuleGetResponseScopeJSON `json:"-"` } -func (r IPV6ConfigurationParam) MarshalJSON() (data []byte, err error) { - return apijson.MarshalRoot(r) +// accessRuleGetResponseScopeJSON contains the JSON metadata for the struct +// [AccessRuleGetResponseScope] +type accessRuleGetResponseScopeJSON struct { + ID apijson.Field + Email apijson.Field + Type apijson.Field + raw string + ExtraFields map[string]apijson.Field } -func (r IPV6ConfigurationParam) implementsFirewallAccessRuleNewParamsConfigurationUnion() {} +func (r *AccessRuleGetResponseScope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} -// The configuration target. You must set the target to `ip6` when specifying an -// IPv6 address in the rule. -type IPV6ConfigurationTarget string +func (r accessRuleGetResponseScopeJSON) RawJSON() string { + return r.raw +} + +// The scope of the rule. +type AccessRuleGetResponseScopeType string const ( - IPV6ConfigurationTargetIp6 IPV6ConfigurationTarget = "ip6" + AccessRuleGetResponseScopeTypeUser AccessRuleGetResponseScopeType = "user" + AccessRuleGetResponseScopeTypeOrganization AccessRuleGetResponseScopeType = "organization" ) -func (r IPV6ConfigurationTarget) IsKnown() bool { +func (r AccessRuleGetResponseScopeType) IsKnown() bool { switch r { - case IPV6ConfigurationTargetIp6: + case AccessRuleGetResponseScopeTypeUser, AccessRuleGetResponseScopeTypeOrganization: return true } return false } -type AccessRuleListResponse = interface{} - type AccessRuleNewParams struct { // The rule configuration. Configuration param.Field[AccessRuleNewParamsConfigurationUnion] `json:"configuration,required"` @@ -357,7 +1597,7 @@ func (r AccessRuleNewParamsMode) IsKnown() bool { type AccessRuleNewResponseEnvelope struct { Errors []shared.ResponseInfo `json:"errors,required"` Messages []shared.ResponseInfo `json:"messages,required"` - Result interface{} `json:"result,required"` + Result AccessRuleNewResponse `json:"result,required"` // Whether the API call was successful Success AccessRuleNewResponseEnvelopeSuccess `json:"success,required"` JSON accessRuleNewResponseEnvelopeJSON `json:"-"` @@ -535,3 +1775,229 @@ func (r AccessRuleListParamsOrder) IsKnown() bool { } return false } + +type AccessRuleDeleteParams struct { + // The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. + AccountID param.Field[string] `path:"account_id"` + // The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. + ZoneID param.Field[string] `path:"zone_id"` +} + +type AccessRuleDeleteResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result AccessRuleDeleteResponse `json:"result,required,nullable"` + // Whether the API call was successful + Success AccessRuleDeleteResponseEnvelopeSuccess `json:"success,required"` + JSON accessRuleDeleteResponseEnvelopeJSON `json:"-"` +} + +// accessRuleDeleteResponseEnvelopeJSON contains the JSON metadata for the struct +// [AccessRuleDeleteResponseEnvelope] +type accessRuleDeleteResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleDeleteResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleDeleteResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type AccessRuleDeleteResponseEnvelopeSuccess bool + +const ( + AccessRuleDeleteResponseEnvelopeSuccessTrue AccessRuleDeleteResponseEnvelopeSuccess = true +) + +func (r AccessRuleDeleteResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case AccessRuleDeleteResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type AccessRuleEditParams struct { + // The rule configuration. + Configuration param.Field[AccessRuleEditParamsConfigurationUnion] `json:"configuration,required"` + // The action to apply to a matched request. + Mode param.Field[AccessRuleEditParamsMode] `json:"mode,required"` + // The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. + AccountID param.Field[string] `path:"account_id"` + // The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. + ZoneID param.Field[string] `path:"zone_id"` + // An informative summary of the rule, typically used as a reminder or explanation. + Notes param.Field[string] `json:"notes"` +} + +func (r AccessRuleEditParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The rule configuration. +type AccessRuleEditParamsConfiguration struct { + // The configuration target. You must set the target to `ip` when specifying an IP + // address in the rule. + Target param.Field[AccessRuleEditParamsConfigurationTarget] `json:"target"` + // The IP address to match. This address will be compared to the IP address of + // incoming requests. + Value param.Field[string] `json:"value"` +} + +func (r AccessRuleEditParamsConfiguration) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +func (r AccessRuleEditParamsConfiguration) implementsFirewallAccessRuleEditParamsConfigurationUnion() { +} + +// The rule configuration. +// +// Satisfied by [firewall.AccessRuleIPConfigurationParam], +// [firewall.IPV6ConfigurationParam], [firewall.AccessRuleCIDRConfigurationParam], +// [firewall.ASNConfigurationParam], [firewall.CountryConfigurationParam], +// [AccessRuleEditParamsConfiguration]. +type AccessRuleEditParamsConfigurationUnion interface { + implementsFirewallAccessRuleEditParamsConfigurationUnion() +} + +// The configuration target. You must set the target to `ip` when specifying an IP +// address in the rule. +type AccessRuleEditParamsConfigurationTarget string + +const ( + AccessRuleEditParamsConfigurationTargetIP AccessRuleEditParamsConfigurationTarget = "ip" + AccessRuleEditParamsConfigurationTargetIp6 AccessRuleEditParamsConfigurationTarget = "ip6" + AccessRuleEditParamsConfigurationTargetIPRange AccessRuleEditParamsConfigurationTarget = "ip_range" + AccessRuleEditParamsConfigurationTargetASN AccessRuleEditParamsConfigurationTarget = "asn" + AccessRuleEditParamsConfigurationTargetCountry AccessRuleEditParamsConfigurationTarget = "country" +) + +func (r AccessRuleEditParamsConfigurationTarget) IsKnown() bool { + switch r { + case AccessRuleEditParamsConfigurationTargetIP, AccessRuleEditParamsConfigurationTargetIp6, AccessRuleEditParamsConfigurationTargetIPRange, AccessRuleEditParamsConfigurationTargetASN, AccessRuleEditParamsConfigurationTargetCountry: + return true + } + return false +} + +// The action to apply to a matched request. +type AccessRuleEditParamsMode string + +const ( + AccessRuleEditParamsModeBlock AccessRuleEditParamsMode = "block" + AccessRuleEditParamsModeChallenge AccessRuleEditParamsMode = "challenge" + AccessRuleEditParamsModeWhitelist AccessRuleEditParamsMode = "whitelist" + AccessRuleEditParamsModeJSChallenge AccessRuleEditParamsMode = "js_challenge" + AccessRuleEditParamsModeManagedChallenge AccessRuleEditParamsMode = "managed_challenge" +) + +func (r AccessRuleEditParamsMode) IsKnown() bool { + switch r { + case AccessRuleEditParamsModeBlock, AccessRuleEditParamsModeChallenge, AccessRuleEditParamsModeWhitelist, AccessRuleEditParamsModeJSChallenge, AccessRuleEditParamsModeManagedChallenge: + return true + } + return false +} + +type AccessRuleEditResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result AccessRuleEditResponse `json:"result,required"` + // Whether the API call was successful + Success AccessRuleEditResponseEnvelopeSuccess `json:"success,required"` + JSON accessRuleEditResponseEnvelopeJSON `json:"-"` +} + +// accessRuleEditResponseEnvelopeJSON contains the JSON metadata for the struct +// [AccessRuleEditResponseEnvelope] +type accessRuleEditResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleEditResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleEditResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type AccessRuleEditResponseEnvelopeSuccess bool + +const ( + AccessRuleEditResponseEnvelopeSuccessTrue AccessRuleEditResponseEnvelopeSuccess = true +) + +func (r AccessRuleEditResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case AccessRuleEditResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type AccessRuleGetParams struct { + // The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. + AccountID param.Field[string] `path:"account_id"` + // The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. + ZoneID param.Field[string] `path:"zone_id"` +} + +type AccessRuleGetResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result AccessRuleGetResponse `json:"result,required"` + // Whether the API call was successful + Success AccessRuleGetResponseEnvelopeSuccess `json:"success,required"` + JSON accessRuleGetResponseEnvelopeJSON `json:"-"` +} + +// accessRuleGetResponseEnvelopeJSON contains the JSON metadata for the struct +// [AccessRuleGetResponseEnvelope] +type accessRuleGetResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AccessRuleGetResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r accessRuleGetResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type AccessRuleGetResponseEnvelopeSuccess bool + +const ( + AccessRuleGetResponseEnvelopeSuccessTrue AccessRuleGetResponseEnvelopeSuccess = true +) + +func (r AccessRuleGetResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case AccessRuleGetResponseEnvelopeSuccessTrue: + return true + } + return false +} diff --git a/firewall/accessrule_test.go b/firewall/accessrule_test.go index 83fc3492b6a..07e485e44e4 100644 --- a/firewall/accessrule_test.go +++ b/firewall/accessrule_test.go @@ -82,3 +82,99 @@ func TestAccessRuleListWithOptionalParams(t *testing.T) { t.Fatalf("err should be nil: %s", err.Error()) } } + +func TestAccessRuleDeleteWithOptionalParams(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.AccessRules.Delete( + context.TODO(), + "023e105f4ecef8ad9ca31a8372d0c353", + firewall.AccessRuleDeleteParams{ + AccountID: cloudflare.F("account_id"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestAccessRuleEditWithOptionalParams(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.AccessRules.Edit( + context.TODO(), + "023e105f4ecef8ad9ca31a8372d0c353", + firewall.AccessRuleEditParams{ + Configuration: cloudflare.F[firewall.AccessRuleEditParamsConfigurationUnion](firewall.AccessRuleIPConfigurationParam{ + Target: cloudflare.F(firewall.AccessRuleIPConfigurationTargetIP), + Value: cloudflare.F("198.51.100.4"), + }), + Mode: cloudflare.F(firewall.AccessRuleEditParamsModeBlock), + AccountID: cloudflare.F("account_id"), + Notes: cloudflare.F("This rule is enabled because of an event that occurred on date X."), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestAccessRuleGetWithOptionalParams(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.AccessRules.Get( + context.TODO(), + "023e105f4ecef8ad9ca31a8372d0c353", + firewall.AccessRuleGetParams{ + AccountID: cloudflare.F("account_id"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} diff --git a/firewall/lockdown.go b/firewall/lockdown.go index aaf616d9c22..13432a7ce31 100644 --- a/firewall/lockdown.go +++ b/firewall/lockdown.go @@ -3,7 +3,22 @@ package firewall import ( + "context" + "errors" + "fmt" + "net/http" + "net/url" + "reflect" + "time" + + "github.com/cloudflare/cloudflare-go/v3/internal/apijson" + "github.com/cloudflare/cloudflare-go/v3/internal/apiquery" + "github.com/cloudflare/cloudflare-go/v3/internal/param" + "github.com/cloudflare/cloudflare-go/v3/internal/requestconfig" "github.com/cloudflare/cloudflare-go/v3/option" + "github.com/cloudflare/cloudflare-go/v3/packages/pagination" + "github.com/cloudflare/cloudflare-go/v3/shared" + "github.com/tidwall/gjson" ) // LockdownService contains methods and other services that help with interacting @@ -24,3 +39,634 @@ func NewLockdownService(opts ...option.RequestOption) (r *LockdownService) { r.Options = opts return } + +// Creates a new Zone Lockdown rule. +func (r *LockdownService) New(ctx context.Context, params LockdownNewParams, opts ...option.RequestOption) (res *Lockdown, err error) { + var env LockdownNewResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/lockdowns", params.ZoneID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Updates an existing Zone Lockdown rule. +func (r *LockdownService) Update(ctx context.Context, lockDownsID string, params LockdownUpdateParams, opts ...option.RequestOption) (res *Lockdown, err error) { + var env LockdownUpdateResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if lockDownsID == "" { + err = errors.New("missing required lock_downs_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/lockdowns/%s", params.ZoneID, lockDownsID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches Zone Lockdown rules. You can filter the results using several optional +// parameters. +func (r *LockdownService) List(ctx context.Context, params LockdownListParams, opts ...option.RequestOption) (res *pagination.V4PagePaginationArray[Lockdown], err error) { + var raw *http.Response + opts = append(r.Options[:], opts...) + opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/lockdowns", params.ZoneID) + cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...) + if err != nil { + return nil, err + } + err = cfg.Execute() + if err != nil { + return nil, err + } + res.SetPageConfig(cfg, raw) + return res, nil +} + +// Fetches Zone Lockdown rules. You can filter the results using several optional +// parameters. +func (r *LockdownService) ListAutoPaging(ctx context.Context, params LockdownListParams, opts ...option.RequestOption) *pagination.V4PagePaginationArrayAutoPager[Lockdown] { + return pagination.NewV4PagePaginationArrayAutoPager(r.List(ctx, params, opts...)) +} + +// Deletes an existing Zone Lockdown rule. +func (r *LockdownService) Delete(ctx context.Context, lockDownsID string, body LockdownDeleteParams, opts ...option.RequestOption) (res *LockdownDeleteResponse, err error) { + var env LockdownDeleteResponseEnvelope + opts = append(r.Options[:], opts...) + if body.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if lockDownsID == "" { + err = errors.New("missing required lock_downs_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/lockdowns/%s", body.ZoneID, lockDownsID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches the details of a Zone Lockdown rule. +func (r *LockdownService) Get(ctx context.Context, lockDownsID string, query LockdownGetParams, opts ...option.RequestOption) (res *Lockdown, err error) { + var env LockdownGetResponseEnvelope + opts = append(r.Options[:], opts...) + if query.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if lockDownsID == "" { + err = errors.New("missing required lock_downs_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/lockdowns/%s", query.ZoneID, lockDownsID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +type Configuration []ConfigurationItem + +type ConfigurationItem struct { + // The configuration target. You must set the target to `ip` when specifying an IP + // address in the Zone Lockdown rule. + Target ConfigurationItemTarget `json:"target"` + // The IP address to match. This address will be compared to the IP address of + // incoming requests. + Value string `json:"value"` + JSON configurationItemJSON `json:"-"` + union ConfigurationItemUnion +} + +// configurationItemJSON contains the JSON metadata for the struct +// [ConfigurationItem] +type configurationItemJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r configurationItemJSON) RawJSON() string { + return r.raw +} + +func (r *ConfigurationItem) UnmarshalJSON(data []byte) (err error) { + *r = ConfigurationItem{} + err = apijson.UnmarshalRoot(data, &r.union) + if err != nil { + return err + } + return apijson.Port(r.union, &r) +} + +// AsUnion returns a [ConfigurationItemUnion] interface which you can cast to the +// specific types for more type safety. +// +// Possible runtime types of the union are [firewall.LockdownIPConfiguration], +// [firewall.LockdownCIDRConfiguration]. +func (r ConfigurationItem) AsUnion() ConfigurationItemUnion { + return r.union +} + +// Union satisfied by [firewall.LockdownIPConfiguration] or +// [firewall.LockdownCIDRConfiguration]. +type ConfigurationItemUnion interface { + implementsFirewallConfigurationItem() +} + +func init() { + apijson.RegisterUnion( + reflect.TypeOf((*ConfigurationItemUnion)(nil)).Elem(), + "", + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(LockdownIPConfiguration{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(LockdownCIDRConfiguration{}), + }, + ) +} + +// The configuration target. You must set the target to `ip` when specifying an IP +// address in the Zone Lockdown rule. +type ConfigurationItemTarget string + +const ( + ConfigurationItemTargetIP ConfigurationItemTarget = "ip" + ConfigurationItemTargetIPRange ConfigurationItemTarget = "ip_range" +) + +func (r ConfigurationItemTarget) IsKnown() bool { + switch r { + case ConfigurationItemTargetIP, ConfigurationItemTargetIPRange: + return true + } + return false +} + +type ConfigurationParam []ConfigurationItemUnionParam + +type ConfigurationItemParam struct { + // The configuration target. You must set the target to `ip` when specifying an IP + // address in the Zone Lockdown rule. + Target param.Field[ConfigurationItemTarget] `json:"target"` + // The IP address to match. This address will be compared to the IP address of + // incoming requests. + Value param.Field[string] `json:"value"` +} + +func (r ConfigurationItemParam) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +func (r ConfigurationItemParam) implementsFirewallConfigurationItemUnionParam() {} + +// Satisfied by [firewall.LockdownIPConfigurationParam], +// [firewall.LockdownCIDRConfigurationParam], [ConfigurationItemParam]. +type ConfigurationItemUnionParam interface { + implementsFirewallConfigurationItemUnionParam() +} + +type Lockdown struct { + // The unique identifier of the Zone Lockdown rule. + ID string `json:"id,required"` + // A list of IP addresses or CIDR ranges that will be allowed to access the URLs + // specified in the Zone Lockdown rule. You can include any number of `ip` or + // `ip_range` configurations. + Configurations Configuration `json:"configurations,required"` + // The timestamp of when the rule was created. + CreatedOn time.Time `json:"created_on,required" format:"date-time"` + // An informative summary of the rule. + Description string `json:"description,required"` + // The timestamp of when the rule was last modified. + ModifiedOn time.Time `json:"modified_on,required" format:"date-time"` + // When true, indicates that the rule is currently paused. + Paused bool `json:"paused,required"` + // The URLs to include in the rule definition. You can use wildcards. Each entered + // URL will be escaped before use, which means you can only use simple wildcard + // patterns. + URLs []LockdownURL `json:"urls,required"` + JSON lockdownJSON `json:"-"` +} + +// lockdownJSON contains the JSON metadata for the struct [Lockdown] +type lockdownJSON struct { + ID apijson.Field + Configurations apijson.Field + CreatedOn apijson.Field + Description apijson.Field + ModifiedOn apijson.Field + Paused apijson.Field + URLs apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *Lockdown) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r lockdownJSON) RawJSON() string { + return r.raw +} + +type LockdownCIDRConfiguration struct { + // The configuration target. You must set the target to `ip_range` when specifying + // an IP address range in the Zone Lockdown rule. + Target LockdownCIDRConfigurationTarget `json:"target"` + // The IP address range to match. You can only use prefix lengths `/16` and `/24`. + Value string `json:"value"` + JSON lockdownCIDRConfigurationJSON `json:"-"` +} + +// lockdownCIDRConfigurationJSON contains the JSON metadata for the struct +// [LockdownCIDRConfiguration] +type lockdownCIDRConfigurationJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *LockdownCIDRConfiguration) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r lockdownCIDRConfigurationJSON) RawJSON() string { + return r.raw +} + +func (r LockdownCIDRConfiguration) implementsFirewallConfigurationItem() {} + +// The configuration target. You must set the target to `ip_range` when specifying +// an IP address range in the Zone Lockdown rule. +type LockdownCIDRConfigurationTarget string + +const ( + LockdownCIDRConfigurationTargetIPRange LockdownCIDRConfigurationTarget = "ip_range" +) + +func (r LockdownCIDRConfigurationTarget) IsKnown() bool { + switch r { + case LockdownCIDRConfigurationTargetIPRange: + return true + } + return false +} + +type LockdownCIDRConfigurationParam struct { + // The configuration target. You must set the target to `ip_range` when specifying + // an IP address range in the Zone Lockdown rule. + Target param.Field[LockdownCIDRConfigurationTarget] `json:"target"` + // The IP address range to match. You can only use prefix lengths `/16` and `/24`. + Value param.Field[string] `json:"value"` +} + +func (r LockdownCIDRConfigurationParam) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +func (r LockdownCIDRConfigurationParam) implementsFirewallConfigurationItemUnionParam() {} + +type LockdownIPConfiguration struct { + // The configuration target. You must set the target to `ip` when specifying an IP + // address in the Zone Lockdown rule. + Target LockdownIPConfigurationTarget `json:"target"` + // The IP address to match. This address will be compared to the IP address of + // incoming requests. + Value string `json:"value"` + JSON lockdownIPConfigurationJSON `json:"-"` +} + +// lockdownIPConfigurationJSON contains the JSON metadata for the struct +// [LockdownIPConfiguration] +type lockdownIPConfigurationJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *LockdownIPConfiguration) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r lockdownIPConfigurationJSON) RawJSON() string { + return r.raw +} + +func (r LockdownIPConfiguration) implementsFirewallConfigurationItem() {} + +// The configuration target. You must set the target to `ip` when specifying an IP +// address in the Zone Lockdown rule. +type LockdownIPConfigurationTarget string + +const ( + LockdownIPConfigurationTargetIP LockdownIPConfigurationTarget = "ip" +) + +func (r LockdownIPConfigurationTarget) IsKnown() bool { + switch r { + case LockdownIPConfigurationTargetIP: + return true + } + return false +} + +type LockdownIPConfigurationParam struct { + // The configuration target. You must set the target to `ip` when specifying an IP + // address in the Zone Lockdown rule. + Target param.Field[LockdownIPConfigurationTarget] `json:"target"` + // The IP address to match. This address will be compared to the IP address of + // incoming requests. + Value param.Field[string] `json:"value"` +} + +func (r LockdownIPConfigurationParam) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +func (r LockdownIPConfigurationParam) implementsFirewallConfigurationItemUnionParam() {} + +type LockdownURL = string + +type LockdownDeleteResponse struct { + // The unique identifier of the Zone Lockdown rule. + ID string `json:"id"` + JSON lockdownDeleteResponseJSON `json:"-"` +} + +// lockdownDeleteResponseJSON contains the JSON metadata for the struct +// [LockdownDeleteResponse] +type lockdownDeleteResponseJSON struct { + ID apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *LockdownDeleteResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r lockdownDeleteResponseJSON) RawJSON() string { + return r.raw +} + +type LockdownNewParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // A list of IP addresses or CIDR ranges that will be allowed to access the URLs + // specified in the Zone Lockdown rule. You can include any number of `ip` or + // `ip_range` configurations. + Configurations param.Field[ConfigurationParam] `json:"configurations,required"` + // The URLs to include in the current WAF override. You can use wildcards. Each + // entered URL will be escaped before use, which means you can only use simple + // wildcard patterns. + URLs param.Field[[]OverrideURLParam] `json:"urls,required"` +} + +func (r LockdownNewParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type LockdownNewResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result Lockdown `json:"result,required"` + // Whether the API call was successful + Success LockdownNewResponseEnvelopeSuccess `json:"success,required"` + JSON lockdownNewResponseEnvelopeJSON `json:"-"` +} + +// lockdownNewResponseEnvelopeJSON contains the JSON metadata for the struct +// [LockdownNewResponseEnvelope] +type lockdownNewResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *LockdownNewResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r lockdownNewResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type LockdownNewResponseEnvelopeSuccess bool + +const ( + LockdownNewResponseEnvelopeSuccessTrue LockdownNewResponseEnvelopeSuccess = true +) + +func (r LockdownNewResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case LockdownNewResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type LockdownUpdateParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // A list of IP addresses or CIDR ranges that will be allowed to access the URLs + // specified in the Zone Lockdown rule. You can include any number of `ip` or + // `ip_range` configurations. + Configurations param.Field[ConfigurationParam] `json:"configurations,required"` + // The URLs to include in the current WAF override. You can use wildcards. Each + // entered URL will be escaped before use, which means you can only use simple + // wildcard patterns. + URLs param.Field[[]OverrideURLParam] `json:"urls,required"` +} + +func (r LockdownUpdateParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type LockdownUpdateResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result Lockdown `json:"result,required"` + // Whether the API call was successful + Success LockdownUpdateResponseEnvelopeSuccess `json:"success,required"` + JSON lockdownUpdateResponseEnvelopeJSON `json:"-"` +} + +// lockdownUpdateResponseEnvelopeJSON contains the JSON metadata for the struct +// [LockdownUpdateResponseEnvelope] +type lockdownUpdateResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *LockdownUpdateResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r lockdownUpdateResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type LockdownUpdateResponseEnvelopeSuccess bool + +const ( + LockdownUpdateResponseEnvelopeSuccessTrue LockdownUpdateResponseEnvelopeSuccess = true +) + +func (r LockdownUpdateResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case LockdownUpdateResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type LockdownListParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The timestamp of when the rule was created. + CreatedOn param.Field[time.Time] `query:"created_on" format:"date-time"` + // A string to search for in the description of existing rules. + Description param.Field[string] `query:"description"` + // A string to search for in the description of existing rules. + DescriptionSearch param.Field[string] `query:"description_search"` + // A single IP address to search for in existing rules. + IP param.Field[string] `query:"ip"` + // A single IP address range to search for in existing rules. + IPRangeSearch param.Field[string] `query:"ip_range_search"` + // A single IP address to search for in existing rules. + IPSearch param.Field[string] `query:"ip_search"` + // The timestamp of when the rule was last modified. + ModifiedOn param.Field[time.Time] `query:"modified_on" format:"date-time"` + // Page number of paginated results. + Page param.Field[float64] `query:"page"` + // The maximum number of results per page. You can only set the value to `1` or to + // a multiple of 5 such as `5`, `10`, `15`, or `20`. + PerPage param.Field[float64] `query:"per_page"` + // The priority of the rule to control the processing order. A lower number + // indicates higher priority. If not provided, any rules with a configured priority + // will be processed before rules without a priority. + Priority param.Field[float64] `query:"priority"` + // A single URI to search for in the list of URLs of existing rules. + URISearch param.Field[string] `query:"uri_search"` +} + +// URLQuery serializes [LockdownListParams]'s query parameters as `url.Values`. +func (r LockdownListParams) URLQuery() (v url.Values) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatRepeat, + NestedFormat: apiquery.NestedQueryFormatDots, + }) +} + +type LockdownDeleteParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} + +type LockdownDeleteResponseEnvelope struct { + Result LockdownDeleteResponse `json:"result"` + JSON lockdownDeleteResponseEnvelopeJSON `json:"-"` +} + +// lockdownDeleteResponseEnvelopeJSON contains the JSON metadata for the struct +// [LockdownDeleteResponseEnvelope] +type lockdownDeleteResponseEnvelopeJSON struct { + Result apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *LockdownDeleteResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r lockdownDeleteResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +type LockdownGetParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} + +type LockdownGetResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result Lockdown `json:"result,required"` + // Whether the API call was successful + Success LockdownGetResponseEnvelopeSuccess `json:"success,required"` + JSON lockdownGetResponseEnvelopeJSON `json:"-"` +} + +// lockdownGetResponseEnvelopeJSON contains the JSON metadata for the struct +// [LockdownGetResponseEnvelope] +type lockdownGetResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *LockdownGetResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r lockdownGetResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type LockdownGetResponseEnvelopeSuccess bool + +const ( + LockdownGetResponseEnvelopeSuccessTrue LockdownGetResponseEnvelopeSuccess = true +) + +func (r LockdownGetResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case LockdownGetResponseEnvelopeSuccessTrue: + return true + } + return false +} diff --git a/firewall/lockdown_test.go b/firewall/lockdown_test.go new file mode 100644 index 00000000000..1afbc8d58f7 --- /dev/null +++ b/firewall/lockdown_test.go @@ -0,0 +1,188 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package firewall_test + +import ( + "context" + "errors" + "os" + "testing" + "time" + + "github.com/cloudflare/cloudflare-go/v3" + "github.com/cloudflare/cloudflare-go/v3/firewall" + "github.com/cloudflare/cloudflare-go/v3/internal/testutil" + "github.com/cloudflare/cloudflare-go/v3/option" +) + +func TestLockdownNew(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.Lockdowns.New(context.TODO(), firewall.LockdownNewParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Configurations: cloudflare.F([]firewall.ConfigurationItemUnionParam{firewall.LockdownIPConfigurationParam{ + Target: cloudflare.F(firewall.LockdownIPConfigurationTargetIP), + Value: cloudflare.F("198.51.100.4"), + }, firewall.LockdownIPConfigurationParam{ + Target: cloudflare.F(firewall.LockdownIPConfigurationTargetIP), + Value: cloudflare.F("198.51.100.4"), + }, firewall.LockdownIPConfigurationParam{ + Target: cloudflare.F(firewall.LockdownIPConfigurationTargetIP), + Value: cloudflare.F("198.51.100.4"), + }}), + URLs: cloudflare.F([]firewall.OverrideURLParam{"shop.example.com/*", "shop.example.com/*", "shop.example.com/*"}), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestLockdownUpdate(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.Lockdowns.Update( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b59", + firewall.LockdownUpdateParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Configurations: cloudflare.F([]firewall.ConfigurationItemUnionParam{firewall.LockdownIPConfigurationParam{ + Target: cloudflare.F(firewall.LockdownIPConfigurationTargetIP), + Value: cloudflare.F("198.51.100.4"), + }, firewall.LockdownIPConfigurationParam{ + Target: cloudflare.F(firewall.LockdownIPConfigurationTargetIP), + Value: cloudflare.F("198.51.100.4"), + }, firewall.LockdownIPConfigurationParam{ + Target: cloudflare.F(firewall.LockdownIPConfigurationTargetIP), + Value: cloudflare.F("198.51.100.4"), + }}), + URLs: cloudflare.F([]firewall.OverrideURLParam{"shop.example.com/*", "shop.example.com/*", "shop.example.com/*"}), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestLockdownListWithOptionalParams(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.Lockdowns.List(context.TODO(), firewall.LockdownListParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + CreatedOn: cloudflare.F(time.Now()), + Description: cloudflare.F("endpoints"), + DescriptionSearch: cloudflare.F("endpoints"), + IP: cloudflare.F("1.2.3.4"), + IPRangeSearch: cloudflare.F("1.2.3.0/16"), + IPSearch: cloudflare.F("1.2.3.4"), + ModifiedOn: cloudflare.F(time.Now()), + Page: cloudflare.F(1.000000), + PerPage: cloudflare.F(1.000000), + Priority: cloudflare.F(5.000000), + URISearch: cloudflare.F("/some/path"), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestLockdownDelete(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.Lockdowns.Delete( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b59", + firewall.LockdownDeleteParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestLockdownGet(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.Lockdowns.Get( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b59", + firewall.LockdownGetParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} diff --git a/firewall/rule.go b/firewall/rule.go index e071c9be02d..86b9b9bc9f3 100644 --- a/firewall/rule.go +++ b/firewall/rule.go @@ -3,7 +3,23 @@ package firewall import ( + "context" + "errors" + "fmt" + "net/http" + "net/url" + "reflect" + + "github.com/cloudflare/cloudflare-go/v3/filters" + "github.com/cloudflare/cloudflare-go/v3/internal/apijson" + "github.com/cloudflare/cloudflare-go/v3/internal/apiquery" + "github.com/cloudflare/cloudflare-go/v3/internal/param" + "github.com/cloudflare/cloudflare-go/v3/internal/requestconfig" "github.com/cloudflare/cloudflare-go/v3/option" + "github.com/cloudflare/cloudflare-go/v3/packages/pagination" + "github.com/cloudflare/cloudflare-go/v3/rate_limits" + "github.com/cloudflare/cloudflare-go/v3/shared" + "github.com/tidwall/gjson" ) // RuleService contains methods and other services that help with interacting with @@ -24,3 +40,814 @@ func NewRuleService(opts ...option.RequestOption) (r *RuleService) { r.Options = opts return } + +// Create one or more firewall rules. +// +// Deprecated: The Firewall Rules API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *RuleService) New(ctx context.Context, params RuleNewParams, opts ...option.RequestOption) (res *[]FirewallRule, err error) { + var env RuleNewResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/rules", params.ZoneID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Updates an existing firewall rule. +// +// Deprecated: The Firewall Rules API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *RuleService) Update(ctx context.Context, ruleID string, params RuleUpdateParams, opts ...option.RequestOption) (res *FirewallRule, err error) { + var env RuleUpdateResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if ruleID == "" { + err = errors.New("missing required rule_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/rules/%s", params.ZoneID, ruleID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches firewall rules in a zone. You can filter the results using several +// optional parameters. +// +// Deprecated: The Firewall Rules API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *RuleService) List(ctx context.Context, params RuleListParams, opts ...option.RequestOption) (res *pagination.V4PagePaginationArray[FirewallRule], err error) { + var raw *http.Response + opts = append(r.Options[:], opts...) + opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/rules", params.ZoneID) + cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...) + if err != nil { + return nil, err + } + err = cfg.Execute() + if err != nil { + return nil, err + } + res.SetPageConfig(cfg, raw) + return res, nil +} + +// Fetches firewall rules in a zone. You can filter the results using several +// optional parameters. +// +// Deprecated: The Firewall Rules API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *RuleService) ListAutoPaging(ctx context.Context, params RuleListParams, opts ...option.RequestOption) *pagination.V4PagePaginationArrayAutoPager[FirewallRule] { + return pagination.NewV4PagePaginationArrayAutoPager(r.List(ctx, params, opts...)) +} + +// Deletes an existing firewall rule. +// +// Deprecated: The Firewall Rules API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *RuleService) Delete(ctx context.Context, ruleID string, body RuleDeleteParams, opts ...option.RequestOption) (res *FirewallRule, err error) { + var env RuleDeleteResponseEnvelope + opts = append(r.Options[:], opts...) + if body.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if ruleID == "" { + err = errors.New("missing required rule_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/rules/%s", body.ZoneID, ruleID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Updates the priority of an existing firewall rule. +// +// Deprecated: The Firewall Rules API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *RuleService) Edit(ctx context.Context, ruleID string, body RuleEditParams, opts ...option.RequestOption) (res *[]FirewallRule, err error) { + var env RuleEditResponseEnvelope + opts = append(r.Options[:], opts...) + if body.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if ruleID == "" { + err = errors.New("missing required rule_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/rules/%s", body.ZoneID, ruleID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, body, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches the details of a firewall rule. +// +// Deprecated: The Firewall Rules API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#firewall-rules-api-and-filters-api +// for full details. +func (r *RuleService) Get(ctx context.Context, ruleID string, params RuleGetParams, opts ...option.RequestOption) (res *FirewallRule, err error) { + var env RuleGetResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if ruleID == "" { + err = errors.New("missing required rule_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/rules/%s", params.ZoneID, ruleID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +type FirewallRule struct { + // The unique identifier of the firewall rule. + ID string `json:"id"` + // The action to apply to a matched request. The `log` action is only available on + // an Enterprise plan. + Action rate_limits.Action `json:"action"` + // An informative summary of the firewall rule. + Description string `json:"description"` + Filter FirewallRuleFilter `json:"filter"` + // When true, indicates that the firewall rule is currently paused. + Paused bool `json:"paused"` + // The priority of the rule. Optional value used to define the processing order. A + // lower number indicates a higher priority. If not provided, rules with a defined + // priority will be processed before rules without a priority. + Priority float64 `json:"priority"` + Products []Product `json:"products"` + // A short reference tag. Allows you to select related firewall rules. + Ref string `json:"ref"` + JSON firewallRuleJSON `json:"-"` +} + +// firewallRuleJSON contains the JSON metadata for the struct [FirewallRule] +type firewallRuleJSON struct { + ID apijson.Field + Action apijson.Field + Description apijson.Field + Filter apijson.Field + Paused apijson.Field + Priority apijson.Field + Products apijson.Field + Ref apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *FirewallRule) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r firewallRuleJSON) RawJSON() string { + return r.raw +} + +type FirewallRuleFilter struct { + // The unique identifier of the filter. + ID string `json:"id"` + // When true, indicates that the firewall rule was deleted. + Deleted bool `json:"deleted"` + // An informative summary of the filter. + Description string `json:"description"` + // The filter expression. For more information, refer to + // [Expressions](https://developers.cloudflare.com/ruleset-engine/rules-language/expressions/). + Expression string `json:"expression"` + // When true, indicates that the filter is currently paused. + Paused bool `json:"paused"` + // A short reference tag. Allows you to select related filters. + Ref string `json:"ref"` + JSON firewallRuleFilterJSON `json:"-"` + union FirewallRuleFilterUnion +} + +// firewallRuleFilterJSON contains the JSON metadata for the struct +// [FirewallRuleFilter] +type firewallRuleFilterJSON struct { + ID apijson.Field + Deleted apijson.Field + Description apijson.Field + Expression apijson.Field + Paused apijson.Field + Ref apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r firewallRuleFilterJSON) RawJSON() string { + return r.raw +} + +func (r *FirewallRuleFilter) UnmarshalJSON(data []byte) (err error) { + *r = FirewallRuleFilter{} + err = apijson.UnmarshalRoot(data, &r.union) + if err != nil { + return err + } + return apijson.Port(r.union, &r) +} + +// AsUnion returns a [FirewallRuleFilterUnion] interface which you can cast to the +// specific types for more type safety. +// +// Possible runtime types of the union are [filters.FirewallFilter], +// [firewall.DeletedFilter]. +func (r FirewallRuleFilter) AsUnion() FirewallRuleFilterUnion { + return r.union +} + +// Union satisfied by [filters.FirewallFilter] or [firewall.DeletedFilter]. +type FirewallRuleFilterUnion interface { + ImplementsFirewallFirewallRuleFilter() +} + +func init() { + apijson.RegisterUnion( + reflect.TypeOf((*FirewallRuleFilterUnion)(nil)).Elem(), + "", + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(filters.FirewallFilter{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(DeletedFilter{}), + }, + ) +} + +// A list of products to bypass for a request when using the `bypass` action. +type Product string + +const ( + ProductZoneLockdown Product = "zoneLockdown" + ProductUABlock Product = "uaBlock" + ProductBIC Product = "bic" + ProductHot Product = "hot" + ProductSecurityLevel Product = "securityLevel" + ProductRateLimit Product = "rateLimit" + ProductWAF Product = "waf" +) + +func (r Product) IsKnown() bool { + switch r { + case ProductZoneLockdown, ProductUABlock, ProductBIC, ProductHot, ProductSecurityLevel, ProductRateLimit, ProductWAF: + return true + } + return false +} + +type DeletedFilter struct { + // The unique identifier of the filter. + ID string `json:"id,required"` + // When true, indicates that the firewall rule was deleted. + Deleted bool `json:"deleted,required"` + JSON deletedFilterJSON `json:"-"` +} + +// deletedFilterJSON contains the JSON metadata for the struct [DeletedFilter] +type deletedFilterJSON struct { + ID apijson.Field + Deleted apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *DeletedFilter) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r deletedFilterJSON) RawJSON() string { + return r.raw +} + +func (r DeletedFilter) ImplementsFirewallFirewallRuleFilter() {} + +type RuleNewParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The action to perform when the threshold of matched traffic within the + // configured period is exceeded. + Action param.Field[RuleNewParamsAction] `json:"action,required"` + Filter param.Field[filters.FirewallFilterParam] `json:"filter,required"` +} + +func (r RuleNewParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The action to perform when the threshold of matched traffic within the +// configured period is exceeded. +type RuleNewParamsAction struct { + // The action to perform. + Mode param.Field[RuleNewParamsActionMode] `json:"mode"` + // A custom content type and reponse to return when the threshold is exceeded. The + // custom response configured in this object will override the custom error for the + // zone. This object is optional. Notes: If you omit this object, Cloudflare will + // use the default HTML error page. If "mode" is "challenge", "managed_challenge", + // or "js_challenge", Cloudflare will use the zone challenge pages and you should + // not provide the "response" object. + Response param.Field[RuleNewParamsActionResponse] `json:"response"` + // The time in seconds during which Cloudflare will perform the mitigation action. + // Must be an integer value greater than or equal to the period. Notes: If "mode" + // is "challenge", "managed_challenge", or "js_challenge", Cloudflare will use the + // zone's Challenge Passage time and you should not provide this value. + Timeout param.Field[float64] `json:"timeout"` +} + +func (r RuleNewParamsAction) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The action to perform. +type RuleNewParamsActionMode string + +const ( + RuleNewParamsActionModeSimulate RuleNewParamsActionMode = "simulate" + RuleNewParamsActionModeBan RuleNewParamsActionMode = "ban" + RuleNewParamsActionModeChallenge RuleNewParamsActionMode = "challenge" + RuleNewParamsActionModeJSChallenge RuleNewParamsActionMode = "js_challenge" + RuleNewParamsActionModeManagedChallenge RuleNewParamsActionMode = "managed_challenge" +) + +func (r RuleNewParamsActionMode) IsKnown() bool { + switch r { + case RuleNewParamsActionModeSimulate, RuleNewParamsActionModeBan, RuleNewParamsActionModeChallenge, RuleNewParamsActionModeJSChallenge, RuleNewParamsActionModeManagedChallenge: + return true + } + return false +} + +// A custom content type and reponse to return when the threshold is exceeded. The +// custom response configured in this object will override the custom error for the +// zone. This object is optional. Notes: If you omit this object, Cloudflare will +// use the default HTML error page. If "mode" is "challenge", "managed_challenge", +// or "js_challenge", Cloudflare will use the zone challenge pages and you should +// not provide the "response" object. +type RuleNewParamsActionResponse struct { + // The response body to return. The value must conform to the configured content + // type. + Body param.Field[string] `json:"body"` + // The content type of the body. Must be one of the following: `text/plain`, + // `text/xml`, or `application/json`. + ContentType param.Field[string] `json:"content_type"` +} + +func (r RuleNewParamsActionResponse) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type RuleNewResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result []FirewallRule `json:"result,required,nullable"` + // Whether the API call was successful + Success RuleNewResponseEnvelopeSuccess `json:"success,required"` + ResultInfo RuleNewResponseEnvelopeResultInfo `json:"result_info"` + JSON ruleNewResponseEnvelopeJSON `json:"-"` +} + +// ruleNewResponseEnvelopeJSON contains the JSON metadata for the struct +// [RuleNewResponseEnvelope] +type ruleNewResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + ResultInfo apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RuleNewResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r ruleNewResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type RuleNewResponseEnvelopeSuccess bool + +const ( + RuleNewResponseEnvelopeSuccessTrue RuleNewResponseEnvelopeSuccess = true +) + +func (r RuleNewResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case RuleNewResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type RuleNewResponseEnvelopeResultInfo struct { + // Total number of results for the requested service + Count float64 `json:"count"` + // Current page within paginated list of results + Page float64 `json:"page"` + // Number of results per page of results + PerPage float64 `json:"per_page"` + // Total results available without any search parameters + TotalCount float64 `json:"total_count"` + JSON ruleNewResponseEnvelopeResultInfoJSON `json:"-"` +} + +// ruleNewResponseEnvelopeResultInfoJSON contains the JSON metadata for the struct +// [RuleNewResponseEnvelopeResultInfo] +type ruleNewResponseEnvelopeResultInfoJSON struct { + Count apijson.Field + Page apijson.Field + PerPage apijson.Field + TotalCount apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RuleNewResponseEnvelopeResultInfo) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r ruleNewResponseEnvelopeResultInfoJSON) RawJSON() string { + return r.raw +} + +type RuleUpdateParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The action to perform when the threshold of matched traffic within the + // configured period is exceeded. + Action param.Field[RuleUpdateParamsAction] `json:"action,required"` + Filter param.Field[filters.FirewallFilterParam] `json:"filter,required"` +} + +func (r RuleUpdateParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The action to perform when the threshold of matched traffic within the +// configured period is exceeded. +type RuleUpdateParamsAction struct { + // The action to perform. + Mode param.Field[RuleUpdateParamsActionMode] `json:"mode"` + // A custom content type and reponse to return when the threshold is exceeded. The + // custom response configured in this object will override the custom error for the + // zone. This object is optional. Notes: If you omit this object, Cloudflare will + // use the default HTML error page. If "mode" is "challenge", "managed_challenge", + // or "js_challenge", Cloudflare will use the zone challenge pages and you should + // not provide the "response" object. + Response param.Field[RuleUpdateParamsActionResponse] `json:"response"` + // The time in seconds during which Cloudflare will perform the mitigation action. + // Must be an integer value greater than or equal to the period. Notes: If "mode" + // is "challenge", "managed_challenge", or "js_challenge", Cloudflare will use the + // zone's Challenge Passage time and you should not provide this value. + Timeout param.Field[float64] `json:"timeout"` +} + +func (r RuleUpdateParamsAction) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The action to perform. +type RuleUpdateParamsActionMode string + +const ( + RuleUpdateParamsActionModeSimulate RuleUpdateParamsActionMode = "simulate" + RuleUpdateParamsActionModeBan RuleUpdateParamsActionMode = "ban" + RuleUpdateParamsActionModeChallenge RuleUpdateParamsActionMode = "challenge" + RuleUpdateParamsActionModeJSChallenge RuleUpdateParamsActionMode = "js_challenge" + RuleUpdateParamsActionModeManagedChallenge RuleUpdateParamsActionMode = "managed_challenge" +) + +func (r RuleUpdateParamsActionMode) IsKnown() bool { + switch r { + case RuleUpdateParamsActionModeSimulate, RuleUpdateParamsActionModeBan, RuleUpdateParamsActionModeChallenge, RuleUpdateParamsActionModeJSChallenge, RuleUpdateParamsActionModeManagedChallenge: + return true + } + return false +} + +// A custom content type and reponse to return when the threshold is exceeded. The +// custom response configured in this object will override the custom error for the +// zone. This object is optional. Notes: If you omit this object, Cloudflare will +// use the default HTML error page. If "mode" is "challenge", "managed_challenge", +// or "js_challenge", Cloudflare will use the zone challenge pages and you should +// not provide the "response" object. +type RuleUpdateParamsActionResponse struct { + // The response body to return. The value must conform to the configured content + // type. + Body param.Field[string] `json:"body"` + // The content type of the body. Must be one of the following: `text/plain`, + // `text/xml`, or `application/json`. + ContentType param.Field[string] `json:"content_type"` +} + +func (r RuleUpdateParamsActionResponse) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type RuleUpdateResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result FirewallRule `json:"result,required"` + // Whether the API call was successful + Success RuleUpdateResponseEnvelopeSuccess `json:"success,required"` + JSON ruleUpdateResponseEnvelopeJSON `json:"-"` +} + +// ruleUpdateResponseEnvelopeJSON contains the JSON metadata for the struct +// [RuleUpdateResponseEnvelope] +type ruleUpdateResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RuleUpdateResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r ruleUpdateResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type RuleUpdateResponseEnvelopeSuccess bool + +const ( + RuleUpdateResponseEnvelopeSuccessTrue RuleUpdateResponseEnvelopeSuccess = true +) + +func (r RuleUpdateResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case RuleUpdateResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type RuleListParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The unique identifier of the firewall rule. + ID param.Field[string] `query:"id"` + // The action to search for. Must be an exact match. + Action param.Field[string] `query:"action"` + // A case-insensitive string to find in the description. + Description param.Field[string] `query:"description"` + // Page number of paginated results. + Page param.Field[float64] `query:"page"` + // When true, indicates that the firewall rule is currently paused. + Paused param.Field[bool] `query:"paused"` + // Number of firewall rules per page. + PerPage param.Field[float64] `query:"per_page"` +} + +// URLQuery serializes [RuleListParams]'s query parameters as `url.Values`. +func (r RuleListParams) URLQuery() (v url.Values) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatRepeat, + NestedFormat: apiquery.NestedQueryFormatDots, + }) +} + +type RuleDeleteParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} + +type RuleDeleteResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result FirewallRule `json:"result,required"` + // Whether the API call was successful + Success RuleDeleteResponseEnvelopeSuccess `json:"success,required"` + JSON ruleDeleteResponseEnvelopeJSON `json:"-"` +} + +// ruleDeleteResponseEnvelopeJSON contains the JSON metadata for the struct +// [RuleDeleteResponseEnvelope] +type ruleDeleteResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RuleDeleteResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r ruleDeleteResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type RuleDeleteResponseEnvelopeSuccess bool + +const ( + RuleDeleteResponseEnvelopeSuccessTrue RuleDeleteResponseEnvelopeSuccess = true +) + +func (r RuleDeleteResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case RuleDeleteResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type RuleEditParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} + +func (r RuleEditParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type RuleEditResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result []FirewallRule `json:"result,required,nullable"` + // Whether the API call was successful + Success RuleEditResponseEnvelopeSuccess `json:"success,required"` + ResultInfo RuleEditResponseEnvelopeResultInfo `json:"result_info"` + JSON ruleEditResponseEnvelopeJSON `json:"-"` +} + +// ruleEditResponseEnvelopeJSON contains the JSON metadata for the struct +// [RuleEditResponseEnvelope] +type ruleEditResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + ResultInfo apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RuleEditResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r ruleEditResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type RuleEditResponseEnvelopeSuccess bool + +const ( + RuleEditResponseEnvelopeSuccessTrue RuleEditResponseEnvelopeSuccess = true +) + +func (r RuleEditResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case RuleEditResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type RuleEditResponseEnvelopeResultInfo struct { + // Total number of results for the requested service + Count float64 `json:"count"` + // Current page within paginated list of results + Page float64 `json:"page"` + // Number of results per page of results + PerPage float64 `json:"per_page"` + // Total results available without any search parameters + TotalCount float64 `json:"total_count"` + JSON ruleEditResponseEnvelopeResultInfoJSON `json:"-"` +} + +// ruleEditResponseEnvelopeResultInfoJSON contains the JSON metadata for the struct +// [RuleEditResponseEnvelopeResultInfo] +type ruleEditResponseEnvelopeResultInfoJSON struct { + Count apijson.Field + Page apijson.Field + PerPage apijson.Field + TotalCount apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RuleEditResponseEnvelopeResultInfo) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r ruleEditResponseEnvelopeResultInfoJSON) RawJSON() string { + return r.raw +} + +type RuleGetParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The unique identifier of the firewall rule. + ID param.Field[string] `query:"id"` +} + +// URLQuery serializes [RuleGetParams]'s query parameters as `url.Values`. +func (r RuleGetParams) URLQuery() (v url.Values) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatRepeat, + NestedFormat: apiquery.NestedQueryFormatDots, + }) +} + +type RuleGetResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result FirewallRule `json:"result,required"` + // Whether the API call was successful + Success RuleGetResponseEnvelopeSuccess `json:"success,required"` + JSON ruleGetResponseEnvelopeJSON `json:"-"` +} + +// ruleGetResponseEnvelopeJSON contains the JSON metadata for the struct +// [RuleGetResponseEnvelope] +type ruleGetResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RuleGetResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r ruleGetResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type RuleGetResponseEnvelopeSuccess bool + +const ( + RuleGetResponseEnvelopeSuccessTrue RuleGetResponseEnvelopeSuccess = true +) + +func (r RuleGetResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case RuleGetResponseEnvelopeSuccessTrue: + return true + } + return false +} diff --git a/firewall/rule_test.go b/firewall/rule_test.go new file mode 100644 index 00000000000..4eb79dd7cb5 --- /dev/null +++ b/firewall/rule_test.go @@ -0,0 +1,220 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package firewall_test + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/cloudflare/cloudflare-go/v3" + "github.com/cloudflare/cloudflare-go/v3/filters" + "github.com/cloudflare/cloudflare-go/v3/firewall" + "github.com/cloudflare/cloudflare-go/v3/internal/testutil" + "github.com/cloudflare/cloudflare-go/v3/option" +) + +func TestRuleNewWithOptionalParams(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.Rules.New(context.TODO(), firewall.RuleNewParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Action: cloudflare.F(firewall.RuleNewParamsAction{ + Mode: cloudflare.F(firewall.RuleNewParamsActionModeSimulate), + Response: cloudflare.F(firewall.RuleNewParamsActionResponse{ + Body: cloudflare.F("This request has been rate-limited."), + ContentType: cloudflare.F("text/xml"), + }), + Timeout: cloudflare.F(86400.000000), + }), + Filter: cloudflare.F(filters.FirewallFilterParam{ + Description: cloudflare.F("Restrict access from these browsers on this address range."), + Expression: cloudflare.F("(http.request.uri.path ~ \".*wp-login.php\" or http.request.uri.path ~ \".*xmlrpc.php\") and ip.addr ne 172.16.22.155"), + Paused: cloudflare.F(false), + Ref: cloudflare.F("FIL-100"), + }), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestRuleUpdateWithOptionalParams(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.Rules.Update( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b60", + firewall.RuleUpdateParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Action: cloudflare.F(firewall.RuleUpdateParamsAction{ + Mode: cloudflare.F(firewall.RuleUpdateParamsActionModeSimulate), + Response: cloudflare.F(firewall.RuleUpdateParamsActionResponse{ + Body: cloudflare.F("This request has been rate-limited."), + ContentType: cloudflare.F("text/xml"), + }), + Timeout: cloudflare.F(86400.000000), + }), + Filter: cloudflare.F(filters.FirewallFilterParam{ + Description: cloudflare.F("Restrict access from these browsers on this address range."), + Expression: cloudflare.F("(http.request.uri.path ~ \".*wp-login.php\" or http.request.uri.path ~ \".*xmlrpc.php\") and ip.addr ne 172.16.22.155"), + Paused: cloudflare.F(false), + Ref: cloudflare.F("FIL-100"), + }), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestRuleListWithOptionalParams(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.Rules.List(context.TODO(), firewall.RuleListParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + ID: cloudflare.F("372e67954025e0ba6aaa6d586b9e0b60"), + Action: cloudflare.F("block"), + Description: cloudflare.F("mir"), + Page: cloudflare.F(1.000000), + Paused: cloudflare.F(false), + PerPage: cloudflare.F(5.000000), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestRuleDelete(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.Rules.Delete( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b60", + firewall.RuleDeleteParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestRuleEdit(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.Rules.Edit( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b60", + firewall.RuleEditParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestRuleGetWithOptionalParams(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.Rules.Get( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b60", + firewall.RuleGetParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + ID: cloudflare.F("372e67954025e0ba6aaa6d586b9e0b60"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} diff --git a/firewall/uarule.go b/firewall/uarule.go index 985854af813..72067537219 100644 --- a/firewall/uarule.go +++ b/firewall/uarule.go @@ -3,7 +3,19 @@ package firewall import ( + "context" + "errors" + "fmt" + "net/http" + "net/url" + + "github.com/cloudflare/cloudflare-go/v3/internal/apijson" + "github.com/cloudflare/cloudflare-go/v3/internal/apiquery" + "github.com/cloudflare/cloudflare-go/v3/internal/param" + "github.com/cloudflare/cloudflare-go/v3/internal/requestconfig" "github.com/cloudflare/cloudflare-go/v3/option" + "github.com/cloudflare/cloudflare-go/v3/packages/pagination" + "github.com/cloudflare/cloudflare-go/v3/shared" ) // UARuleService contains methods and other services that help with interacting @@ -24,3 +36,576 @@ func NewUARuleService(opts ...option.RequestOption) (r *UARuleService) { r.Options = opts return } + +// Creates a new User Agent Blocking rule in a zone. +func (r *UARuleService) New(ctx context.Context, params UARuleNewParams, opts ...option.RequestOption) (res *interface{}, err error) { + var env UARuleNewResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/ua_rules", params.ZoneID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Updates an existing User Agent Blocking rule. +func (r *UARuleService) Update(ctx context.Context, uaRuleID string, params UARuleUpdateParams, opts ...option.RequestOption) (res *interface{}, err error) { + var env UARuleUpdateResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if uaRuleID == "" { + err = errors.New("missing required ua_rule_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/ua_rules/%s", params.ZoneID, uaRuleID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches User Agent Blocking rules in a zone. You can filter the results using +// several optional parameters. +func (r *UARuleService) List(ctx context.Context, params UARuleListParams, opts ...option.RequestOption) (res *pagination.V4PagePaginationArray[UARuleListResponse], err error) { + var raw *http.Response + opts = append(r.Options[:], opts...) + opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/ua_rules", params.ZoneID) + cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...) + if err != nil { + return nil, err + } + err = cfg.Execute() + if err != nil { + return nil, err + } + res.SetPageConfig(cfg, raw) + return res, nil +} + +// Fetches User Agent Blocking rules in a zone. You can filter the results using +// several optional parameters. +func (r *UARuleService) ListAutoPaging(ctx context.Context, params UARuleListParams, opts ...option.RequestOption) *pagination.V4PagePaginationArrayAutoPager[UARuleListResponse] { + return pagination.NewV4PagePaginationArrayAutoPager(r.List(ctx, params, opts...)) +} + +// Deletes an existing User Agent Blocking rule. +func (r *UARuleService) Delete(ctx context.Context, uaRuleID string, body UARuleDeleteParams, opts ...option.RequestOption) (res *UARuleDeleteResponse, err error) { + var env UARuleDeleteResponseEnvelope + opts = append(r.Options[:], opts...) + if body.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if uaRuleID == "" { + err = errors.New("missing required ua_rule_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/ua_rules/%s", body.ZoneID, uaRuleID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches the details of a User Agent Blocking rule. +func (r *UARuleService) Get(ctx context.Context, uaRuleID string, query UARuleGetParams, opts ...option.RequestOption) (res *interface{}, err error) { + var env UARuleGetResponseEnvelope + opts = append(r.Options[:], opts...) + if query.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if uaRuleID == "" { + err = errors.New("missing required ua_rule_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/ua_rules/%s", query.ZoneID, uaRuleID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +type UARuleListResponse struct { + // The unique identifier of the User Agent Blocking rule. + ID string `json:"id"` + // The configuration object for the current rule. + Configuration UARuleListResponseConfiguration `json:"configuration"` + // An informative summary of the rule. + Description string `json:"description"` + // The action to apply to a matched request. + Mode UARuleListResponseMode `json:"mode"` + // When true, indicates that the rule is currently paused. + Paused bool `json:"paused"` + JSON uaRuleListResponseJSON `json:"-"` +} + +// uaRuleListResponseJSON contains the JSON metadata for the struct +// [UARuleListResponse] +type uaRuleListResponseJSON struct { + ID apijson.Field + Configuration apijson.Field + Description apijson.Field + Mode apijson.Field + Paused apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *UARuleListResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r uaRuleListResponseJSON) RawJSON() string { + return r.raw +} + +// The configuration object for the current rule. +type UARuleListResponseConfiguration struct { + // The configuration target for this rule. You must set the target to `ua` for User + // Agent Blocking rules. + Target string `json:"target"` + // The exact user agent string to match. This value will be compared to the + // received `User-Agent` HTTP header value. + Value string `json:"value"` + JSON uaRuleListResponseConfigurationJSON `json:"-"` +} + +// uaRuleListResponseConfigurationJSON contains the JSON metadata for the struct +// [UARuleListResponseConfiguration] +type uaRuleListResponseConfigurationJSON struct { + Target apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *UARuleListResponseConfiguration) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r uaRuleListResponseConfigurationJSON) RawJSON() string { + return r.raw +} + +// The action to apply to a matched request. +type UARuleListResponseMode string + +const ( + UARuleListResponseModeBlock UARuleListResponseMode = "block" + UARuleListResponseModeChallenge UARuleListResponseMode = "challenge" + UARuleListResponseModeJSChallenge UARuleListResponseMode = "js_challenge" + UARuleListResponseModeManagedChallenge UARuleListResponseMode = "managed_challenge" +) + +func (r UARuleListResponseMode) IsKnown() bool { + switch r { + case UARuleListResponseModeBlock, UARuleListResponseModeChallenge, UARuleListResponseModeJSChallenge, UARuleListResponseModeManagedChallenge: + return true + } + return false +} + +type UARuleDeleteResponse struct { + // The unique identifier of the User Agent Blocking rule. + ID string `json:"id"` + JSON uaRuleDeleteResponseJSON `json:"-"` +} + +// uaRuleDeleteResponseJSON contains the JSON metadata for the struct +// [UARuleDeleteResponse] +type uaRuleDeleteResponseJSON struct { + ID apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *UARuleDeleteResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r uaRuleDeleteResponseJSON) RawJSON() string { + return r.raw +} + +type UARuleNewParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The rule configuration. + Configuration param.Field[UARuleNewParamsConfigurationUnion] `json:"configuration,required"` + // The action to apply to a matched request. + Mode param.Field[UARuleNewParamsMode] `json:"mode,required"` +} + +func (r UARuleNewParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The rule configuration. +type UARuleNewParamsConfiguration struct { + // The configuration target. You must set the target to `ip` when specifying an IP + // address in the rule. + Target param.Field[UARuleNewParamsConfigurationTarget] `json:"target"` + // The IP address to match. This address will be compared to the IP address of + // incoming requests. + Value param.Field[string] `json:"value"` +} + +func (r UARuleNewParamsConfiguration) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +func (r UARuleNewParamsConfiguration) implementsFirewallUARuleNewParamsConfigurationUnion() {} + +// The rule configuration. +// +// Satisfied by [firewall.AccessRuleIPConfigurationParam], +// [firewall.IPV6ConfigurationParam], [firewall.AccessRuleCIDRConfigurationParam], +// [firewall.ASNConfigurationParam], [firewall.CountryConfigurationParam], +// [UARuleNewParamsConfiguration]. +type UARuleNewParamsConfigurationUnion interface { + implementsFirewallUARuleNewParamsConfigurationUnion() +} + +// The configuration target. You must set the target to `ip` when specifying an IP +// address in the rule. +type UARuleNewParamsConfigurationTarget string + +const ( + UARuleNewParamsConfigurationTargetIP UARuleNewParamsConfigurationTarget = "ip" + UARuleNewParamsConfigurationTargetIp6 UARuleNewParamsConfigurationTarget = "ip6" + UARuleNewParamsConfigurationTargetIPRange UARuleNewParamsConfigurationTarget = "ip_range" + UARuleNewParamsConfigurationTargetASN UARuleNewParamsConfigurationTarget = "asn" + UARuleNewParamsConfigurationTargetCountry UARuleNewParamsConfigurationTarget = "country" +) + +func (r UARuleNewParamsConfigurationTarget) IsKnown() bool { + switch r { + case UARuleNewParamsConfigurationTargetIP, UARuleNewParamsConfigurationTargetIp6, UARuleNewParamsConfigurationTargetIPRange, UARuleNewParamsConfigurationTargetASN, UARuleNewParamsConfigurationTargetCountry: + return true + } + return false +} + +// The action to apply to a matched request. +type UARuleNewParamsMode string + +const ( + UARuleNewParamsModeBlock UARuleNewParamsMode = "block" + UARuleNewParamsModeChallenge UARuleNewParamsMode = "challenge" + UARuleNewParamsModeWhitelist UARuleNewParamsMode = "whitelist" + UARuleNewParamsModeJSChallenge UARuleNewParamsMode = "js_challenge" + UARuleNewParamsModeManagedChallenge UARuleNewParamsMode = "managed_challenge" +) + +func (r UARuleNewParamsMode) IsKnown() bool { + switch r { + case UARuleNewParamsModeBlock, UARuleNewParamsModeChallenge, UARuleNewParamsModeWhitelist, UARuleNewParamsModeJSChallenge, UARuleNewParamsModeManagedChallenge: + return true + } + return false +} + +type UARuleNewResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result interface{} `json:"result,required"` + // Whether the API call was successful + Success UARuleNewResponseEnvelopeSuccess `json:"success,required"` + JSON uaRuleNewResponseEnvelopeJSON `json:"-"` +} + +// uaRuleNewResponseEnvelopeJSON contains the JSON metadata for the struct +// [UARuleNewResponseEnvelope] +type uaRuleNewResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *UARuleNewResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r uaRuleNewResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type UARuleNewResponseEnvelopeSuccess bool + +const ( + UARuleNewResponseEnvelopeSuccessTrue UARuleNewResponseEnvelopeSuccess = true +) + +func (r UARuleNewResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case UARuleNewResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type UARuleUpdateParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The rule configuration. + Configuration param.Field[UARuleUpdateParamsConfigurationUnion] `json:"configuration,required"` + // The action to apply to a matched request. + Mode param.Field[UARuleUpdateParamsMode] `json:"mode,required"` +} + +func (r UARuleUpdateParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The rule configuration. +type UARuleUpdateParamsConfiguration struct { + // The configuration target. You must set the target to `ip` when specifying an IP + // address in the rule. + Target param.Field[UARuleUpdateParamsConfigurationTarget] `json:"target"` + // The IP address to match. This address will be compared to the IP address of + // incoming requests. + Value param.Field[string] `json:"value"` +} + +func (r UARuleUpdateParamsConfiguration) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +func (r UARuleUpdateParamsConfiguration) implementsFirewallUARuleUpdateParamsConfigurationUnion() {} + +// The rule configuration. +// +// Satisfied by [firewall.AccessRuleIPConfigurationParam], +// [firewall.IPV6ConfigurationParam], [firewall.AccessRuleCIDRConfigurationParam], +// [firewall.ASNConfigurationParam], [firewall.CountryConfigurationParam], +// [UARuleUpdateParamsConfiguration]. +type UARuleUpdateParamsConfigurationUnion interface { + implementsFirewallUARuleUpdateParamsConfigurationUnion() +} + +// The configuration target. You must set the target to `ip` when specifying an IP +// address in the rule. +type UARuleUpdateParamsConfigurationTarget string + +const ( + UARuleUpdateParamsConfigurationTargetIP UARuleUpdateParamsConfigurationTarget = "ip" + UARuleUpdateParamsConfigurationTargetIp6 UARuleUpdateParamsConfigurationTarget = "ip6" + UARuleUpdateParamsConfigurationTargetIPRange UARuleUpdateParamsConfigurationTarget = "ip_range" + UARuleUpdateParamsConfigurationTargetASN UARuleUpdateParamsConfigurationTarget = "asn" + UARuleUpdateParamsConfigurationTargetCountry UARuleUpdateParamsConfigurationTarget = "country" +) + +func (r UARuleUpdateParamsConfigurationTarget) IsKnown() bool { + switch r { + case UARuleUpdateParamsConfigurationTargetIP, UARuleUpdateParamsConfigurationTargetIp6, UARuleUpdateParamsConfigurationTargetIPRange, UARuleUpdateParamsConfigurationTargetASN, UARuleUpdateParamsConfigurationTargetCountry: + return true + } + return false +} + +// The action to apply to a matched request. +type UARuleUpdateParamsMode string + +const ( + UARuleUpdateParamsModeBlock UARuleUpdateParamsMode = "block" + UARuleUpdateParamsModeChallenge UARuleUpdateParamsMode = "challenge" + UARuleUpdateParamsModeWhitelist UARuleUpdateParamsMode = "whitelist" + UARuleUpdateParamsModeJSChallenge UARuleUpdateParamsMode = "js_challenge" + UARuleUpdateParamsModeManagedChallenge UARuleUpdateParamsMode = "managed_challenge" +) + +func (r UARuleUpdateParamsMode) IsKnown() bool { + switch r { + case UARuleUpdateParamsModeBlock, UARuleUpdateParamsModeChallenge, UARuleUpdateParamsModeWhitelist, UARuleUpdateParamsModeJSChallenge, UARuleUpdateParamsModeManagedChallenge: + return true + } + return false +} + +type UARuleUpdateResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result interface{} `json:"result,required"` + // Whether the API call was successful + Success UARuleUpdateResponseEnvelopeSuccess `json:"success,required"` + JSON uaRuleUpdateResponseEnvelopeJSON `json:"-"` +} + +// uaRuleUpdateResponseEnvelopeJSON contains the JSON metadata for the struct +// [UARuleUpdateResponseEnvelope] +type uaRuleUpdateResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *UARuleUpdateResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r uaRuleUpdateResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type UARuleUpdateResponseEnvelopeSuccess bool + +const ( + UARuleUpdateResponseEnvelopeSuccessTrue UARuleUpdateResponseEnvelopeSuccess = true +) + +func (r UARuleUpdateResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case UARuleUpdateResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type UARuleListParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // A string to search for in the description of existing rules. + Description param.Field[string] `query:"description"` + // A string to search for in the description of existing rules. + DescriptionSearch param.Field[string] `query:"description_search"` + // Page number of paginated results. + Page param.Field[float64] `query:"page"` + // The maximum number of results per page. You can only set the value to `1` or to + // a multiple of 5 such as `5`, `10`, `15`, or `20`. + PerPage param.Field[float64] `query:"per_page"` + // A string to search for in the user agent values of existing rules. + UASearch param.Field[string] `query:"ua_search"` +} + +// URLQuery serializes [UARuleListParams]'s query parameters as `url.Values`. +func (r UARuleListParams) URLQuery() (v url.Values) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatRepeat, + NestedFormat: apiquery.NestedQueryFormatDots, + }) +} + +type UARuleDeleteParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} + +type UARuleDeleteResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result UARuleDeleteResponse `json:"result,required"` + // Whether the API call was successful + Success UARuleDeleteResponseEnvelopeSuccess `json:"success,required"` + JSON uaRuleDeleteResponseEnvelopeJSON `json:"-"` +} + +// uaRuleDeleteResponseEnvelopeJSON contains the JSON metadata for the struct +// [UARuleDeleteResponseEnvelope] +type uaRuleDeleteResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *UARuleDeleteResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r uaRuleDeleteResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type UARuleDeleteResponseEnvelopeSuccess bool + +const ( + UARuleDeleteResponseEnvelopeSuccessTrue UARuleDeleteResponseEnvelopeSuccess = true +) + +func (r UARuleDeleteResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case UARuleDeleteResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type UARuleGetParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} + +type UARuleGetResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result interface{} `json:"result,required"` + // Whether the API call was successful + Success UARuleGetResponseEnvelopeSuccess `json:"success,required"` + JSON uaRuleGetResponseEnvelopeJSON `json:"-"` +} + +// uaRuleGetResponseEnvelopeJSON contains the JSON metadata for the struct +// [UARuleGetResponseEnvelope] +type uaRuleGetResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *UARuleGetResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r uaRuleGetResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type UARuleGetResponseEnvelopeSuccess bool + +const ( + UARuleGetResponseEnvelopeSuccessTrue UARuleGetResponseEnvelopeSuccess = true +) + +func (r UARuleGetResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case UARuleGetResponseEnvelopeSuccessTrue: + return true + } + return false +} diff --git a/firewall/uarule_test.go b/firewall/uarule_test.go new file mode 100644 index 00000000000..6802510bcd0 --- /dev/null +++ b/firewall/uarule_test.go @@ -0,0 +1,169 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package firewall_test + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/cloudflare/cloudflare-go/v3" + "github.com/cloudflare/cloudflare-go/v3/firewall" + "github.com/cloudflare/cloudflare-go/v3/internal/testutil" + "github.com/cloudflare/cloudflare-go/v3/option" +) + +func TestUARuleNewWithOptionalParams(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.UARules.New(context.TODO(), firewall.UARuleNewParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Configuration: cloudflare.F[firewall.UARuleNewParamsConfigurationUnion](firewall.AccessRuleIPConfigurationParam{ + Target: cloudflare.F(firewall.AccessRuleIPConfigurationTargetIP), + Value: cloudflare.F("198.51.100.4"), + }), + Mode: cloudflare.F(firewall.UARuleNewParamsModeBlock), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestUARuleUpdateWithOptionalParams(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.UARules.Update( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b59", + firewall.UARuleUpdateParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Configuration: cloudflare.F[firewall.UARuleUpdateParamsConfigurationUnion](firewall.AccessRuleIPConfigurationParam{ + Target: cloudflare.F(firewall.AccessRuleIPConfigurationTargetIP), + Value: cloudflare.F("198.51.100.4"), + }), + Mode: cloudflare.F(firewall.UARuleUpdateParamsModeBlock), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestUARuleListWithOptionalParams(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.UARules.List(context.TODO(), firewall.UARuleListParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Description: cloudflare.F("abusive"), + DescriptionSearch: cloudflare.F("abusive"), + Page: cloudflare.F(1.000000), + PerPage: cloudflare.F(1.000000), + UASearch: cloudflare.F("Safari"), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestUARuleDelete(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.UARules.Delete( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b59", + firewall.UARuleDeleteParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestUARuleGet(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.UARules.Get( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b59", + firewall.UARuleGetParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} diff --git a/firewall/wafoverride.go b/firewall/wafoverride.go index 86642a414fa..879392ad64b 100644 --- a/firewall/wafoverride.go +++ b/firewall/wafoverride.go @@ -3,7 +3,19 @@ package firewall import ( + "context" + "errors" + "fmt" + "net/http" + "net/url" + + "github.com/cloudflare/cloudflare-go/v3/internal/apijson" + "github.com/cloudflare/cloudflare-go/v3/internal/apiquery" + "github.com/cloudflare/cloudflare-go/v3/internal/param" + "github.com/cloudflare/cloudflare-go/v3/internal/requestconfig" "github.com/cloudflare/cloudflare-go/v3/option" + "github.com/cloudflare/cloudflare-go/v3/packages/pagination" + "github.com/cloudflare/cloudflare-go/v3/shared" ) // WAFOverrideService contains methods and other services that help with @@ -24,3 +36,595 @@ func NewWAFOverrideService(opts ...option.RequestOption) (r *WAFOverrideService) r.Options = opts return } + +// Creates a URI-based WAF override for a zone. +// +// **Note:** Applies only to the +// [previous version of WAF managed rules](https://developers.cloudflare.com/support/firewall/managed-rules-web-application-firewall-waf/understanding-waf-managed-rules-web-application-firewall/). +func (r *WAFOverrideService) New(ctx context.Context, params WAFOverrideNewParams, opts ...option.RequestOption) (res *Override, err error) { + var env WAFOverrideNewResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/waf/overrides", params.ZoneID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Updates an existing URI-based WAF override. +// +// **Note:** Applies only to the +// [previous version of WAF managed rules](https://developers.cloudflare.com/support/firewall/managed-rules-web-application-firewall-waf/understanding-waf-managed-rules-web-application-firewall/). +func (r *WAFOverrideService) Update(ctx context.Context, overridesID string, params WAFOverrideUpdateParams, opts ...option.RequestOption) (res *Override, err error) { + var env WAFOverrideUpdateResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if overridesID == "" { + err = errors.New("missing required overrides_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/waf/overrides/%s", params.ZoneID, overridesID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches the URI-based WAF overrides in a zone. +// +// **Note:** Applies only to the +// [previous version of WAF managed rules](https://developers.cloudflare.com/support/firewall/managed-rules-web-application-firewall-waf/understanding-waf-managed-rules-web-application-firewall/). +func (r *WAFOverrideService) List(ctx context.Context, params WAFOverrideListParams, opts ...option.RequestOption) (res *pagination.V4PagePaginationArray[Override], err error) { + var raw *http.Response + opts = append(r.Options[:], opts...) + opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/waf/overrides", params.ZoneID) + cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...) + if err != nil { + return nil, err + } + err = cfg.Execute() + if err != nil { + return nil, err + } + res.SetPageConfig(cfg, raw) + return res, nil +} + +// Fetches the URI-based WAF overrides in a zone. +// +// **Note:** Applies only to the +// [previous version of WAF managed rules](https://developers.cloudflare.com/support/firewall/managed-rules-web-application-firewall-waf/understanding-waf-managed-rules-web-application-firewall/). +func (r *WAFOverrideService) ListAutoPaging(ctx context.Context, params WAFOverrideListParams, opts ...option.RequestOption) *pagination.V4PagePaginationArrayAutoPager[Override] { + return pagination.NewV4PagePaginationArrayAutoPager(r.List(ctx, params, opts...)) +} + +// Deletes an existing URI-based WAF override. +// +// **Note:** Applies only to the +// [previous version of WAF managed rules](https://developers.cloudflare.com/support/firewall/managed-rules-web-application-firewall-waf/understanding-waf-managed-rules-web-application-firewall/). +func (r *WAFOverrideService) Delete(ctx context.Context, overridesID string, body WAFOverrideDeleteParams, opts ...option.RequestOption) (res *WAFOverrideDeleteResponse, err error) { + var env WAFOverrideDeleteResponseEnvelope + opts = append(r.Options[:], opts...) + if body.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if overridesID == "" { + err = errors.New("missing required overrides_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/waf/overrides/%s", body.ZoneID, overridesID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches the details of a URI-based WAF override. +// +// **Note:** Applies only to the +// [previous version of WAF managed rules](https://developers.cloudflare.com/support/firewall/managed-rules-web-application-firewall-waf/understanding-waf-managed-rules-web-application-firewall/). +func (r *WAFOverrideService) Get(ctx context.Context, overridesID string, query WAFOverrideGetParams, opts ...option.RequestOption) (res *Override, err error) { + var env WAFOverrideGetResponseEnvelope + opts = append(r.Options[:], opts...) + if query.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if overridesID == "" { + err = errors.New("missing required overrides_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/waf/overrides/%s", query.ZoneID, overridesID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +type Override struct { + // The unique identifier of the WAF override. + ID string `json:"id"` + // An informative summary of the current URI-based WAF override. + Description string `json:"description,nullable"` + // An object that allows you to enable or disable WAF rule groups for the current + // WAF override. Each key of this object must be the ID of a WAF rule group, and + // each value must be a valid WAF action (usually `default` or `disable`). When + // creating a new URI-based WAF override, you must provide a `groups` object or a + // `rules` object. + Groups map[string]interface{} `json:"groups"` + // When true, indicates that the WAF package is currently paused. + Paused bool `json:"paused"` + // The relative priority of the current URI-based WAF override when multiple + // overrides match a single URL. A lower number indicates higher priority. Higher + // priority overrides may overwrite values set by lower priority overrides. + Priority float64 `json:"priority"` + // Specifies that, when a WAF rule matches, its configured action will be replaced + // by the action configured in this object. + RewriteAction RewriteAction `json:"rewrite_action"` + // An object that allows you to override the action of specific WAF rules. Each key + // of this object must be the ID of a WAF rule, and each value must be a valid WAF + // action. Unless you are disabling a rule, ensure that you also enable the rule + // group that this WAF rule belongs to. When creating a new URI-based WAF override, + // you must provide a `groups` object or a `rules` object. + Rules WAFRule `json:"rules"` + // The URLs to include in the current WAF override. You can use wildcards. Each + // entered URL will be escaped before use, which means you can only use simple + // wildcard patterns. + URLs []OverrideURL `json:"urls"` + JSON overrideJSON `json:"-"` +} + +// overrideJSON contains the JSON metadata for the struct [Override] +type overrideJSON struct { + ID apijson.Field + Description apijson.Field + Groups apijson.Field + Paused apijson.Field + Priority apijson.Field + RewriteAction apijson.Field + Rules apijson.Field + URLs apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *Override) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r overrideJSON) RawJSON() string { + return r.raw +} + +type OverrideURL = string + +type OverrideURLParam = string + +// Specifies that, when a WAF rule matches, its configured action will be replaced +// by the action configured in this object. +type RewriteAction struct { + // The WAF rule action to apply. + Block RewriteActionBlock `json:"block"` + // The WAF rule action to apply. + Challenge RewriteActionChallenge `json:"challenge"` + // The WAF rule action to apply. + Default RewriteActionDefault `json:"default"` + // The WAF rule action to apply. + Disable RewriteActionDisable `json:"disable"` + // The WAF rule action to apply. + Simulate RewriteActionSimulate `json:"simulate"` + JSON rewriteActionJSON `json:"-"` +} + +// rewriteActionJSON contains the JSON metadata for the struct [RewriteAction] +type rewriteActionJSON struct { + Block apijson.Field + Challenge apijson.Field + Default apijson.Field + Disable apijson.Field + Simulate apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RewriteAction) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rewriteActionJSON) RawJSON() string { + return r.raw +} + +// The WAF rule action to apply. +type RewriteActionBlock string + +const ( + RewriteActionBlockChallenge RewriteActionBlock = "challenge" + RewriteActionBlockBlock RewriteActionBlock = "block" + RewriteActionBlockSimulate RewriteActionBlock = "simulate" + RewriteActionBlockDisable RewriteActionBlock = "disable" + RewriteActionBlockDefault RewriteActionBlock = "default" +) + +func (r RewriteActionBlock) IsKnown() bool { + switch r { + case RewriteActionBlockChallenge, RewriteActionBlockBlock, RewriteActionBlockSimulate, RewriteActionBlockDisable, RewriteActionBlockDefault: + return true + } + return false +} + +// The WAF rule action to apply. +type RewriteActionChallenge string + +const ( + RewriteActionChallengeChallenge RewriteActionChallenge = "challenge" + RewriteActionChallengeBlock RewriteActionChallenge = "block" + RewriteActionChallengeSimulate RewriteActionChallenge = "simulate" + RewriteActionChallengeDisable RewriteActionChallenge = "disable" + RewriteActionChallengeDefault RewriteActionChallenge = "default" +) + +func (r RewriteActionChallenge) IsKnown() bool { + switch r { + case RewriteActionChallengeChallenge, RewriteActionChallengeBlock, RewriteActionChallengeSimulate, RewriteActionChallengeDisable, RewriteActionChallengeDefault: + return true + } + return false +} + +// The WAF rule action to apply. +type RewriteActionDefault string + +const ( + RewriteActionDefaultChallenge RewriteActionDefault = "challenge" + RewriteActionDefaultBlock RewriteActionDefault = "block" + RewriteActionDefaultSimulate RewriteActionDefault = "simulate" + RewriteActionDefaultDisable RewriteActionDefault = "disable" + RewriteActionDefaultDefault RewriteActionDefault = "default" +) + +func (r RewriteActionDefault) IsKnown() bool { + switch r { + case RewriteActionDefaultChallenge, RewriteActionDefaultBlock, RewriteActionDefaultSimulate, RewriteActionDefaultDisable, RewriteActionDefaultDefault: + return true + } + return false +} + +// The WAF rule action to apply. +type RewriteActionDisable string + +const ( + RewriteActionDisableChallenge RewriteActionDisable = "challenge" + RewriteActionDisableBlock RewriteActionDisable = "block" + RewriteActionDisableSimulate RewriteActionDisable = "simulate" + RewriteActionDisableDisable RewriteActionDisable = "disable" + RewriteActionDisableDefault RewriteActionDisable = "default" +) + +func (r RewriteActionDisable) IsKnown() bool { + switch r { + case RewriteActionDisableChallenge, RewriteActionDisableBlock, RewriteActionDisableSimulate, RewriteActionDisableDisable, RewriteActionDisableDefault: + return true + } + return false +} + +// The WAF rule action to apply. +type RewriteActionSimulate string + +const ( + RewriteActionSimulateChallenge RewriteActionSimulate = "challenge" + RewriteActionSimulateBlock RewriteActionSimulate = "block" + RewriteActionSimulateSimulate RewriteActionSimulate = "simulate" + RewriteActionSimulateDisable RewriteActionSimulate = "disable" + RewriteActionSimulateDefault RewriteActionSimulate = "default" +) + +func (r RewriteActionSimulate) IsKnown() bool { + switch r { + case RewriteActionSimulateChallenge, RewriteActionSimulateBlock, RewriteActionSimulateSimulate, RewriteActionSimulateDisable, RewriteActionSimulateDefault: + return true + } + return false +} + +// Specifies that, when a WAF rule matches, its configured action will be replaced +// by the action configured in this object. +type RewriteActionParam struct { + // The WAF rule action to apply. + Block param.Field[RewriteActionBlock] `json:"block"` + // The WAF rule action to apply. + Challenge param.Field[RewriteActionChallenge] `json:"challenge"` + // The WAF rule action to apply. + Default param.Field[RewriteActionDefault] `json:"default"` + // The WAF rule action to apply. + Disable param.Field[RewriteActionDisable] `json:"disable"` + // The WAF rule action to apply. + Simulate param.Field[RewriteActionSimulate] `json:"simulate"` +} + +func (r RewriteActionParam) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type WAFRule map[string]WAFRuleItem + +// The WAF rule action to apply. +type WAFRuleItem string + +const ( + WAFRuleItemChallenge WAFRuleItem = "challenge" + WAFRuleItemBlock WAFRuleItem = "block" + WAFRuleItemSimulate WAFRuleItem = "simulate" + WAFRuleItemDisable WAFRuleItem = "disable" + WAFRuleItemDefault WAFRuleItem = "default" +) + +func (r WAFRuleItem) IsKnown() bool { + switch r { + case WAFRuleItemChallenge, WAFRuleItemBlock, WAFRuleItemSimulate, WAFRuleItemDisable, WAFRuleItemDefault: + return true + } + return false +} + +type WAFRuleParam map[string]WAFRuleItem + +type WAFOverrideDeleteResponse struct { + // The unique identifier of the WAF override. + ID string `json:"id"` + JSON wafOverrideDeleteResponseJSON `json:"-"` +} + +// wafOverrideDeleteResponseJSON contains the JSON metadata for the struct +// [WAFOverrideDeleteResponse] +type wafOverrideDeleteResponseJSON struct { + ID apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *WAFOverrideDeleteResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r wafOverrideDeleteResponseJSON) RawJSON() string { + return r.raw +} + +type WAFOverrideNewParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The URLs to include in the current WAF override. You can use wildcards. Each + // entered URL will be escaped before use, which means you can only use simple + // wildcard patterns. + URLs param.Field[[]OverrideURLParam] `json:"urls,required"` +} + +func (r WAFOverrideNewParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type WAFOverrideNewResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result Override `json:"result,required"` + // Whether the API call was successful + Success WAFOverrideNewResponseEnvelopeSuccess `json:"success,required"` + JSON wafOverrideNewResponseEnvelopeJSON `json:"-"` +} + +// wafOverrideNewResponseEnvelopeJSON contains the JSON metadata for the struct +// [WAFOverrideNewResponseEnvelope] +type wafOverrideNewResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *WAFOverrideNewResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r wafOverrideNewResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type WAFOverrideNewResponseEnvelopeSuccess bool + +const ( + WAFOverrideNewResponseEnvelopeSuccessTrue WAFOverrideNewResponseEnvelopeSuccess = true +) + +func (r WAFOverrideNewResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case WAFOverrideNewResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type WAFOverrideUpdateParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // Identifier + ID param.Field[string] `json:"id,required"` + // Specifies that, when a WAF rule matches, its configured action will be replaced + // by the action configured in this object. + RewriteAction param.Field[RewriteActionParam] `json:"rewrite_action,required"` + // An object that allows you to override the action of specific WAF rules. Each key + // of this object must be the ID of a WAF rule, and each value must be a valid WAF + // action. Unless you are disabling a rule, ensure that you also enable the rule + // group that this WAF rule belongs to. When creating a new URI-based WAF override, + // you must provide a `groups` object or a `rules` object. + Rules param.Field[WAFRuleParam] `json:"rules,required"` + // The URLs to include in the current WAF override. You can use wildcards. Each + // entered URL will be escaped before use, which means you can only use simple + // wildcard patterns. + URLs param.Field[[]OverrideURLParam] `json:"urls,required"` +} + +func (r WAFOverrideUpdateParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type WAFOverrideUpdateResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result Override `json:"result,required"` + // Whether the API call was successful + Success WAFOverrideUpdateResponseEnvelopeSuccess `json:"success,required"` + JSON wafOverrideUpdateResponseEnvelopeJSON `json:"-"` +} + +// wafOverrideUpdateResponseEnvelopeJSON contains the JSON metadata for the struct +// [WAFOverrideUpdateResponseEnvelope] +type wafOverrideUpdateResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *WAFOverrideUpdateResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r wafOverrideUpdateResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type WAFOverrideUpdateResponseEnvelopeSuccess bool + +const ( + WAFOverrideUpdateResponseEnvelopeSuccessTrue WAFOverrideUpdateResponseEnvelopeSuccess = true +) + +func (r WAFOverrideUpdateResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case WAFOverrideUpdateResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type WAFOverrideListParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The page number of paginated results. + Page param.Field[float64] `query:"page"` + // The number of WAF overrides per page. + PerPage param.Field[float64] `query:"per_page"` +} + +// URLQuery serializes [WAFOverrideListParams]'s query parameters as `url.Values`. +func (r WAFOverrideListParams) URLQuery() (v url.Values) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatRepeat, + NestedFormat: apiquery.NestedQueryFormatDots, + }) +} + +type WAFOverrideDeleteParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} + +type WAFOverrideDeleteResponseEnvelope struct { + Result WAFOverrideDeleteResponse `json:"result"` + JSON wafOverrideDeleteResponseEnvelopeJSON `json:"-"` +} + +// wafOverrideDeleteResponseEnvelopeJSON contains the JSON metadata for the struct +// [WAFOverrideDeleteResponseEnvelope] +type wafOverrideDeleteResponseEnvelopeJSON struct { + Result apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *WAFOverrideDeleteResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r wafOverrideDeleteResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +type WAFOverrideGetParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} + +type WAFOverrideGetResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result Override `json:"result,required"` + // Whether the API call was successful + Success WAFOverrideGetResponseEnvelopeSuccess `json:"success,required"` + JSON wafOverrideGetResponseEnvelopeJSON `json:"-"` +} + +// wafOverrideGetResponseEnvelopeJSON contains the JSON metadata for the struct +// [WAFOverrideGetResponseEnvelope] +type wafOverrideGetResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *WAFOverrideGetResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r wafOverrideGetResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type WAFOverrideGetResponseEnvelopeSuccess bool + +const ( + WAFOverrideGetResponseEnvelopeSuccessTrue WAFOverrideGetResponseEnvelopeSuccess = true +) + +func (r WAFOverrideGetResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case WAFOverrideGetResponseEnvelopeSuccessTrue: + return true + } + return false +} diff --git a/firewall/wafoverride_test.go b/firewall/wafoverride_test.go new file mode 100644 index 00000000000..d62c7921492 --- /dev/null +++ b/firewall/wafoverride_test.go @@ -0,0 +1,169 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package firewall_test + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/cloudflare/cloudflare-go/v3" + "github.com/cloudflare/cloudflare-go/v3/firewall" + "github.com/cloudflare/cloudflare-go/v3/internal/testutil" + "github.com/cloudflare/cloudflare-go/v3/option" +) + +func TestWAFOverrideNew(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.WAF.Overrides.New(context.TODO(), firewall.WAFOverrideNewParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + URLs: cloudflare.F([]firewall.OverrideURLParam{"shop.example.com/*", "shop.example.com/*", "shop.example.com/*"}), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestWAFOverrideUpdateWithOptionalParams(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.WAF.Overrides.Update( + context.TODO(), + "de677e5818985db1285d0e80225f06e5", + firewall.WAFOverrideUpdateParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + ID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + RewriteAction: cloudflare.F(firewall.RewriteActionParam{ + Block: cloudflare.F(firewall.RewriteActionBlockChallenge), + Challenge: cloudflare.F(firewall.RewriteActionChallengeChallenge), + Default: cloudflare.F(firewall.RewriteActionDefaultChallenge), + Disable: cloudflare.F(firewall.RewriteActionDisableChallenge), + Simulate: cloudflare.F(firewall.RewriteActionSimulateChallenge), + }), + Rules: cloudflare.F(firewall.WAFRuleParam{ + "100015": firewall.WAFRuleItemChallenge, + }), + URLs: cloudflare.F([]firewall.OverrideURLParam{"shop.example.com/*", "shop.example.com/*", "shop.example.com/*"}), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestWAFOverrideListWithOptionalParams(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.WAF.Overrides.List(context.TODO(), firewall.WAFOverrideListParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Page: cloudflare.F(1.000000), + PerPage: cloudflare.F(5.000000), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestWAFOverrideDelete(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.WAF.Overrides.Delete( + context.TODO(), + "de677e5818985db1285d0e80225f06e5", + firewall.WAFOverrideDeleteParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestWAFOverrideGet(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.WAF.Overrides.Get( + context.TODO(), + "de677e5818985db1285d0e80225f06e5", + firewall.WAFOverrideGetParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} diff --git a/firewall/wafpackage.go b/firewall/wafpackage.go index 725aa1dd9c2..2184b1f97ad 100644 --- a/firewall/wafpackage.go +++ b/firewall/wafpackage.go @@ -3,7 +3,21 @@ package firewall import ( + "context" + "errors" + "fmt" + "net/http" + "net/url" + "reflect" + + "github.com/cloudflare/cloudflare-go/v3/internal/apijson" + "github.com/cloudflare/cloudflare-go/v3/internal/apiquery" + "github.com/cloudflare/cloudflare-go/v3/internal/param" + "github.com/cloudflare/cloudflare-go/v3/internal/requestconfig" "github.com/cloudflare/cloudflare-go/v3/option" + "github.com/cloudflare/cloudflare-go/v3/packages/pagination" + "github.com/cloudflare/cloudflare-go/v3/shared" + "github.com/tidwall/gjson" ) // WAFPackageService contains methods and other services that help with interacting @@ -28,3 +42,287 @@ func NewWAFPackageService(opts ...option.RequestOption) (r *WAFPackageService) { r.Rules = NewWAFPackageRuleService(opts...) return } + +// Fetches WAF packages for a zone. +// +// **Note:** Applies only to the +// [previous version of WAF managed rules](https://developers.cloudflare.com/support/firewall/managed-rules-web-application-firewall-waf/understanding-waf-managed-rules-web-application-firewall/). +func (r *WAFPackageService) List(ctx context.Context, params WAFPackageListParams, opts ...option.RequestOption) (res *pagination.V4PagePaginationArray[WAFPackageListResponse], err error) { + var raw *http.Response + opts = append(r.Options[:], opts...) + opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/waf/packages", params.ZoneID) + cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...) + if err != nil { + return nil, err + } + err = cfg.Execute() + if err != nil { + return nil, err + } + res.SetPageConfig(cfg, raw) + return res, nil +} + +// Fetches WAF packages for a zone. +// +// **Note:** Applies only to the +// [previous version of WAF managed rules](https://developers.cloudflare.com/support/firewall/managed-rules-web-application-firewall-waf/understanding-waf-managed-rules-web-application-firewall/). +func (r *WAFPackageService) ListAutoPaging(ctx context.Context, params WAFPackageListParams, opts ...option.RequestOption) *pagination.V4PagePaginationArrayAutoPager[WAFPackageListResponse] { + return pagination.NewV4PagePaginationArrayAutoPager(r.List(ctx, params, opts...)) +} + +// Fetches the details of a WAF package. +// +// **Note:** Applies only to the +// [previous version of WAF managed rules](https://developers.cloudflare.com/support/firewall/managed-rules-web-application-firewall-waf/understanding-waf-managed-rules-web-application-firewall/). +func (r *WAFPackageService) Get(ctx context.Context, packageID string, query WAFPackageGetParams, opts ...option.RequestOption) (res *WAFPackageGetResponse, err error) { + opts = append(r.Options[:], opts...) + if query.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if packageID == "" { + err = errors.New("missing required package_id parameter") + return + } + path := fmt.Sprintf("zones/%s/firewall/waf/packages/%s", query.ZoneID, packageID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) + return +} + +type WAFPackageListResponse = interface{} + +type WAFPackageGetResponse struct { + // This field can have the runtime type of [[]shared.ResponseInfo]. + Errors interface{} `json:"errors"` + // This field can have the runtime type of [[]shared.ResponseInfo]. + Messages interface{} `json:"messages"` + // This field can have the runtime type of [interface{}]. + Result interface{} `json:"result"` + // Whether the API call was successful + Success WAFPackageGetResponseSuccess `json:"success"` + JSON wafPackageGetResponseJSON `json:"-"` + union WAFPackageGetResponseUnion +} + +// wafPackageGetResponseJSON contains the JSON metadata for the struct +// [WAFPackageGetResponse] +type wafPackageGetResponseJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r wafPackageGetResponseJSON) RawJSON() string { + return r.raw +} + +func (r *WAFPackageGetResponse) UnmarshalJSON(data []byte) (err error) { + *r = WAFPackageGetResponse{} + err = apijson.UnmarshalRoot(data, &r.union) + if err != nil { + return err + } + return apijson.Port(r.union, &r) +} + +// AsUnion returns a [WAFPackageGetResponseUnion] interface which you can cast to +// the specific types for more type safety. +// +// Possible runtime types of the union are +// [firewall.WAFPackageGetResponseFirewallAPIResponseSingle], +// [firewall.WAFPackageGetResponseResult]. +func (r WAFPackageGetResponse) AsUnion() WAFPackageGetResponseUnion { + return r.union +} + +// Union satisfied by [firewall.WAFPackageGetResponseFirewallAPIResponseSingle] or +// [firewall.WAFPackageGetResponseResult]. +type WAFPackageGetResponseUnion interface { + implementsFirewallWAFPackageGetResponse() +} + +func init() { + apijson.RegisterUnion( + reflect.TypeOf((*WAFPackageGetResponseUnion)(nil)).Elem(), + "", + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(WAFPackageGetResponseFirewallAPIResponseSingle{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(WAFPackageGetResponseResult{}), + }, + ) +} + +type WAFPackageGetResponseFirewallAPIResponseSingle struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result interface{} `json:"result,required"` + // Whether the API call was successful + Success WAFPackageGetResponseFirewallAPIResponseSingleSuccess `json:"success,required"` + JSON wafPackageGetResponseFirewallAPIResponseSingleJSON `json:"-"` +} + +// wafPackageGetResponseFirewallAPIResponseSingleJSON contains the JSON metadata +// for the struct [WAFPackageGetResponseFirewallAPIResponseSingle] +type wafPackageGetResponseFirewallAPIResponseSingleJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *WAFPackageGetResponseFirewallAPIResponseSingle) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r wafPackageGetResponseFirewallAPIResponseSingleJSON) RawJSON() string { + return r.raw +} + +func (r WAFPackageGetResponseFirewallAPIResponseSingle) implementsFirewallWAFPackageGetResponse() {} + +// Whether the API call was successful +type WAFPackageGetResponseFirewallAPIResponseSingleSuccess bool + +const ( + WAFPackageGetResponseFirewallAPIResponseSingleSuccessTrue WAFPackageGetResponseFirewallAPIResponseSingleSuccess = true +) + +func (r WAFPackageGetResponseFirewallAPIResponseSingleSuccess) IsKnown() bool { + switch r { + case WAFPackageGetResponseFirewallAPIResponseSingleSuccessTrue: + return true + } + return false +} + +type WAFPackageGetResponseResult struct { + Result interface{} `json:"result"` + JSON wafPackageGetResponseResultJSON `json:"-"` +} + +// wafPackageGetResponseResultJSON contains the JSON metadata for the struct +// [WAFPackageGetResponseResult] +type wafPackageGetResponseResultJSON struct { + Result apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *WAFPackageGetResponseResult) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r wafPackageGetResponseResultJSON) RawJSON() string { + return r.raw +} + +func (r WAFPackageGetResponseResult) implementsFirewallWAFPackageGetResponse() {} + +// Whether the API call was successful +type WAFPackageGetResponseSuccess bool + +const ( + WAFPackageGetResponseSuccessTrue WAFPackageGetResponseSuccess = true +) + +func (r WAFPackageGetResponseSuccess) IsKnown() bool { + switch r { + case WAFPackageGetResponseSuccessTrue: + return true + } + return false +} + +type WAFPackageListParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The direction used to sort returned packages. + Direction param.Field[WAFPackageListParamsDirection] `query:"direction"` + // When set to `all`, all the search requirements must match. When set to `any`, + // only one of the search requirements has to match. + Match param.Field[WAFPackageListParamsMatch] `query:"match"` + // The name of the WAF package. + Name param.Field[string] `query:"name"` + // The field used to sort returned packages. + Order param.Field[WAFPackageListParamsOrder] `query:"order"` + // The page number of paginated results. + Page param.Field[float64] `query:"page"` + // The number of packages per page. + PerPage param.Field[float64] `query:"per_page"` +} + +// URLQuery serializes [WAFPackageListParams]'s query parameters as `url.Values`. +func (r WAFPackageListParams) URLQuery() (v url.Values) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatRepeat, + NestedFormat: apiquery.NestedQueryFormatDots, + }) +} + +// The direction used to sort returned packages. +type WAFPackageListParamsDirection string + +const ( + WAFPackageListParamsDirectionAsc WAFPackageListParamsDirection = "asc" + WAFPackageListParamsDirectionDesc WAFPackageListParamsDirection = "desc" +) + +func (r WAFPackageListParamsDirection) IsKnown() bool { + switch r { + case WAFPackageListParamsDirectionAsc, WAFPackageListParamsDirectionDesc: + return true + } + return false +} + +// When set to `all`, all the search requirements must match. When set to `any`, +// only one of the search requirements has to match. +type WAFPackageListParamsMatch string + +const ( + WAFPackageListParamsMatchAny WAFPackageListParamsMatch = "any" + WAFPackageListParamsMatchAll WAFPackageListParamsMatch = "all" +) + +func (r WAFPackageListParamsMatch) IsKnown() bool { + switch r { + case WAFPackageListParamsMatchAny, WAFPackageListParamsMatchAll: + return true + } + return false +} + +// The field used to sort returned packages. +type WAFPackageListParamsOrder string + +const ( + WAFPackageListParamsOrderName WAFPackageListParamsOrder = "name" +) + +func (r WAFPackageListParamsOrder) IsKnown() bool { + switch r { + case WAFPackageListParamsOrderName: + return true + } + return false +} + +type WAFPackageGetParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} diff --git a/firewall/wafpackage_test.go b/firewall/wafpackage_test.go new file mode 100644 index 00000000000..fd5b4db0ed1 --- /dev/null +++ b/firewall/wafpackage_test.go @@ -0,0 +1,76 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package firewall_test + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/cloudflare/cloudflare-go/v3" + "github.com/cloudflare/cloudflare-go/v3/firewall" + "github.com/cloudflare/cloudflare-go/v3/internal/testutil" + "github.com/cloudflare/cloudflare-go/v3/option" +) + +func TestWAFPackageListWithOptionalParams(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.WAF.Packages.List(context.TODO(), firewall.WAFPackageListParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Direction: cloudflare.F(firewall.WAFPackageListParamsDirectionAsc), + Match: cloudflare.F(firewall.WAFPackageListParamsMatchAny), + Name: cloudflare.F("USER"), + Order: cloudflare.F(firewall.WAFPackageListParamsOrderName), + Page: cloudflare.F(1.000000), + PerPage: cloudflare.F(5.000000), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestWAFPackageGet(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.Firewall.WAF.Packages.Get( + context.TODO(), + "023e105f4ecef8ad9ca31a8372d0c353", + firewall.WAFPackageGetParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} diff --git a/rate_limits/ratelimit.go b/rate_limits/ratelimit.go index ea1db192149..55d9666d982 100644 --- a/rate_limits/ratelimit.go +++ b/rate_limits/ratelimit.go @@ -3,7 +3,19 @@ package rate_limits import ( + "context" + "errors" + "fmt" + "net/http" + "net/url" + + "github.com/cloudflare/cloudflare-go/v3/internal/apijson" + "github.com/cloudflare/cloudflare-go/v3/internal/apiquery" + "github.com/cloudflare/cloudflare-go/v3/internal/param" + "github.com/cloudflare/cloudflare-go/v3/internal/requestconfig" "github.com/cloudflare/cloudflare-go/v3/option" + "github.com/cloudflare/cloudflare-go/v3/packages/pagination" + "github.com/cloudflare/cloudflare-go/v3/shared" ) // RateLimitService contains methods and other services that help with interacting @@ -24,3 +36,1306 @@ func NewRateLimitService(opts ...option.RequestOption) (r *RateLimitService) { r.Options = opts return } + +// Creates a new rate limit for a zone. Refer to the object definition for a list +// of required attributes. +// +// Deprecated: Rate limiting API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#rate-limiting-api-previous-version +// for full details. +func (r *RateLimitService) New(ctx context.Context, params RateLimitNewParams, opts ...option.RequestOption) (res *RateLimit, err error) { + var env RateLimitNewResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/rate_limits", params.ZoneID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches the rate limits for a zone. +// +// Deprecated: Rate limiting API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#rate-limiting-api-previous-version +// for full details. +func (r *RateLimitService) List(ctx context.Context, params RateLimitListParams, opts ...option.RequestOption) (res *pagination.V4PagePaginationArray[RateLimit], err error) { + var raw *http.Response + opts = append(r.Options[:], opts...) + opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + path := fmt.Sprintf("zones/%s/rate_limits", params.ZoneID) + cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...) + if err != nil { + return nil, err + } + err = cfg.Execute() + if err != nil { + return nil, err + } + res.SetPageConfig(cfg, raw) + return res, nil +} + +// Fetches the rate limits for a zone. +// +// Deprecated: Rate limiting API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#rate-limiting-api-previous-version +// for full details. +func (r *RateLimitService) ListAutoPaging(ctx context.Context, params RateLimitListParams, opts ...option.RequestOption) *pagination.V4PagePaginationArrayAutoPager[RateLimit] { + return pagination.NewV4PagePaginationArrayAutoPager(r.List(ctx, params, opts...)) +} + +// Deletes an existing rate limit. +// +// Deprecated: Rate limiting API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#rate-limiting-api-previous-version +// for full details. +func (r *RateLimitService) Delete(ctx context.Context, rateLimitID string, body RateLimitDeleteParams, opts ...option.RequestOption) (res *RateLimitDeleteResponse, err error) { + var env RateLimitDeleteResponseEnvelope + opts = append(r.Options[:], opts...) + if body.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if rateLimitID == "" { + err = errors.New("missing required rate_limit_id parameter") + return + } + path := fmt.Sprintf("zones/%s/rate_limits/%s", body.ZoneID, rateLimitID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Updates an existing rate limit. +// +// Deprecated: Rate limiting API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#rate-limiting-api-previous-version +// for full details. +func (r *RateLimitService) Edit(ctx context.Context, rateLimitID string, params RateLimitEditParams, opts ...option.RequestOption) (res *RateLimit, err error) { + var env RateLimitEditResponseEnvelope + opts = append(r.Options[:], opts...) + if params.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if rateLimitID == "" { + err = errors.New("missing required rate_limit_id parameter") + return + } + path := fmt.Sprintf("zones/%s/rate_limits/%s", params.ZoneID, rateLimitID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, params, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// Fetches the details of a rate limit. +// +// Deprecated: Rate limiting API is deprecated in favour of using the Ruleset +// Engine. See +// https://developers.cloudflare.com/fundamentals/api/reference/deprecations/#rate-limiting-api-previous-version +// for full details. +func (r *RateLimitService) Get(ctx context.Context, rateLimitID string, query RateLimitGetParams, opts ...option.RequestOption) (res *RateLimit, err error) { + var env RateLimitGetResponseEnvelope + opts = append(r.Options[:], opts...) + if query.ZoneID.Value == "" { + err = errors.New("missing required zone_id parameter") + return + } + if rateLimitID == "" { + err = errors.New("missing required rate_limit_id parameter") + return + } + path := fmt.Sprintf("zones/%s/rate_limits/%s", query.ZoneID, rateLimitID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &env, opts...) + if err != nil { + return + } + res = &env.Result + return +} + +// The action to apply to a matched request. The `log` action is only available on +// an Enterprise plan. +type Action string + +const ( + ActionBlock Action = "block" + ActionChallenge Action = "challenge" + ActionJSChallenge Action = "js_challenge" + ActionManagedChallenge Action = "managed_challenge" + ActionAllow Action = "allow" + ActionLog Action = "log" + ActionBypass Action = "bypass" +) + +func (r Action) IsKnown() bool { + switch r { + case ActionBlock, ActionChallenge, ActionJSChallenge, ActionManagedChallenge, ActionAllow, ActionLog, ActionBypass: + return true + } + return false +} + +// An HTTP method or `_ALL_` to indicate all methods. +type Methods string + +const ( + MethodsGet Methods = "GET" + MethodsPost Methods = "POST" + MethodsPut Methods = "PUT" + MethodsDelete Methods = "DELETE" + MethodsPatch Methods = "PATCH" + MethodsHead Methods = "HEAD" + Methods_All Methods = "_ALL_" +) + +func (r Methods) IsKnown() bool { + switch r { + case MethodsGet, MethodsPost, MethodsPut, MethodsDelete, MethodsPatch, MethodsHead, Methods_All: + return true + } + return false +} + +type RateLimit struct { + // The unique identifier of the rate limit. + ID string `json:"id"` + // The action to perform when the threshold of matched traffic within the + // configured period is exceeded. + Action RateLimitAction `json:"action"` + // Criteria specifying when the current rate limit should be bypassed. You can + // specify that the rate limit should not apply to one or more URLs. + Bypass []RateLimitBypass `json:"bypass"` + // An informative summary of the rate limit. This value is sanitized and any tags + // will be removed. + Description string `json:"description"` + // When true, indicates that the rate limit is currently disabled. + Disabled bool `json:"disabled"` + // Determines which traffic the rate limit counts towards the threshold. + Match RateLimitMatch `json:"match"` + // The time in seconds (an integer value) to count matching traffic. If the count + // exceeds the configured threshold within this period, Cloudflare will perform the + // configured action. + Period float64 `json:"period"` + // The threshold that will trigger the configured mitigation action. Configure this + // value along with the `period` property to establish a threshold per period. + Threshold float64 `json:"threshold"` + JSON rateLimitJSON `json:"-"` +} + +// rateLimitJSON contains the JSON metadata for the struct [RateLimit] +type rateLimitJSON struct { + ID apijson.Field + Action apijson.Field + Bypass apijson.Field + Description apijson.Field + Disabled apijson.Field + Match apijson.Field + Period apijson.Field + Threshold apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimit) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitJSON) RawJSON() string { + return r.raw +} + +// The action to perform when the threshold of matched traffic within the +// configured period is exceeded. +type RateLimitAction struct { + // The action to perform. + Mode RateLimitActionMode `json:"mode"` + // A custom content type and reponse to return when the threshold is exceeded. The + // custom response configured in this object will override the custom error for the + // zone. This object is optional. Notes: If you omit this object, Cloudflare will + // use the default HTML error page. If "mode" is "challenge", "managed_challenge", + // or "js_challenge", Cloudflare will use the zone challenge pages and you should + // not provide the "response" object. + Response RateLimitActionResponse `json:"response"` + // The time in seconds during which Cloudflare will perform the mitigation action. + // Must be an integer value greater than or equal to the period. Notes: If "mode" + // is "challenge", "managed_challenge", or "js_challenge", Cloudflare will use the + // zone's Challenge Passage time and you should not provide this value. + Timeout float64 `json:"timeout"` + JSON rateLimitActionJSON `json:"-"` +} + +// rateLimitActionJSON contains the JSON metadata for the struct [RateLimitAction] +type rateLimitActionJSON struct { + Mode apijson.Field + Response apijson.Field + Timeout apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitAction) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitActionJSON) RawJSON() string { + return r.raw +} + +// The action to perform. +type RateLimitActionMode string + +const ( + RateLimitActionModeSimulate RateLimitActionMode = "simulate" + RateLimitActionModeBan RateLimitActionMode = "ban" + RateLimitActionModeChallenge RateLimitActionMode = "challenge" + RateLimitActionModeJSChallenge RateLimitActionMode = "js_challenge" + RateLimitActionModeManagedChallenge RateLimitActionMode = "managed_challenge" +) + +func (r RateLimitActionMode) IsKnown() bool { + switch r { + case RateLimitActionModeSimulate, RateLimitActionModeBan, RateLimitActionModeChallenge, RateLimitActionModeJSChallenge, RateLimitActionModeManagedChallenge: + return true + } + return false +} + +// A custom content type and reponse to return when the threshold is exceeded. The +// custom response configured in this object will override the custom error for the +// zone. This object is optional. Notes: If you omit this object, Cloudflare will +// use the default HTML error page. If "mode" is "challenge", "managed_challenge", +// or "js_challenge", Cloudflare will use the zone challenge pages and you should +// not provide the "response" object. +type RateLimitActionResponse struct { + // The response body to return. The value must conform to the configured content + // type. + Body string `json:"body"` + // The content type of the body. Must be one of the following: `text/plain`, + // `text/xml`, or `application/json`. + ContentType string `json:"content_type"` + JSON rateLimitActionResponseJSON `json:"-"` +} + +// rateLimitActionResponseJSON contains the JSON metadata for the struct +// [RateLimitActionResponse] +type rateLimitActionResponseJSON struct { + Body apijson.Field + ContentType apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitActionResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitActionResponseJSON) RawJSON() string { + return r.raw +} + +type RateLimitBypass struct { + Name RateLimitBypassName `json:"name"` + // The URL to bypass. + Value string `json:"value"` + JSON rateLimitBypassJSON `json:"-"` +} + +// rateLimitBypassJSON contains the JSON metadata for the struct [RateLimitBypass] +type rateLimitBypassJSON struct { + Name apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitBypass) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitBypassJSON) RawJSON() string { + return r.raw +} + +type RateLimitBypassName string + +const ( + RateLimitBypassNameURL RateLimitBypassName = "url" +) + +func (r RateLimitBypassName) IsKnown() bool { + switch r { + case RateLimitBypassNameURL: + return true + } + return false +} + +// Determines which traffic the rate limit counts towards the threshold. +type RateLimitMatch struct { + Headers []RateLimitMatchHeader `json:"headers"` + Request RateLimitMatchRequest `json:"request"` + Response RateLimitMatchResponse `json:"response"` + JSON rateLimitMatchJSON `json:"-"` +} + +// rateLimitMatchJSON contains the JSON metadata for the struct [RateLimitMatch] +type rateLimitMatchJSON struct { + Headers apijson.Field + Request apijson.Field + Response apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitMatch) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitMatchJSON) RawJSON() string { + return r.raw +} + +type RateLimitMatchHeader struct { + // The name of the response header to match. + Name string `json:"name"` + // The operator used when matching: `eq` means "equal" and `ne` means "not equal". + Op RateLimitMatchHeadersOp `json:"op"` + // The value of the response header, which must match exactly. + Value string `json:"value"` + JSON rateLimitMatchHeaderJSON `json:"-"` +} + +// rateLimitMatchHeaderJSON contains the JSON metadata for the struct +// [RateLimitMatchHeader] +type rateLimitMatchHeaderJSON struct { + Name apijson.Field + Op apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitMatchHeader) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitMatchHeaderJSON) RawJSON() string { + return r.raw +} + +// The operator used when matching: `eq` means "equal" and `ne` means "not equal". +type RateLimitMatchHeadersOp string + +const ( + RateLimitMatchHeadersOpEq RateLimitMatchHeadersOp = "eq" + RateLimitMatchHeadersOpNe RateLimitMatchHeadersOp = "ne" +) + +func (r RateLimitMatchHeadersOp) IsKnown() bool { + switch r { + case RateLimitMatchHeadersOpEq, RateLimitMatchHeadersOpNe: + return true + } + return false +} + +type RateLimitMatchRequest struct { + // The HTTP methods to match. You can specify a subset (for example, + // `['POST','PUT']`) or all methods (`['_ALL_']`). This field is optional when + // creating a rate limit. + Methods []Methods `json:"methods"` + // The HTTP schemes to match. You can specify one scheme (`['HTTPS']`), both + // schemes (`['HTTP','HTTPS']`), or all schemes (`['_ALL_']`). This field is + // optional. + Schemes []string `json:"schemes"` + // The URL pattern to match, composed of a host and a path such as + // `example.org/path*`. Normalization is applied before the pattern is matched. `*` + // wildcards are expanded to match applicable traffic. Query strings are not + // matched. Set the value to `*` to match all traffic to your zone. + URL string `json:"url"` + JSON rateLimitMatchRequestJSON `json:"-"` +} + +// rateLimitMatchRequestJSON contains the JSON metadata for the struct +// [RateLimitMatchRequest] +type rateLimitMatchRequestJSON struct { + Methods apijson.Field + Schemes apijson.Field + URL apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitMatchRequest) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitMatchRequestJSON) RawJSON() string { + return r.raw +} + +type RateLimitMatchResponse struct { + // When true, only the uncached traffic served from your origin servers will count + // towards rate limiting. In this case, any cached traffic served by Cloudflare + // will not count towards rate limiting. This field is optional. Notes: This field + // is deprecated. Instead, use response headers and set "origin_traffic" to "false" + // to avoid legacy behaviour interacting with the "response_headers" property. + OriginTraffic bool `json:"origin_traffic"` + JSON rateLimitMatchResponseJSON `json:"-"` +} + +// rateLimitMatchResponseJSON contains the JSON metadata for the struct +// [RateLimitMatchResponse] +type rateLimitMatchResponseJSON struct { + OriginTraffic apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitMatchResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitMatchResponseJSON) RawJSON() string { + return r.raw +} + +type RateLimitDeleteResponse struct { + // The unique identifier of the rate limit. + ID string `json:"id"` + // The action to perform when the threshold of matched traffic within the + // configured period is exceeded. + Action RateLimitDeleteResponseAction `json:"action"` + // Criteria specifying when the current rate limit should be bypassed. You can + // specify that the rate limit should not apply to one or more URLs. + Bypass []RateLimitDeleteResponseBypass `json:"bypass"` + // An informative summary of the rate limit. This value is sanitized and any tags + // will be removed. + Description string `json:"description"` + // When true, indicates that the rate limit is currently disabled. + Disabled bool `json:"disabled"` + // Determines which traffic the rate limit counts towards the threshold. + Match RateLimitDeleteResponseMatch `json:"match"` + // The time in seconds (an integer value) to count matching traffic. If the count + // exceeds the configured threshold within this period, Cloudflare will perform the + // configured action. + Period float64 `json:"period"` + // The threshold that will trigger the configured mitigation action. Configure this + // value along with the `period` property to establish a threshold per period. + Threshold float64 `json:"threshold"` + JSON rateLimitDeleteResponseJSON `json:"-"` +} + +// rateLimitDeleteResponseJSON contains the JSON metadata for the struct +// [RateLimitDeleteResponse] +type rateLimitDeleteResponseJSON struct { + ID apijson.Field + Action apijson.Field + Bypass apijson.Field + Description apijson.Field + Disabled apijson.Field + Match apijson.Field + Period apijson.Field + Threshold apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitDeleteResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitDeleteResponseJSON) RawJSON() string { + return r.raw +} + +// The action to perform when the threshold of matched traffic within the +// configured period is exceeded. +type RateLimitDeleteResponseAction struct { + // The action to perform. + Mode RateLimitDeleteResponseActionMode `json:"mode"` + // A custom content type and reponse to return when the threshold is exceeded. The + // custom response configured in this object will override the custom error for the + // zone. This object is optional. Notes: If you omit this object, Cloudflare will + // use the default HTML error page. If "mode" is "challenge", "managed_challenge", + // or "js_challenge", Cloudflare will use the zone challenge pages and you should + // not provide the "response" object. + Response RateLimitDeleteResponseActionResponse `json:"response"` + // The time in seconds during which Cloudflare will perform the mitigation action. + // Must be an integer value greater than or equal to the period. Notes: If "mode" + // is "challenge", "managed_challenge", or "js_challenge", Cloudflare will use the + // zone's Challenge Passage time and you should not provide this value. + Timeout float64 `json:"timeout"` + JSON rateLimitDeleteResponseActionJSON `json:"-"` +} + +// rateLimitDeleteResponseActionJSON contains the JSON metadata for the struct +// [RateLimitDeleteResponseAction] +type rateLimitDeleteResponseActionJSON struct { + Mode apijson.Field + Response apijson.Field + Timeout apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitDeleteResponseAction) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitDeleteResponseActionJSON) RawJSON() string { + return r.raw +} + +// The action to perform. +type RateLimitDeleteResponseActionMode string + +const ( + RateLimitDeleteResponseActionModeSimulate RateLimitDeleteResponseActionMode = "simulate" + RateLimitDeleteResponseActionModeBan RateLimitDeleteResponseActionMode = "ban" + RateLimitDeleteResponseActionModeChallenge RateLimitDeleteResponseActionMode = "challenge" + RateLimitDeleteResponseActionModeJSChallenge RateLimitDeleteResponseActionMode = "js_challenge" + RateLimitDeleteResponseActionModeManagedChallenge RateLimitDeleteResponseActionMode = "managed_challenge" +) + +func (r RateLimitDeleteResponseActionMode) IsKnown() bool { + switch r { + case RateLimitDeleteResponseActionModeSimulate, RateLimitDeleteResponseActionModeBan, RateLimitDeleteResponseActionModeChallenge, RateLimitDeleteResponseActionModeJSChallenge, RateLimitDeleteResponseActionModeManagedChallenge: + return true + } + return false +} + +// A custom content type and reponse to return when the threshold is exceeded. The +// custom response configured in this object will override the custom error for the +// zone. This object is optional. Notes: If you omit this object, Cloudflare will +// use the default HTML error page. If "mode" is "challenge", "managed_challenge", +// or "js_challenge", Cloudflare will use the zone challenge pages and you should +// not provide the "response" object. +type RateLimitDeleteResponseActionResponse struct { + // The response body to return. The value must conform to the configured content + // type. + Body string `json:"body"` + // The content type of the body. Must be one of the following: `text/plain`, + // `text/xml`, or `application/json`. + ContentType string `json:"content_type"` + JSON rateLimitDeleteResponseActionResponseJSON `json:"-"` +} + +// rateLimitDeleteResponseActionResponseJSON contains the JSON metadata for the +// struct [RateLimitDeleteResponseActionResponse] +type rateLimitDeleteResponseActionResponseJSON struct { + Body apijson.Field + ContentType apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitDeleteResponseActionResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitDeleteResponseActionResponseJSON) RawJSON() string { + return r.raw +} + +type RateLimitDeleteResponseBypass struct { + Name RateLimitDeleteResponseBypassName `json:"name"` + // The URL to bypass. + Value string `json:"value"` + JSON rateLimitDeleteResponseBypassJSON `json:"-"` +} + +// rateLimitDeleteResponseBypassJSON contains the JSON metadata for the struct +// [RateLimitDeleteResponseBypass] +type rateLimitDeleteResponseBypassJSON struct { + Name apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitDeleteResponseBypass) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitDeleteResponseBypassJSON) RawJSON() string { + return r.raw +} + +type RateLimitDeleteResponseBypassName string + +const ( + RateLimitDeleteResponseBypassNameURL RateLimitDeleteResponseBypassName = "url" +) + +func (r RateLimitDeleteResponseBypassName) IsKnown() bool { + switch r { + case RateLimitDeleteResponseBypassNameURL: + return true + } + return false +} + +// Determines which traffic the rate limit counts towards the threshold. +type RateLimitDeleteResponseMatch struct { + Headers []RateLimitDeleteResponseMatchHeader `json:"headers"` + Request RateLimitDeleteResponseMatchRequest `json:"request"` + Response RateLimitDeleteResponseMatchResponse `json:"response"` + JSON rateLimitDeleteResponseMatchJSON `json:"-"` +} + +// rateLimitDeleteResponseMatchJSON contains the JSON metadata for the struct +// [RateLimitDeleteResponseMatch] +type rateLimitDeleteResponseMatchJSON struct { + Headers apijson.Field + Request apijson.Field + Response apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitDeleteResponseMatch) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitDeleteResponseMatchJSON) RawJSON() string { + return r.raw +} + +type RateLimitDeleteResponseMatchHeader struct { + // The name of the response header to match. + Name string `json:"name"` + // The operator used when matching: `eq` means "equal" and `ne` means "not equal". + Op RateLimitDeleteResponseMatchHeadersOp `json:"op"` + // The value of the response header, which must match exactly. + Value string `json:"value"` + JSON rateLimitDeleteResponseMatchHeaderJSON `json:"-"` +} + +// rateLimitDeleteResponseMatchHeaderJSON contains the JSON metadata for the struct +// [RateLimitDeleteResponseMatchHeader] +type rateLimitDeleteResponseMatchHeaderJSON struct { + Name apijson.Field + Op apijson.Field + Value apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitDeleteResponseMatchHeader) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitDeleteResponseMatchHeaderJSON) RawJSON() string { + return r.raw +} + +// The operator used when matching: `eq` means "equal" and `ne` means "not equal". +type RateLimitDeleteResponseMatchHeadersOp string + +const ( + RateLimitDeleteResponseMatchHeadersOpEq RateLimitDeleteResponseMatchHeadersOp = "eq" + RateLimitDeleteResponseMatchHeadersOpNe RateLimitDeleteResponseMatchHeadersOp = "ne" +) + +func (r RateLimitDeleteResponseMatchHeadersOp) IsKnown() bool { + switch r { + case RateLimitDeleteResponseMatchHeadersOpEq, RateLimitDeleteResponseMatchHeadersOpNe: + return true + } + return false +} + +type RateLimitDeleteResponseMatchRequest struct { + // The HTTP methods to match. You can specify a subset (for example, + // `['POST','PUT']`) or all methods (`['_ALL_']`). This field is optional when + // creating a rate limit. + Methods []Methods `json:"methods"` + // The HTTP schemes to match. You can specify one scheme (`['HTTPS']`), both + // schemes (`['HTTP','HTTPS']`), or all schemes (`['_ALL_']`). This field is + // optional. + Schemes []string `json:"schemes"` + // The URL pattern to match, composed of a host and a path such as + // `example.org/path*`. Normalization is applied before the pattern is matched. `*` + // wildcards are expanded to match applicable traffic. Query strings are not + // matched. Set the value to `*` to match all traffic to your zone. + URL string `json:"url"` + JSON rateLimitDeleteResponseMatchRequestJSON `json:"-"` +} + +// rateLimitDeleteResponseMatchRequestJSON contains the JSON metadata for the +// struct [RateLimitDeleteResponseMatchRequest] +type rateLimitDeleteResponseMatchRequestJSON struct { + Methods apijson.Field + Schemes apijson.Field + URL apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitDeleteResponseMatchRequest) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitDeleteResponseMatchRequestJSON) RawJSON() string { + return r.raw +} + +type RateLimitDeleteResponseMatchResponse struct { + // When true, only the uncached traffic served from your origin servers will count + // towards rate limiting. In this case, any cached traffic served by Cloudflare + // will not count towards rate limiting. This field is optional. Notes: This field + // is deprecated. Instead, use response headers and set "origin_traffic" to "false" + // to avoid legacy behaviour interacting with the "response_headers" property. + OriginTraffic bool `json:"origin_traffic"` + JSON rateLimitDeleteResponseMatchResponseJSON `json:"-"` +} + +// rateLimitDeleteResponseMatchResponseJSON contains the JSON metadata for the +// struct [RateLimitDeleteResponseMatchResponse] +type rateLimitDeleteResponseMatchResponseJSON struct { + OriginTraffic apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitDeleteResponseMatchResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitDeleteResponseMatchResponseJSON) RawJSON() string { + return r.raw +} + +type RateLimitNewParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The action to perform when the threshold of matched traffic within the + // configured period is exceeded. + Action param.Field[RateLimitNewParamsAction] `json:"action,required"` + // Determines which traffic the rate limit counts towards the threshold. + Match param.Field[RateLimitNewParamsMatch] `json:"match,required"` + // The time in seconds (an integer value) to count matching traffic. If the count + // exceeds the configured threshold within this period, Cloudflare will perform the + // configured action. + Period param.Field[float64] `json:"period,required"` + // The threshold that will trigger the configured mitigation action. Configure this + // value along with the `period` property to establish a threshold per period. + Threshold param.Field[float64] `json:"threshold,required"` +} + +func (r RateLimitNewParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The action to perform when the threshold of matched traffic within the +// configured period is exceeded. +type RateLimitNewParamsAction struct { + // The action to perform. + Mode param.Field[RateLimitNewParamsActionMode] `json:"mode"` + // A custom content type and reponse to return when the threshold is exceeded. The + // custom response configured in this object will override the custom error for the + // zone. This object is optional. Notes: If you omit this object, Cloudflare will + // use the default HTML error page. If "mode" is "challenge", "managed_challenge", + // or "js_challenge", Cloudflare will use the zone challenge pages and you should + // not provide the "response" object. + Response param.Field[RateLimitNewParamsActionResponse] `json:"response"` + // The time in seconds during which Cloudflare will perform the mitigation action. + // Must be an integer value greater than or equal to the period. Notes: If "mode" + // is "challenge", "managed_challenge", or "js_challenge", Cloudflare will use the + // zone's Challenge Passage time and you should not provide this value. + Timeout param.Field[float64] `json:"timeout"` +} + +func (r RateLimitNewParamsAction) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The action to perform. +type RateLimitNewParamsActionMode string + +const ( + RateLimitNewParamsActionModeSimulate RateLimitNewParamsActionMode = "simulate" + RateLimitNewParamsActionModeBan RateLimitNewParamsActionMode = "ban" + RateLimitNewParamsActionModeChallenge RateLimitNewParamsActionMode = "challenge" + RateLimitNewParamsActionModeJSChallenge RateLimitNewParamsActionMode = "js_challenge" + RateLimitNewParamsActionModeManagedChallenge RateLimitNewParamsActionMode = "managed_challenge" +) + +func (r RateLimitNewParamsActionMode) IsKnown() bool { + switch r { + case RateLimitNewParamsActionModeSimulate, RateLimitNewParamsActionModeBan, RateLimitNewParamsActionModeChallenge, RateLimitNewParamsActionModeJSChallenge, RateLimitNewParamsActionModeManagedChallenge: + return true + } + return false +} + +// A custom content type and reponse to return when the threshold is exceeded. The +// custom response configured in this object will override the custom error for the +// zone. This object is optional. Notes: If you omit this object, Cloudflare will +// use the default HTML error page. If "mode" is "challenge", "managed_challenge", +// or "js_challenge", Cloudflare will use the zone challenge pages and you should +// not provide the "response" object. +type RateLimitNewParamsActionResponse struct { + // The response body to return. The value must conform to the configured content + // type. + Body param.Field[string] `json:"body"` + // The content type of the body. Must be one of the following: `text/plain`, + // `text/xml`, or `application/json`. + ContentType param.Field[string] `json:"content_type"` +} + +func (r RateLimitNewParamsActionResponse) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// Determines which traffic the rate limit counts towards the threshold. +type RateLimitNewParamsMatch struct { + Headers param.Field[[]RateLimitNewParamsMatchHeader] `json:"headers"` + Request param.Field[RateLimitNewParamsMatchRequest] `json:"request"` + Response param.Field[RateLimitNewParamsMatchResponse] `json:"response"` +} + +func (r RateLimitNewParamsMatch) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type RateLimitNewParamsMatchHeader struct { + // The name of the response header to match. + Name param.Field[string] `json:"name"` + // The operator used when matching: `eq` means "equal" and `ne` means "not equal". + Op param.Field[RateLimitNewParamsMatchHeadersOp] `json:"op"` + // The value of the response header, which must match exactly. + Value param.Field[string] `json:"value"` +} + +func (r RateLimitNewParamsMatchHeader) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The operator used when matching: `eq` means "equal" and `ne` means "not equal". +type RateLimitNewParamsMatchHeadersOp string + +const ( + RateLimitNewParamsMatchHeadersOpEq RateLimitNewParamsMatchHeadersOp = "eq" + RateLimitNewParamsMatchHeadersOpNe RateLimitNewParamsMatchHeadersOp = "ne" +) + +func (r RateLimitNewParamsMatchHeadersOp) IsKnown() bool { + switch r { + case RateLimitNewParamsMatchHeadersOpEq, RateLimitNewParamsMatchHeadersOpNe: + return true + } + return false +} + +type RateLimitNewParamsMatchRequest struct { + // The HTTP methods to match. You can specify a subset (for example, + // `['POST','PUT']`) or all methods (`['_ALL_']`). This field is optional when + // creating a rate limit. + Methods param.Field[[]Methods] `json:"methods"` + // The HTTP schemes to match. You can specify one scheme (`['HTTPS']`), both + // schemes (`['HTTP','HTTPS']`), or all schemes (`['_ALL_']`). This field is + // optional. + Schemes param.Field[[]string] `json:"schemes"` + // The URL pattern to match, composed of a host and a path such as + // `example.org/path*`. Normalization is applied before the pattern is matched. `*` + // wildcards are expanded to match applicable traffic. Query strings are not + // matched. Set the value to `*` to match all traffic to your zone. + URL param.Field[string] `json:"url"` +} + +func (r RateLimitNewParamsMatchRequest) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type RateLimitNewParamsMatchResponse struct { + // When true, only the uncached traffic served from your origin servers will count + // towards rate limiting. In this case, any cached traffic served by Cloudflare + // will not count towards rate limiting. This field is optional. Notes: This field + // is deprecated. Instead, use response headers and set "origin_traffic" to "false" + // to avoid legacy behaviour interacting with the "response_headers" property. + OriginTraffic param.Field[bool] `json:"origin_traffic"` +} + +func (r RateLimitNewParamsMatchResponse) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type RateLimitNewResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result RateLimit `json:"result,required"` + // Whether the API call was successful + Success RateLimitNewResponseEnvelopeSuccess `json:"success,required"` + JSON rateLimitNewResponseEnvelopeJSON `json:"-"` +} + +// rateLimitNewResponseEnvelopeJSON contains the JSON metadata for the struct +// [RateLimitNewResponseEnvelope] +type rateLimitNewResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitNewResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitNewResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type RateLimitNewResponseEnvelopeSuccess bool + +const ( + RateLimitNewResponseEnvelopeSuccessTrue RateLimitNewResponseEnvelopeSuccess = true +) + +func (r RateLimitNewResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case RateLimitNewResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type RateLimitListParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The page number of paginated results. + Page param.Field[float64] `query:"page"` + // The maximum number of results per page. You can only set the value to `1` or to + // a multiple of 5 such as `5`, `10`, `15`, or `20`. + PerPage param.Field[float64] `query:"per_page"` +} + +// URLQuery serializes [RateLimitListParams]'s query parameters as `url.Values`. +func (r RateLimitListParams) URLQuery() (v url.Values) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatRepeat, + NestedFormat: apiquery.NestedQueryFormatDots, + }) +} + +type RateLimitDeleteParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} + +type RateLimitDeleteResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result RateLimitDeleteResponse `json:"result,required"` + // Whether the API call was successful + Success RateLimitDeleteResponseEnvelopeSuccess `json:"success,required"` + JSON rateLimitDeleteResponseEnvelopeJSON `json:"-"` +} + +// rateLimitDeleteResponseEnvelopeJSON contains the JSON metadata for the struct +// [RateLimitDeleteResponseEnvelope] +type rateLimitDeleteResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitDeleteResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitDeleteResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type RateLimitDeleteResponseEnvelopeSuccess bool + +const ( + RateLimitDeleteResponseEnvelopeSuccessTrue RateLimitDeleteResponseEnvelopeSuccess = true +) + +func (r RateLimitDeleteResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case RateLimitDeleteResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type RateLimitEditParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` + // The action to perform when the threshold of matched traffic within the + // configured period is exceeded. + Action param.Field[RateLimitEditParamsAction] `json:"action,required"` + // Determines which traffic the rate limit counts towards the threshold. + Match param.Field[RateLimitEditParamsMatch] `json:"match,required"` + // The time in seconds (an integer value) to count matching traffic. If the count + // exceeds the configured threshold within this period, Cloudflare will perform the + // configured action. + Period param.Field[float64] `json:"period,required"` + // The threshold that will trigger the configured mitigation action. Configure this + // value along with the `period` property to establish a threshold per period. + Threshold param.Field[float64] `json:"threshold,required"` +} + +func (r RateLimitEditParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The action to perform when the threshold of matched traffic within the +// configured period is exceeded. +type RateLimitEditParamsAction struct { + // The action to perform. + Mode param.Field[RateLimitEditParamsActionMode] `json:"mode"` + // A custom content type and reponse to return when the threshold is exceeded. The + // custom response configured in this object will override the custom error for the + // zone. This object is optional. Notes: If you omit this object, Cloudflare will + // use the default HTML error page. If "mode" is "challenge", "managed_challenge", + // or "js_challenge", Cloudflare will use the zone challenge pages and you should + // not provide the "response" object. + Response param.Field[RateLimitEditParamsActionResponse] `json:"response"` + // The time in seconds during which Cloudflare will perform the mitigation action. + // Must be an integer value greater than or equal to the period. Notes: If "mode" + // is "challenge", "managed_challenge", or "js_challenge", Cloudflare will use the + // zone's Challenge Passage time and you should not provide this value. + Timeout param.Field[float64] `json:"timeout"` +} + +func (r RateLimitEditParamsAction) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The action to perform. +type RateLimitEditParamsActionMode string + +const ( + RateLimitEditParamsActionModeSimulate RateLimitEditParamsActionMode = "simulate" + RateLimitEditParamsActionModeBan RateLimitEditParamsActionMode = "ban" + RateLimitEditParamsActionModeChallenge RateLimitEditParamsActionMode = "challenge" + RateLimitEditParamsActionModeJSChallenge RateLimitEditParamsActionMode = "js_challenge" + RateLimitEditParamsActionModeManagedChallenge RateLimitEditParamsActionMode = "managed_challenge" +) + +func (r RateLimitEditParamsActionMode) IsKnown() bool { + switch r { + case RateLimitEditParamsActionModeSimulate, RateLimitEditParamsActionModeBan, RateLimitEditParamsActionModeChallenge, RateLimitEditParamsActionModeJSChallenge, RateLimitEditParamsActionModeManagedChallenge: + return true + } + return false +} + +// A custom content type and reponse to return when the threshold is exceeded. The +// custom response configured in this object will override the custom error for the +// zone. This object is optional. Notes: If you omit this object, Cloudflare will +// use the default HTML error page. If "mode" is "challenge", "managed_challenge", +// or "js_challenge", Cloudflare will use the zone challenge pages and you should +// not provide the "response" object. +type RateLimitEditParamsActionResponse struct { + // The response body to return. The value must conform to the configured content + // type. + Body param.Field[string] `json:"body"` + // The content type of the body. Must be one of the following: `text/plain`, + // `text/xml`, or `application/json`. + ContentType param.Field[string] `json:"content_type"` +} + +func (r RateLimitEditParamsActionResponse) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// Determines which traffic the rate limit counts towards the threshold. +type RateLimitEditParamsMatch struct { + Headers param.Field[[]RateLimitEditParamsMatchHeader] `json:"headers"` + Request param.Field[RateLimitEditParamsMatchRequest] `json:"request"` + Response param.Field[RateLimitEditParamsMatchResponse] `json:"response"` +} + +func (r RateLimitEditParamsMatch) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type RateLimitEditParamsMatchHeader struct { + // The name of the response header to match. + Name param.Field[string] `json:"name"` + // The operator used when matching: `eq` means "equal" and `ne` means "not equal". + Op param.Field[RateLimitEditParamsMatchHeadersOp] `json:"op"` + // The value of the response header, which must match exactly. + Value param.Field[string] `json:"value"` +} + +func (r RateLimitEditParamsMatchHeader) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// The operator used when matching: `eq` means "equal" and `ne` means "not equal". +type RateLimitEditParamsMatchHeadersOp string + +const ( + RateLimitEditParamsMatchHeadersOpEq RateLimitEditParamsMatchHeadersOp = "eq" + RateLimitEditParamsMatchHeadersOpNe RateLimitEditParamsMatchHeadersOp = "ne" +) + +func (r RateLimitEditParamsMatchHeadersOp) IsKnown() bool { + switch r { + case RateLimitEditParamsMatchHeadersOpEq, RateLimitEditParamsMatchHeadersOpNe: + return true + } + return false +} + +type RateLimitEditParamsMatchRequest struct { + // The HTTP methods to match. You can specify a subset (for example, + // `['POST','PUT']`) or all methods (`['_ALL_']`). This field is optional when + // creating a rate limit. + Methods param.Field[[]Methods] `json:"methods"` + // The HTTP schemes to match. You can specify one scheme (`['HTTPS']`), both + // schemes (`['HTTP','HTTPS']`), or all schemes (`['_ALL_']`). This field is + // optional. + Schemes param.Field[[]string] `json:"schemes"` + // The URL pattern to match, composed of a host and a path such as + // `example.org/path*`. Normalization is applied before the pattern is matched. `*` + // wildcards are expanded to match applicable traffic. Query strings are not + // matched. Set the value to `*` to match all traffic to your zone. + URL param.Field[string] `json:"url"` +} + +func (r RateLimitEditParamsMatchRequest) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type RateLimitEditParamsMatchResponse struct { + // When true, only the uncached traffic served from your origin servers will count + // towards rate limiting. In this case, any cached traffic served by Cloudflare + // will not count towards rate limiting. This field is optional. Notes: This field + // is deprecated. Instead, use response headers and set "origin_traffic" to "false" + // to avoid legacy behaviour interacting with the "response_headers" property. + OriginTraffic param.Field[bool] `json:"origin_traffic"` +} + +func (r RateLimitEditParamsMatchResponse) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type RateLimitEditResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result RateLimit `json:"result,required"` + // Whether the API call was successful + Success RateLimitEditResponseEnvelopeSuccess `json:"success,required"` + JSON rateLimitEditResponseEnvelopeJSON `json:"-"` +} + +// rateLimitEditResponseEnvelopeJSON contains the JSON metadata for the struct +// [RateLimitEditResponseEnvelope] +type rateLimitEditResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitEditResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitEditResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type RateLimitEditResponseEnvelopeSuccess bool + +const ( + RateLimitEditResponseEnvelopeSuccessTrue RateLimitEditResponseEnvelopeSuccess = true +) + +func (r RateLimitEditResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case RateLimitEditResponseEnvelopeSuccessTrue: + return true + } + return false +} + +type RateLimitGetParams struct { + // Identifier + ZoneID param.Field[string] `path:"zone_id,required"` +} + +type RateLimitGetResponseEnvelope struct { + Errors []shared.ResponseInfo `json:"errors,required"` + Messages []shared.ResponseInfo `json:"messages,required"` + Result RateLimit `json:"result,required"` + // Whether the API call was successful + Success RateLimitGetResponseEnvelopeSuccess `json:"success,required"` + JSON rateLimitGetResponseEnvelopeJSON `json:"-"` +} + +// rateLimitGetResponseEnvelopeJSON contains the JSON metadata for the struct +// [RateLimitGetResponseEnvelope] +type rateLimitGetResponseEnvelopeJSON struct { + Errors apijson.Field + Messages apijson.Field + Result apijson.Field + Success apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *RateLimitGetResponseEnvelope) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r rateLimitGetResponseEnvelopeJSON) RawJSON() string { + return r.raw +} + +// Whether the API call was successful +type RateLimitGetResponseEnvelopeSuccess bool + +const ( + RateLimitGetResponseEnvelopeSuccessTrue RateLimitGetResponseEnvelopeSuccess = true +) + +func (r RateLimitGetResponseEnvelopeSuccess) IsKnown() bool { + switch r { + case RateLimitGetResponseEnvelopeSuccessTrue: + return true + } + return false +} diff --git a/rate_limits/ratelimit_test.go b/rate_limits/ratelimit_test.go new file mode 100644 index 00000000000..977e6294506 --- /dev/null +++ b/rate_limits/ratelimit_test.go @@ -0,0 +1,222 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package rate_limits_test + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/cloudflare/cloudflare-go/v3" + "github.com/cloudflare/cloudflare-go/v3/internal/testutil" + "github.com/cloudflare/cloudflare-go/v3/option" + "github.com/cloudflare/cloudflare-go/v3/rate_limits" +) + +func TestRateLimitNewWithOptionalParams(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.RateLimits.New(context.TODO(), rate_limits.RateLimitNewParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Action: cloudflare.F(rate_limits.RateLimitNewParamsAction{ + Mode: cloudflare.F(rate_limits.RateLimitNewParamsActionModeSimulate), + Response: cloudflare.F(rate_limits.RateLimitNewParamsActionResponse{ + Body: cloudflare.F("This request has been rate-limited."), + ContentType: cloudflare.F("text/xml"), + }), + Timeout: cloudflare.F(86400.000000), + }), + Match: cloudflare.F(rate_limits.RateLimitNewParamsMatch{ + Headers: cloudflare.F([]rate_limits.RateLimitNewParamsMatchHeader{{ + Name: cloudflare.F("Cf-Cache-Status"), + Op: cloudflare.F(rate_limits.RateLimitNewParamsMatchHeadersOpEq), + Value: cloudflare.F("HIT"), + }, { + Name: cloudflare.F("Cf-Cache-Status"), + Op: cloudflare.F(rate_limits.RateLimitNewParamsMatchHeadersOpEq), + Value: cloudflare.F("HIT"), + }, { + Name: cloudflare.F("Cf-Cache-Status"), + Op: cloudflare.F(rate_limits.RateLimitNewParamsMatchHeadersOpEq), + Value: cloudflare.F("HIT"), + }}), + Request: cloudflare.F(rate_limits.RateLimitNewParamsMatchRequest{ + Methods: cloudflare.F([]rate_limits.Methods{rate_limits.MethodsGet, rate_limits.MethodsPost}), + Schemes: cloudflare.F([]string{"HTTP", "HTTPS"}), + URL: cloudflare.F("*.example.org/path*"), + }), + Response: cloudflare.F(rate_limits.RateLimitNewParamsMatchResponse{ + OriginTraffic: cloudflare.F(true), + }), + }), + Period: cloudflare.F(900.000000), + Threshold: cloudflare.F(60.000000), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestRateLimitListWithOptionalParams(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.RateLimits.List(context.TODO(), rate_limits.RateLimitListParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Page: cloudflare.F(1.000000), + PerPage: cloudflare.F(1.000000), + }) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestRateLimitDelete(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.RateLimits.Delete( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b59", + rate_limits.RateLimitDeleteParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestRateLimitEditWithOptionalParams(t *testing.T) { + t.Skip("TODO: investigate broken test") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.RateLimits.Edit( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b59", + rate_limits.RateLimitEditParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + Action: cloudflare.F(rate_limits.RateLimitEditParamsAction{ + Mode: cloudflare.F(rate_limits.RateLimitEditParamsActionModeSimulate), + Response: cloudflare.F(rate_limits.RateLimitEditParamsActionResponse{ + Body: cloudflare.F("This request has been rate-limited."), + ContentType: cloudflare.F("text/xml"), + }), + Timeout: cloudflare.F(86400.000000), + }), + Match: cloudflare.F(rate_limits.RateLimitEditParamsMatch{ + Headers: cloudflare.F([]rate_limits.RateLimitEditParamsMatchHeader{{ + Name: cloudflare.F("Cf-Cache-Status"), + Op: cloudflare.F(rate_limits.RateLimitEditParamsMatchHeadersOpEq), + Value: cloudflare.F("HIT"), + }, { + Name: cloudflare.F("Cf-Cache-Status"), + Op: cloudflare.F(rate_limits.RateLimitEditParamsMatchHeadersOpEq), + Value: cloudflare.F("HIT"), + }, { + Name: cloudflare.F("Cf-Cache-Status"), + Op: cloudflare.F(rate_limits.RateLimitEditParamsMatchHeadersOpEq), + Value: cloudflare.F("HIT"), + }}), + Request: cloudflare.F(rate_limits.RateLimitEditParamsMatchRequest{ + Methods: cloudflare.F([]rate_limits.Methods{rate_limits.MethodsGet, rate_limits.MethodsPost}), + Schemes: cloudflare.F([]string{"HTTP", "HTTPS"}), + URL: cloudflare.F("*.example.org/path*"), + }), + Response: cloudflare.F(rate_limits.RateLimitEditParamsMatchResponse{ + OriginTraffic: cloudflare.F(true), + }), + }), + Period: cloudflare.F(900.000000), + Threshold: cloudflare.F(60.000000), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + +func TestRateLimitGet(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := cloudflare.NewClient( + option.WithBaseURL(baseURL), + option.WithAPIKey("144c9defac04969c7bfad8efaa8ea194"), + option.WithAPIEmail("user@example.com"), + ) + _, err := client.RateLimits.Get( + context.TODO(), + "372e67954025e0ba6aaa6d586b9e0b59", + rate_limits.RateLimitGetParams{ + ZoneID: cloudflare.F("023e105f4ecef8ad9ca31a8372d0c353"), + }, + ) + if err != nil { + var apierr *cloudflare.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +}