From cc8a68bf870469fc1d3aae2b45e6b8bc881f8df5 Mon Sep 17 00:00:00 2001 From: Rex Scaria Date: Tue, 17 Aug 2021 15:49:57 -0400 Subject: [PATCH] GATE-1703 team rules + accounts + config api --- teams_accounts.go | 119 +++++++++++ teams_accounts_test.go | 128 ++++++++++++ teams_rules.go | 222 +++++++++++++++++++++ teams_rules_test.go | 438 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 907 insertions(+) create mode 100644 teams_accounts.go create mode 100644 teams_accounts_test.go create mode 100644 teams_rules.go create mode 100644 teams_rules_test.go diff --git a/teams_accounts.go b/teams_accounts.go new file mode 100644 index 000000000000..220b8246ab36 --- /dev/null +++ b/teams_accounts.go @@ -0,0 +1,119 @@ +package cloudflare + +import ( + "context" + "encoding/json" + "fmt" + "github.com/pkg/errors" + "net/http" + "time" +) + +type TeamsAccount struct { + GatewayTag string `json:"gateway_tag"` // Internal teams ID + ProviderName string `json:"provider_name"` // Auth provider + ID string `json:"id"` // cloudflare account ID +} + +// TeamsAccountResponse is the API response, containing information on teams account +type TeamsAccountResponse struct { + Response + Result TeamsAccount `json:"result"` +} + +// TeamsConfigResponse is the API response, containing information on teams account config +type TeamsConfigResponse struct { + Response + Result TeamsConfiguration `json:"result"` +} + +// TeamsConfiguration data model. +type TeamsConfiguration struct { + Settings TeamsAccountSettings `json:"settings"` + CreatedAt time.Time `json:"created_at,omitempty"` + UpdatedAt time.Time `json:"updated_at,omitempty"` +} + +type TeamsAccountSettings struct { + Antivirus *TeamsAntivirus `json:"antivirus,omitempty"` + TLSDecrypt *TeamsTLSDecrypt `json:"tls_decrypt,omitempty"` + ActivityLog *TeamsActivityLog `json:"activity_log,omitempty"` + BlockPage *TeamsBlockPage `json:"block_page,omitempty"` +} + +type TeamsAntivirus struct { + EnabledDownloadPhase bool `json:"enabled_download_phase,omitempty"` + EnabledUploadPhase bool `json:"enabled_upload_phase,omitempty"` + FailClosed bool `json:"fail_closed,omitempty"` +} + +type TeamsTLSDecrypt struct { + Enabled bool `json:"enabled,omitempty"` +} + +type TeamsActivityLog struct { + Enabled bool `json:"enabled,omitempty"` +} + +type TeamsBlockPage struct { + Enabled bool `json:"enabled,omitempty"` + FooterText string `json:"footer_text,omitempty"` + HeaderText string `json:"header_text,omitempty"` + LogoPath string `json:"logo_path,omitempty"` + BackgroundColor string `json:"background_color,omitempty"` + Name string `json:"name,omitempty"` +} + +// TeamsAccount returns teams account information with internal and external id +func (api *API) TeamsAccount(ctx context.Context, accountID string) (TeamsAccount, error) { + uri := fmt.Sprintf("/accounts/%s/gateway", accountID) + + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return TeamsAccount{}, err + } + + var teamsAccountResponse TeamsAccountResponse + err = json.Unmarshal(res, &teamsAccountResponse) + if err != nil { + return TeamsAccount{}, errors.Wrap(err, errUnmarshalError) + } + + return teamsAccountResponse.Result, nil +} + +// TeamsAccountConfiguration returns teams account configuration +func (api *API) TeamsAccountConfiguration(ctx context.Context, accountID string) (TeamsConfiguration, error) { + uri := fmt.Sprintf("/accounts/%s/gateway/configuration", accountID) + + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return TeamsConfiguration{}, err + } + + var teamsConfigResponse TeamsConfigResponse + err = json.Unmarshal(res, &teamsConfigResponse) + if err != nil { + return TeamsConfiguration{}, errors.Wrap(err, errUnmarshalError) + } + + return teamsConfigResponse.Result, nil +} + +// TeamsAccountUpdateConfiguration upserts teams account configuration +func (api *API) TeamsAccountUpdateConfiguration(ctx context.Context, accountID string, config TeamsConfiguration) (TeamsConfiguration, error) { + uri := fmt.Sprintf("/accounts/%s/gateway/configuration", accountID) + + res, err := api.makeRequestContext(ctx, http.MethodPut, uri, config) + if err != nil { + return TeamsConfiguration{}, err + } + + var teamsConfigResponse TeamsConfigResponse + err = json.Unmarshal(res, &teamsConfigResponse) + if err != nil { + return TeamsConfiguration{}, errors.Wrap(err, errUnmarshalError) + } + + return teamsConfigResponse.Result, nil +} diff --git a/teams_accounts_test.go b/teams_accounts_test.go new file mode 100644 index 000000000000..d24c9c9c046c --- /dev/null +++ b/teams_accounts_test.go @@ -0,0 +1,128 @@ +package cloudflare + +import ( + "context" + "fmt" + "github.com/stretchr/testify/assert" + "net/http" + "testing" +) + +func TestTeamsAccount(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "id": "%s", + "provider_name": "cf", + "gateway_tag": "1234" + } + } + `, testAccountID) + } + + mux.HandleFunc("/accounts/"+testAccountID+"/gateway", handler) + + actual, err := client.TeamsAccount(context.Background(), testAccountID) + + if assert.NoError(t, err) { + assert.Equal(t, actual.ProviderName, "cf") + assert.Equal(t, actual.GatewayTag, "1234") + assert.Equal(t, actual.ID, testAccountID) + } +} + +func TestTeamsAccountConfiguration(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "settings": { + "antivirus": { + "enabled_download_phase": true + }, + "tls_decrypt": { + "enabled": true + }, + "activity_log": { + "enabled": true + } + } + } + } + `) + } + + mux.HandleFunc("/accounts/"+testAccountID+"/gateway/configuration", handler) + + actual, err := client.TeamsAccountConfiguration(context.Background(), testAccountID) + + if assert.NoError(t, err) { + assert.Equal(t, actual.Settings, TeamsAccountSettings{ + Antivirus: &TeamsAntivirus{EnabledDownloadPhase: true}, + ActivityLog: &TeamsActivityLog{Enabled: true}, + TLSDecrypt: &TeamsTLSDecrypt{Enabled: true}, + }) + } +} + +func TestTeamsAccountUpdateConfiguration(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPut, r.Method, "Expected method 'put', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "settings": { + "antivirus": { + "enabled_download_phase": false + }, + "tls_decrypt": { + "enabled": true + }, + "activity_log": { + "enabled": true + } + } + } + } + `) + } + + settings := TeamsAccountSettings{ + Antivirus: &TeamsAntivirus{EnabledDownloadPhase: false}, + ActivityLog: &TeamsActivityLog{Enabled: true}, + TLSDecrypt: &TeamsTLSDecrypt{Enabled: true}, + } + + mux.HandleFunc("/accounts/"+testAccountID+"/gateway/configuration", handler) + + configuration := TeamsConfiguration{ + Settings: settings, + } + actual, err := client.TeamsAccountUpdateConfiguration(context.Background(), testAccountID, configuration) + + if assert.NoError(t, err) { + + assert.Equal(t, actual, configuration) + } +} diff --git a/teams_rules.go b/teams_rules.go new file mode 100644 index 000000000000..eeeca38fb902 --- /dev/null +++ b/teams_rules.go @@ -0,0 +1,222 @@ +package cloudflare + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/pkg/errors" +) + +type TeamsRuleSettings struct { + // Enable block page on rules with action block + BlockPageEnabled bool `json:"block_page_enabled"` + + // show this string at block page caused by this rule + BlockReason string `json:"block_reason"` + + // list of ipv4 or ipv6 ips to override with, when action is set to dns override + OverrideIPs []string `json:"override_ips"` + + // host name to override with when action is set to dns override. Can not be used with OverrideIPs + OverrideHost string `json:"override_host"` + + // settings for l4(network) level overrides + L4Override *TeamsL4OverrideSettings `json:"l4override"` + + // settings for browser isolation actions + BISOAdminControls *TeamsBISOAdminControlSettings `json:"biso_admin_controls"` +} + +// TeamsL4OverrideSettings used in l4 filter type rule with action set to override +type TeamsL4OverrideSettings struct { + IP string `json:"ip,omitempty"` + Port int `json:"port,omitempty"` +} + +type TeamsBISOAdminControlSettings struct { + DisablePrinting bool `json:"dp"` + DisableCopyPaste bool `json:"dcp"` +} + +type TeamsFilterType string + +type TeamsGatewayAction string + +const ( + HttpFilter TeamsFilterType = "http" + DnsFilter TeamsFilterType = "dns" + L4Filter TeamsFilterType = "l4" +) + +const ( + Allow TeamsGatewayAction = "allow" + Block TeamsGatewayAction = "block" + SafeSearch TeamsGatewayAction = "safesearch" + YTRestricted TeamsGatewayAction = "ytrestricted" + On TeamsGatewayAction = "on" + Off TeamsGatewayAction = "off" + Scan TeamsGatewayAction = "scan" + NoScan TeamsGatewayAction = "noscan" + Isolate TeamsGatewayAction = "isolate" + NoIsolate TeamsGatewayAction = "noisolate" + Override TeamsGatewayAction = "override" + L4Override TeamsGatewayAction = "l4_override" +) + +// TeamsRule represents an Teams wirefilter rule. +type TeamsRule struct { + ID string `json:"id,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` + DeletedAt *time.Time `json:"deleted_at,omitempty"` + Name string `json:"name"` + Description string `json:"description"` + Precedence uint64 `json:"precedence"` + Enabled bool `json:"enabled"` + Action TeamsGatewayAction `json:"action"` + Filters []TeamsFilterType `json:"filters"` + Traffic string `json:"traffic"` + Identity string `json:"identity"` + Version uint64 `json:"version"` + RuleSettings TeamsRuleSettings `json:"rule_settings,omitempty"` +} + +// TeamsRuleResponse is the API response, containing a single rule +type TeamsRuleResponse struct { + Response + Result TeamsRule `json:"result"` +} + +// TeamsRuleResponse is the API response, containing an array of rules +type TeamsRulesResponse struct { + Response + Result []TeamsRule `json:"result"` +} + +// TeamsRulePatchRequest is used to patch an existing rule +type TeamsRulePatchRequest struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Precedence uint64 `json:"precedencTeamsRulee"` + Enabled bool `json:"enabled"` + Action TeamsGatewayAction `json:"action"` + RuleSettings TeamsRuleSettings `json:"rule_settings,omitempty"` +} + +// TeamsRules returns all rules within an account. +// +// API reference: https://api.cloudflare.com/#teams-rules-properties +func (api *API) TeamsRules(ctx context.Context, accountID string) ([]TeamsRule, error) { + uri := fmt.Sprintf("/accounts/%s/gateway/rules", accountID) + + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return []TeamsRule{}, err + } + + var teamsRulesResponse TeamsRulesResponse + err = json.Unmarshal(res, &teamsRulesResponse) + if err != nil { + return []TeamsRule{}, errors.Wrap(err, errUnmarshalError) + } + + return teamsRulesResponse.Result, nil +} + +// TeamsRule returns the rule with rule id in the url +// +// API reference: https://api.cloudflare.com/#teams-rules-properties +func (api *API) TeamsRule(ctx context.Context, accountID string, ruleId string) (TeamsRule, error) { + uri := fmt.Sprintf("/accounts/%s/gateway/rules/%s", accountID, ruleId) + + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return TeamsRule{}, err + } + + var teamsRuleResponse TeamsRuleResponse + err = json.Unmarshal(res, &teamsRuleResponse) + if err != nil { + return TeamsRule{}, errors.Wrap(err, errUnmarshalError) + } + + return teamsRuleResponse.Result, nil +} + +// TeamsCreateRule creates a rule with wirefilter expression +// +// API reference: https://api.cloudflare.com/#teams-rules-properties +func (api *API) TeamsCreateRule(ctx context.Context, accountID string, rule TeamsRule) (TeamsRule, error) { + uri := fmt.Sprintf("/accounts/%s/gateway/rules", accountID) + + res, err := api.makeRequestContext(ctx, http.MethodPost, uri, rule) + if err != nil { + return TeamsRule{}, err + } + + var teamsRuleResponse TeamsRuleResponse + err = json.Unmarshal(res, &teamsRuleResponse) + if err != nil { + return TeamsRule{}, errors.Wrap(err, errUnmarshalError) + } + + return teamsRuleResponse.Result, nil +} + +// TeamsUpdateRule updates a rule with wirefilter expression +// +// API reference: https://api.cloudflare.com/#teams-rules-properties +func (api *API) TeamsUpdateRule(ctx context.Context, accountID string, ruleId string, rule TeamsRule) (TeamsRule, error) { + uri := fmt.Sprintf("/accounts/%s/gateway/rules/%s", accountID, ruleId) + + res, err := api.makeRequestContext(ctx, http.MethodPut, uri, rule) + if err != nil { + return TeamsRule{}, err + } + + var teamsRuleResponse TeamsRuleResponse + err = json.Unmarshal(res, &teamsRuleResponse) + if err != nil { + return TeamsRule{}, errors.Wrap(err, errUnmarshalError) + } + + return teamsRuleResponse.Result, nil +} + +// TeamsPatchRule patches a rule associated values +// +// API reference: https://api.cloudflare.com/#teams-rules-properties +func (api *API) TeamsPatchRule(ctx context.Context, accountID string, ruleId string, rule TeamsRulePatchRequest) (TeamsRule, error) { + uri := fmt.Sprintf("/accounts/%s/gateway/rules/%s", accountID, ruleId) + + res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, rule) + if err != nil { + return TeamsRule{}, err + } + + var teamsRuleResponse TeamsRuleResponse + err = json.Unmarshal(res, &teamsRuleResponse) + if err != nil { + return TeamsRule{}, errors.Wrap(err, errUnmarshalError) + } + + return teamsRuleResponse.Result, nil +} + +// TeamsDeleteRule deletes a rule +// +// API reference: https://api.cloudflare.com/#teams-rules-properties +func (api *API) TeamsDeleteRule(ctx context.Context, accountID string, ruleId string) error { + uri := fmt.Sprintf("/accounts/%s/gateway/rules/%s", accountID, ruleId) + + _, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) + if err != nil { + return err + } + + return nil +} diff --git a/teams_rules_test.go b/teams_rules_test.go new file mode 100644 index 000000000000..ea24c825648c --- /dev/null +++ b/teams_rules_test.go @@ -0,0 +1,438 @@ +package cloudflare + +import ( + "context" + "fmt" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestTeamsRules(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": [ + { + "id": "7559a944-3dd7-41bf-b183-360a814a8c36", + "name": "rule1", + "description": "rule description", + "precedence": 1000, + "enabled": false, + "action": "isolate", + "filters": [ + "http" + ], + "created_at": "2014-01-01T05:20:00.12345Z", + "updated_at": "2014-01-01T05:20:00.12345Z", + "deleted_at": null, + "traffic": "http.host == \"example.com\"", + "identity": "", + "version": 1, + "rule_settings": { + "block_page_enabled": false, + "block_reason": "", + "override_ips": null, + "override_host": "", + "l4override": null, + "biso_admin_controls": null, + "add_headers": null + } + }, + { + "id": "9ae57318-f32e-46b3-b889-48dd6dcc49af", + "name": "rule2", + "description": "rule description 2", + "precedence": 2000, + "enabled": true, + "action": "block", + "filters": [ + "http" + ], + "created_at": "2014-01-01T05:20:00.12345Z", + "updated_at": "2014-01-01T05:20:00.12345Z", + "deleted_at": null, + "traffic": "http.host == \"abcd.com\"", + "identity": "", + "version": 1, + "rule_settings": { + "block_page_enabled": true, + "block_reason": "", + "override_ips": null, + "override_host": "", + "l4override": null, + "biso_admin_controls": null, + "add_headers": null + } + } + ] + } + `) + } + + createdAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z") + updatedAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z") + + want := []TeamsRule{{ + ID: "7559a944-3dd7-41bf-b183-360a814a8c36", + Name: "rule1", + Description: "rule description", + Precedence: 1000, + Enabled: false, + Action: Isolate, + Filters: []TeamsFilterType{HttpFilter}, + Traffic: `http.host == "example.com"`, + Identity: "", + Version: 1, + RuleSettings: TeamsRuleSettings{ + BlockPageEnabled: false, + BlockReason: "", + OverrideIPs: nil, + OverrideHost: "", + L4Override: nil, + BISOAdminControls: nil, + }, + CreatedAt: &createdAt, + UpdatedAt: &updatedAt, + DeletedAt: nil, + }, + { + ID: "9ae57318-f32e-46b3-b889-48dd6dcc49af", + Name: "rule2", + Description: "rule description 2", + Precedence: 2000, + Enabled: true, + Action: Block, + Filters: []TeamsFilterType{HttpFilter}, + Traffic: `http.host == "abcd.com"`, + Identity: "", + Version: 1, + RuleSettings: TeamsRuleSettings{ + BlockPageEnabled: true, + BlockReason: "", + OverrideIPs: nil, + OverrideHost: "", + L4Override: nil, + BISOAdminControls: nil, + }, + CreatedAt: &createdAt, + UpdatedAt: &updatedAt, + DeletedAt: nil, + }} + + mux.HandleFunc("/accounts/"+testAccountID+"/gateway/rules", handler) + + actual, err := client.TeamsRules(context.Background(), testAccountID) + + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } +} + +func TestTeamsRule(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "id": "7559a944-3dd7-41bf-b183-360a814a8c36", + "name": "rule1", + "description": "rule description", + "precedence": 1000, + "enabled": false, + "action": "isolate", + "filters": [ + "http" + ], + "created_at": "2014-01-01T05:20:00.12345Z", + "updated_at": "2014-01-01T05:20:00.12345Z", + "deleted_at": null, + "traffic": "http.host == \"abcd.com\"", + "identity": "", + "version": 1, + "rule_settings": { + "block_page_enabled": false, + "block_reason": "", + "override_ips": null, + "override_host": "", + "l4override": null, + "biso_admin_controls": null, + "add_headers": null + } + } + } + `) + } + + createdAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z") + updatedAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z") + + want := TeamsRule{ + ID: "7559a944-3dd7-41bf-b183-360a814a8c36", + Name: "rule1", + Description: "rule description", + Precedence: 1000, + Enabled: false, + Action: Isolate, + Filters: []TeamsFilterType{HttpFilter}, + Traffic: `http.host == "abcd.com"`, + Identity: "", + Version: 1, + RuleSettings: TeamsRuleSettings{ + BlockPageEnabled: false, + BlockReason: "", + OverrideIPs: nil, + OverrideHost: "", + L4Override: nil, + BISOAdminControls: nil, + }, + CreatedAt: &createdAt, + UpdatedAt: &updatedAt, + DeletedAt: nil, + } + + mux.HandleFunc("/accounts/"+testAccountID+"/gateway/rules/7559a9443dd741bfb183360a814a8c36", handler) + + actual, err := client.TeamsRule(context.Background(), testAccountID, "7559a9443dd741bfb183360a814a8c36") + + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } +} + +func TestTeamsCreateRule(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "name": "rule1", + "description": "rule description", + "precedence": 1000, + "enabled": false, + "action": "isolate", + "filters": [ + "http" + ], + "traffic": "http.host == \"abcd.com\"", + "identity": "", + "rule_settings": { + "block_page_enabled": false, + "block_reason": "", + "override_ips": null, + "override_host": "", + "l4override": null, + "biso_admin_controls": null, + "add_headers": null + } + } + } + `) + } + + want := TeamsRule{ + Name: "rule1", + Description: "rule description", + Precedence: 1000, + Enabled: false, + Action: Isolate, + Filters: []TeamsFilterType{HttpFilter}, + Traffic: `http.host == "abcd.com"`, + Identity: "", + RuleSettings: TeamsRuleSettings{ + BlockPageEnabled: false, + BlockReason: "", + OverrideIPs: nil, + OverrideHost: "", + L4Override: nil, + BISOAdminControls: nil, + }, + DeletedAt: nil, + } + + mux.HandleFunc("/accounts/"+testAccountID+"/gateway/rules", handler) + + actual, err := client.TeamsCreateRule(context.Background(), testAccountID, want) + + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } +} + +func TestTeamsUpdateRule(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "id": "7559a944-3dd7-41bf-b183-360a814a8c36", + "name": "rule_name_change", + "description": "rule new description", + "precedence": 3000, + "enabled": true, + "action": "block", + "filters": [ + "http" + ], + "traffic": "", + "identity": "", + "created_at": "2014-01-01T05:20:00.12345Z", + "updated_at": "2014-02-01T05:20:00.12345Z", + "rule_settings": { + "block_page_enabled": false, + "block_reason": "", + "override_ips": null, + "override_host": "", + "l4override": null, + "biso_admin_controls": null, + "add_headers": null + } + } + } + `) + } + + createdAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z") + updatedAt, _ := time.Parse(time.RFC3339, "2014-02-01T05:20:00.12345Z") + + want := TeamsRule{ + ID: "7559a944-3dd7-41bf-b183-360a814a8c36", + Name: "rule_name_change", + Description: "rule new description", + Precedence: 3000, + Enabled: true, + Action: Block, + Filters: []TeamsFilterType{HttpFilter}, + Traffic: "", + Identity: "", + RuleSettings: TeamsRuleSettings{ + BlockPageEnabled: false, + BlockReason: "", + OverrideIPs: nil, + OverrideHost: "", + L4Override: nil, + BISOAdminControls: nil, + }, + CreatedAt: &createdAt, + UpdatedAt: &updatedAt, + DeletedAt: nil, + } + + mux.HandleFunc("/accounts/"+testAccountID+"/gateway/rules/7559a9443dd741bfb183360a814a8c36", handler) + + actual, err := client.TeamsUpdateRule(context.Background(), testAccountID, "7559a9443dd741bfb183360a814a8c36", want) + + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } +} + +func TestTeamsPatchRule(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPatch, r.Method, "Expected method 'Patch', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "name": "rule_name_change", + "description": "rule new description", + "precedence": 3000, + "enabled": true, + "action": "block", + "rule_settings": { + "block_page_enabled": false, + "block_reason": "", + "override_ips": null, + "override_host": "", + "l4override": null, + "biso_admin_controls": null, + "add_headers": null + } + } + } + `) + } + + reqBody := TeamsRulePatchRequest{ + Name: "rule_name_change", + Description: "rule new description", + Precedence: 3000, + Enabled: true, + Action: Block, + RuleSettings: TeamsRuleSettings{ + BlockPageEnabled: false, + BlockReason: "", + OverrideIPs: nil, + OverrideHost: "", + L4Override: nil, + BISOAdminControls: nil, + }, + } + + mux.HandleFunc("/accounts/"+testAccountID+"/gateway/rules/7559a9443dd741bfb183360a814a8c36", handler) + + actual, err := client.TeamsPatchRule(context.Background(), testAccountID, "7559a9443dd741bfb183360a814a8c36", reqBody) + + if assert.NoError(t, err) { + assert.Equal(t, actual.Name, "rule_name_change") + assert.Equal(t, actual.Description, "rule new description") + assert.Equal(t, actual.Precedence, uint64(3000)) + assert.Equal(t, actual.Action, Block) + assert.Equal(t, actual.Enabled, true) + } +} + +func TestTeamsDeleteRule(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'Delete', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": nil + } + `) + } + + mux.HandleFunc("/accounts/"+testAccountID+"/gateway/rules/7559a9443dd741bfb183360a814a8c36", handler) + + err := client.TeamsDeleteRule(context.Background(), testAccountID, "7559a9443dd741bfb183360a814a8c36") + + assert.NoError(t, err) +}