diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..e2c8769 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,67 @@ +name: "CodeQL" + +on: + workflow_dispatch: + push: + branches: [master] + pull_request: + # The branches below must be a subset of the branches above + branches: [master] + schedule: + - cron: '0 22 * * 0' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + # Override automatic language detection by changing the below list + # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] + language: ['go'] + # Learn more... + # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index c36f7b2..a0b27a0 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -7,16 +7,21 @@ jobs: runs-on: ubuntu-latest steps: - - name: Set up Go 1.12 + - name: Set up Go 1.14 uses: actions/setup-go@v1 with: - go-version: 1.12 + go-version: 1.14 id: go + - name: golint + run: | + go get -u golang.org/x/lint/golint + - name: Check out code into the Go module directory uses: actions/checkout@v1 - name: Build run: | + export PATH=$PATH:$(go env GOPATH)/bin go build -v . - make lint + GOBIN=$PWD/bin make lint diff --git a/.gitignore b/.gitignore index 3e88108..1806f7f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,5 +12,4 @@ *.out .idea/ -.vscode/settings.json -.vscode/launch.json +.vscode/ diff --git a/Makefile b/Makefile index 6e45d57..a72c78b 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,13 @@ lint: go vet + golint test -z $(gofmt -s -l .) test: go test -v +<<<<<<< HEAD publish: test git tag -fa v0.3.0 git push origin --tags +======= +>>>>>>> upstream/master diff --git a/api.go b/api.go index d029ec6..51b27d3 100644 --- a/api.go +++ b/api.go @@ -9,7 +9,6 @@ import ( "io/ioutil" "net/http" "net/url" - "runtime" "strings" "time" ) @@ -462,6 +461,7 @@ type Site struct { AnalyticsEvents map[string]string TopAttacks map[string]string Members map[string]string + AgentAnonMode string } // sitesResponse is the response for list sites. @@ -506,6 +506,8 @@ type UpdateSiteBody struct { DisplayName string `json:"displayName,omitempty"` AgentLevel string `json:"agentLevel,omitempty"` BlockDurationSeconds int `json:"blockDurationSeconds,omitempty"` + BlockHTTPCode int `json:"blockHTTPCode,omitempty"` + AgentAnonMode string `json:"agentAnonMode,omitempty"` } // UpdateSite updates a site by name. @@ -529,109 +531,115 @@ func (sc *Client) UpdateSite(corpName, siteName string, body UpdateSiteBody) (Si return site, nil } -// CreateCustomAlertBody is the body for creating a custom alert. -type CreateCustomAlertBody struct { - TagName string `json:"tagName,omitempty"` //The name of the tag whose occurrences the alert is watching. Must match an existing tag - LongName string `json:"longName,omitempty"` //A human readable description of the alert. Must be between 3 and 25 characters. - Interval int `json:"interval"` //The number of minutes of past traffic to examine. Must be 1, 10 or 60. - Threshold int `json:"threshold"` //The number of occurrences of the tag in the interval needed to trigger the alert. - BlockDurationSeconds int `json:"blockDurationSeconds"` //The number of seconds this alert is active. - Enabled bool `json:"enabled"` //A flag to toggle this alert. - Action string `json:"action,omitempty"` //A flag that describes what happens when the alert is triggered. 'info' creates an incident in the dashboard. 'flagged' creates an incident and blocks traffic for 24 hours. -} - -//ResponseCustomAlertBody contains the data for a custom alert -type ResponseCustomAlertBody struct { - CreateCustomAlertBody - ID string `json:"id,omitempty"` //Site-specific unique ID of the alert - Type string `json:"type,omitempty"` //Type of alert (siteAlert, template, rateLimit, siteMetric) - SkipNotifications bool `json:"skipNotifications"` //A flag to disable external notifications - slack, webhooks, emails, etc. - FieldName string `json:"fieldName,omitempty"` - CreatedBy string `json:"createdBy,omitempty"` //The email of the user that created the alert - Created time.Time `json:"created,omitempty"` //Created RFC3339 date time - Operator string -} - -// ResponseCustomAlertsBodyList is the response for the alerts endpoint -type ResponseCustomAlertsBodyList struct { - Data []ResponseCustomAlertBody -} - -// GetAllSiteCustomAlerts lists custom alerts for a given corp and site. -func (sc Client) GetAllSiteCustomAlerts(corpName, siteName string) (ResponseCustomAlertsBodyList, error) { +// CustomAlert is the body for creating a custom alert. +type CustomAlert struct { + ID string `json:"id,omitempty"` //Site-specific unique ID of the alert + SiteID string `json:"siteID,omitempty"` + TagName string `json:"tagName,omitempty"` //The name of the tag whose occurrences the alert is watching. Must match an existing tag + LongName string `json:"longName,omitempty"` //A human readable description of the alert. Must be between 3 and 25 characters. + Interval int `json:"interval"` //The number of minutes of past traffic to examine. Must be 1, 10 or 60. + Threshold int `json:"threshold"` //The number of occurrences of the tag in the interval needed to trigger the alert. + BlockDurationSeconds int `json:"blockDurationSeconds"` //The number of seconds this alert is active. + Enabled bool `json:"enabled"` //A flag to toggle this alert. + Action string `json:"action,omitempty"` //A flag that describes what happens when the alert is triggered. 'info' creates an incident in the dashboard. 'flagged' creates an incident and blocks traffic for 24 hours. + Type string `json:"type,omitempty"` //Type of alert (siteAlert, template, rateLimit, siteMetric) + SkipNotifications bool `json:"skipNotifications"` //A flag to disable external notifications - slack, webhooks, emails, etc. + FieldName string `json:"fieldName,omitempty"` + CreatedBy string `json:"createdBy,omitempty"` //The email of the user that created the alert + Created time.Time `json:"created,omitempty"` //RFC3339 date time + Operator string +} + +// customAlertsResponse is the response for the alerts endpoint +type customAlertsResponse struct { + Data []CustomAlert +} + +// ListCustomAlerts lists custom alerts for a given corp and site. +func (sc *Client) ListCustomAlerts(corpName, siteName string) ([]CustomAlert, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s/alerts", corpName, siteName), "") if err != nil { - return ResponseCustomAlertsBodyList{}, logError(1, fmt.Errorf("%s with %s %s ", err.Error(), corpName, siteName)) + return []CustomAlert{}, err } - var car ResponseCustomAlertsBodyList + var car customAlertsResponse err = json.Unmarshal(resp, &car) if err != nil { - return ResponseCustomAlertsBodyList{}, err + return []CustomAlert{}, err } - return car, nil + return car.Data, nil +} + +// CustomAlertBody is the body for creating a custom alert. +type CustomAlertBody struct { + TagName string `json:"tagName"` + LongName string `json:"longName"` + Interval int `json:"interval"` + Threshold int `json:"threshold"` + Enabled bool `json:"enabled"` + Action string `json:"action"` } -// CreateSiteCustomAlert creates a custom alert. -func (sc Client) CreateSiteCustomAlert(corpName, siteName string, body CreateCustomAlertBody) (ResponseCustomAlertBody, error) { +// CreateCustomAlert creates a custom alert. +func (sc *Client) CreateCustomAlert(corpName, siteName string, body CustomAlertBody) (CustomAlert, error) { b, err := json.Marshal(body) if err != nil { - return ResponseCustomAlertBody{}, err + return CustomAlert{}, err } resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/alerts", corpName, siteName), string(b)) if err != nil { - return ResponseCustomAlertBody{}, err + return CustomAlert{}, err } - var c ResponseCustomAlertBody + var c CustomAlert err = json.Unmarshal(resp, &c) if err != nil { - return ResponseCustomAlertBody{}, err + return CustomAlert{}, err } return c, nil } -// GetSiteCustomAlertByID gets a custom alert by ID -func (sc Client) GetSiteCustomAlertByID(corpName, siteName, id string) (ResponseCustomAlertBody, error) { +// GetCustomAlert gets a custom alert by ID +func (sc *Client) GetCustomAlert(corpName, siteName, id string) (CustomAlert, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s/alerts/%s", corpName, siteName, id), "") if err != nil { - return ResponseCustomAlertBody{}, err + return CustomAlert{}, err } - var ca ResponseCustomAlertBody + var ca CustomAlert err = json.Unmarshal(resp, &ca) if err != nil { - return ResponseCustomAlertBody{}, err + return CustomAlert{}, err } return ca, nil } -// UpdateSiteCustomAlertByID updates a custom alert by id. -func (sc Client) UpdateSiteCustomAlertByID(corpName, siteName, id string, body CreateCustomAlertBody) (ResponseCustomAlertBody, error) { +// UpdateCustomAlert updates a custom alert by id. +func (sc *Client) UpdateCustomAlert(corpName, siteName, id string, body CustomAlertBody) (CustomAlert, error) { b, err := json.Marshal(body) if err != nil { - return ResponseCustomAlertBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), string(b))) + return CustomAlert{}, err } resp, err := sc.doRequest("PATCH", fmt.Sprintf("/v0/corps/%s/sites/%s/alerts/%s", corpName, siteName, id), string(b)) if err != nil { - return ResponseCustomAlertBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return CustomAlert{}, err } - var c ResponseCustomAlertBody + var c CustomAlert err = json.Unmarshal(resp, &c) if err != nil { - return ResponseCustomAlertBody{}, err + return CustomAlert{}, err } return c, err } -// DeleteSiteCustomAlertByID deletes a custom alert. -func (sc Client) DeleteSiteCustomAlertByID(corpName, siteName, id string) error { +// DeleteCustomAlert deletes a custom alert. +func (sc *Client) DeleteCustomAlert(corpName, siteName, id string) error { _, err := sc.doRequest("DELETE", fmt.Sprintf("/v0/corps/%s/sites/%s/alerts/%s", corpName, siteName, id), "") return err @@ -1134,7 +1142,7 @@ func (sc *Client) GetIntegration(corpName, siteName, id string) (Integration, er // UpdateIntegrationBody is the body for updating an integration. type UpdateIntegrationBody struct { URL string `json:"url,omitempty"` - Events []string `json:"smallIconURI,omitempty"` + Events []string `json:"events,omitempty"` } // UpdateIntegration updates an integration by id. @@ -1155,6 +1163,61 @@ func (sc *Client) DeleteIntegration(corpName, siteName, id string) error { return err } +// AddCorpIntegration adds an integration. +func (sc *Client) AddCorpIntegration(corpName string, body IntegrationBody) (Integration, error) { + b, err := json.Marshal(body) + if err != nil { + return Integration{}, err + } + + resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/integrations", corpName), string(b)) + if err != nil { + return Integration{}, err + } + + var ir Integration + err = json.Unmarshal(resp, &ir) + if err != nil { + return Integration{}, err + } + + return ir, nil +} + +// GetCorpIntegration gets an integration by id. +func (sc *Client) GetCorpIntegration(corpName, id string) (Integration, error) { + resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/integrations/%s", corpName, id), "") + if err != nil { + return Integration{}, err + } + + var i Integration + err = json.Unmarshal(resp, &i) + if err != nil { + return Integration{}, err + } + + return i, nil +} + +// UpdateCorpIntegration updates an integration by id. +func (sc *Client) UpdateCorpIntegration(corpName, id string, body UpdateIntegrationBody) error { + b, err := json.Marshal(body) + if err != nil { + return err + } + + _, err = sc.doRequest("PATCH", fmt.Sprintf("/v0/corps/%s/integrations/%s", corpName, id), string(b)) + return err +} + +// DeleteCorpIntegration deletes a redaction by id. +func (sc *Client) DeleteCorpIntegration(corpName, id string) error { + _, err := sc.doRequest("DELETE", fmt.Sprintf("/v0/corps/%s/integrations/%s", corpName, id), "") + + return err +} + // Param is a whitelisted parameter. type Param struct { ID string @@ -1279,7 +1342,7 @@ func (sc *Client) AddHeaderLink(corpName, siteName string, body HeaderLinkBody) return []HeaderLink{}, err } - resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/pathwhitelist", corpName, siteName), string(b)) + resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/headerLinks", corpName, siteName), string(b)) if err != nil { return []HeaderLink{}, err } @@ -1456,9 +1519,30 @@ type SiteMonitor struct { Created time.Time } +// SiteMonitorResp is the response from GET site monitor +type SiteMonitorResp struct { + Data []SiteMonitor +} + // GetSiteMonitor gets the site monitor URL. -func (sc *Client) GetSiteMonitor(corpName, siteName, email string) (SiteMonitor, error) { +func (sc *Client) GetSiteMonitor(corpName, siteName, email string) ([]SiteMonitor, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s/monitors", corpName, siteName), "") + if err != nil { + return []SiteMonitor{}, err + } + + var s SiteMonitorResp + err = json.Unmarshal(resp, &s) + if err != nil { + return []SiteMonitor{}, err + } + + return s.Data, nil +} + +// GenerateSiteMonitor generates a site monitor URL. +func (sc *Client) GenerateSiteMonitor(corpName, siteName string) (SiteMonitor, error) { + resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/monitors", corpName, siteName), "") if err != nil { return SiteMonitor{}, err } @@ -1472,9 +1556,9 @@ func (sc *Client) GetSiteMonitor(corpName, siteName, email string) (SiteMonitor, return s, nil } -// GenerateSiteMonitor generates a site monitor URL. -func (sc *Client) GenerateSiteMonitor(corpName, siteName string) (SiteMonitor, error) { - resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/monitors", corpName, siteName), "") +// GenerateSiteMonitorDashboard generates a site monitor URL for a dashboard. +func (sc *Client) GenerateSiteMonitorDashboard(corpName, siteName, dashboard string) (SiteMonitor, error) { + resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/monitors?dashboardId=%s", corpName, siteName, dashboard), "") if err != nil { return SiteMonitor{}, err } @@ -1488,17 +1572,27 @@ func (sc *Client) GenerateSiteMonitor(corpName, siteName string) (SiteMonitor, e return s, nil } -// EnableSiteMonitor enables the site monitor URL for a given site. -func (sc *Client) EnableSiteMonitor(corpName, siteName string) error { - _, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/monitors/enable", corpName, siteName), "") +// UpdateSiteMonitorBody is the body to update a site monitor +type UpdateSiteMonitorBody struct { + ID string `json:"id"` + Share bool `json:"share"` +} + +// UpdateSiteMonitor updates a monitor in place +func (sc *Client) UpdateSiteMonitor(corpName, siteName, id string, body UpdateSiteMonitorBody) error { + b, err := json.Marshal(body) + if err != nil { + return err + } + + _, err = sc.doRequest("PUT", fmt.Sprintf("/v0/corps/%s/sites/%s/monitors/%s", corpName, siteName, id), string(b)) return err } -// DisableSiteMonitor disables the site monitor URL for a given site. -func (sc *Client) DisableSiteMonitor(corpName, siteName string) error { - _, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/monitors/disable", corpName, siteName), "") - +// DeleteSiteMonitor Deletes the site monitor URL for a given site. +func (sc *Client) DeleteSiteMonitor(corpName, siteName, id string) error { + _, err := sc.doRequest("DELETE", fmt.Sprintf("/v0/corps/%s/sites/%s/monitors/%s", corpName, siteName, id), "") return err } @@ -1730,40 +1824,40 @@ func (sc *Client) GetTimeseries(corpName, siteName string, query url.Values) ([] // CreateSiteBody is the structure required to create a Site. type CreateSiteBody struct { - Name string `json:"name,omitempty"` //Identifying name of the site - DisplayName string `json:"displayName,omitempty"` //Display name of the site - AgentLevel string `json:"agentLevel,omitempty"` //Agent action level - 'block', 'log' or 'off' - AgentAnonMode string `json:"agentAnonMode,omitempty"` //Agent IP anonimization mode - 'EU' or 'off' - BlockHTTPCode int `json:"blockHTTPCode,omitempty"` //HTTP response code to send when when traffic is being blocked - BlockDurationSeconds int `json:"blockDurationSeconds"` //Duration to block an IP in seconds + Name string `json:"name,omitempty"` //Identifying name of the site + DisplayName string `json:"displayName,omitempty"` //Display name of the site + AgentLevel string `json:"agentLevel,omitempty"` //Agent action level - 'block', 'log' or 'off' + AgentAnonMode string `json:"agentAnonMode,omitempty"` //Agent IP anonimization mode - 'EU' or '' + BlockHTTPCode int `json:"blockHTTPCode,omitempty"` //HTTP response code to send when when traffic is being blocked + BlockDurationSeconds int `json:"blockDurationSeconds,omitempty"` //Duration to block an IP in seconds } // CreateSite Creates a site in a corp. -func (sc Client) CreateSite(corpName string, body CreateSiteBody) (Site, error) { +func (sc *Client) CreateSite(corpName string, body CreateSiteBody) (Site, error) { b, err := json.Marshal(body) if err != nil { - return Site{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return Site{}, err } resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites", corpName), string(b)) if err != nil { - return Site{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return Site{}, err } var site Site err = json.Unmarshal(resp, &site) if err != nil { - return Site{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), resp)) + return Site{}, err } return site, nil } -// DeleteSite deltes the site -func (sc Client) DeleteSite(corpName, siteName string) error { +// DeleteSite deletes the site +func (sc *Client) DeleteSite(corpName, siteName string) error { _, err := sc.doRequest("DELETE", fmt.Sprintf("/v0/corps/%s/sites/%s", corpName, siteName), "") if err != nil { - return logError(1, fmt.Errorf("%s could not delete %s in %s ", err.Error(), corpName, siteName)) + return err } return nil } @@ -1780,19 +1874,28 @@ type Condition struct { // Action contains the rule action type Action struct { - Type string `json:"type,omitempty"` //(block, allow, exclude) + Type string `json:"type,omitempty"` //(block, allow, exclude) + Signal string `json:"signal,omitempty"` +} + +// RateLimit holds all the data that is specific to rate limit rules +type RateLimit struct { + Threshold int `json:"threshold"` + Interval int `json:"interval"` // interval in minutes, 1 or 10 + Duration int `json:"duration"` // duration in seconds } //CreateSiteRuleBody contains the rule for the site type CreateSiteRuleBody struct { - Type string `json:"type,omitempty,omitempty"` //(group, single) + Type string `json:"type,omitempty,omitempty"` //(signal, request, rateLimit) GroupOperator string `json:"groupOperator,omitempty"` //type: group - Conditions that must be matched when evaluating the request (all, any) Enabled bool `json:"enabled,omitempty"` Reason string `json:"reason,omitempty"` //Description of the rule - Signal string `json:"signal,omitempty"` //The signal id of the signal being excluded + Signal string `json:"signal,omitempty"` //The signal id of the signal being excluded. Null unless type==request Expiration string `json:"expiration,omitempty"` //Date the rule will automatically be disabled. If rule is always enabled, will return empty string Conditions []Condition `json:"conditions,omitempty"` Actions []Action `json:"actions,omitempty"` + RateLimit *RateLimit `json:"rateLimit,omitempty"` //Null unless type==rateLimit } // ResponseSiteRuleBody contains the response from creating the rule @@ -1814,42 +1917,42 @@ type ResponseSiteRuleBodyList struct { func (sc *Client) CreateSiteRule(corpName, siteName string, body CreateSiteRuleBody) (ResponseSiteRuleBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseSiteRuleBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseSiteRuleBody{}, err } resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/rules", corpName, siteName), string(b)) if err != nil { - return ResponseSiteRuleBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseSiteRuleBody{}, err } return getResponseSiteRuleBody(resp) } // UpdateSiteRuleByID updates a rule and returns a response -func (sc Client) UpdateSiteRuleByID(corpName, siteName, id string, body CreateSiteRuleBody) (ResponseSiteRuleBody, error) { +func (sc *Client) UpdateSiteRuleByID(corpName, siteName, id string, body CreateSiteRuleBody) (ResponseSiteRuleBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseSiteRuleBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseSiteRuleBody{}, err } resp, err := sc.doRequest("PUT", fmt.Sprintf("/v0/corps/%s/sites/%s/rules/%s", corpName, siteName, id), string(b)) if err != nil { - return ResponseSiteRuleBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseSiteRuleBody{}, err } return getResponseSiteRuleBody(resp) } // DeleteSiteRuleByID deletes a rule and returns an error -func (sc Client) DeleteSiteRuleByID(corpName, siteName, id string) error { +func (sc *Client) DeleteSiteRuleByID(corpName, siteName, id string) error { _, err := sc.doRequest("DELETE", fmt.Sprintf("/v0/corps/%s/sites/%s/rules/%s", corpName, siteName, id), "") if err != nil { - return logError(1, fmt.Errorf("%s could not delete %s in %s in %s", err.Error(), id, corpName, siteName)) + return err } return nil } //GetSiteRuleByID get a site rule by id -func (sc Client) GetSiteRuleByID(corpName, siteName, id string) (ResponseSiteRuleBody, error) { +func (sc *Client) GetSiteRuleByID(corpName, siteName, id string) (ResponseSiteRuleBody, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s/rules/%s", corpName, siteName, id), "") if err != nil { - return ResponseSiteRuleBody{}, logError(1, fmt.Errorf("%s could not get %s in %s in %s", err.Error(), id, siteName, corpName)) + return ResponseSiteRuleBody{}, err } return getResponseSiteRuleBody(resp) } @@ -1858,7 +1961,7 @@ func getResponseSiteRuleBody(response []byte) (ResponseSiteRuleBody, error) { var responseSiteRules ResponseSiteRuleBody err := json.Unmarshal(response, &responseSiteRules) if err != nil { - return ResponseSiteRuleBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), response)) + return ResponseSiteRuleBody{}, err } return responseSiteRules, nil } @@ -1868,7 +1971,7 @@ func (sc *Client) GetAllSiteRules(corpName, siteName string) (ResponseSiteRuleBo resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s/rules", corpName, siteName), "") if err != nil { - return ResponseSiteRuleBodyList{}, logError(1, fmt.Errorf("%s with %s %s ", err.Error(), corpName, siteName)) + return ResponseSiteRuleBodyList{}, err } var responseRulesList ResponseSiteRuleBodyList @@ -1883,7 +1986,7 @@ func (sc *Client) GetAllSiteRules(corpName, siteName string) (ResponseSiteRuleBo // CreateListBody Create List Request type CreateListBody struct { Name string `json:"name,omitempty"` //Descriptive list name - Type string `json:"type,omitempty"` //List types (string, ip, country, wildcard) + Type string `json:"type,omitempty"` //List types (string, ip, country, wildcard, signal) Description string `json:"description,omitempty"` //Optional list description Entries []string `json:"entries,omitempty"` //List entries } @@ -1916,14 +2019,14 @@ type ResponseListBodyList struct { } //CreateSiteList Create a site list -func (sc Client) CreateSiteList(corpName, siteName string, body CreateListBody) (ResponseListBody, error) { +func (sc *Client) CreateSiteList(corpName, siteName string, body CreateListBody) (ResponseListBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseListBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseListBody{}, err } resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/lists", corpName, siteName), string(b)) if err != nil { - return ResponseListBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseListBody{}, err } return getResponseListBody(resp) } @@ -1938,29 +2041,29 @@ func getResponseListBody(response []byte) (ResponseListBody, error) { } // UpdateSiteListByID updates a site list and returns a response -func (sc Client) UpdateSiteListByID(corpName, siteName string, id string, body UpdateListBody) (ResponseListBody, error) { +func (sc *Client) UpdateSiteListByID(corpName, siteName string, id string, body UpdateListBody) (ResponseListBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseListBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseListBody{}, err } resp, err := sc.doRequest("PATCH", fmt.Sprintf("/v0/corps/%s/sites/%s/lists/%s", corpName, siteName, id), string(b)) if err != nil { - return ResponseListBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseListBody{}, err } return getResponseListBody(resp) } // DeleteSiteListByID deletes a rule and returns an error -func (sc Client) DeleteSiteListByID(corpName, siteName string, id string) error { +func (sc *Client) DeleteSiteListByID(corpName, siteName string, id string) error { _, err := sc.doRequest("DELETE", fmt.Sprintf("/v0/corps/%s/sites/%s/lists/%s", corpName, siteName, id), "") if err != nil { - return logError(1, fmt.Errorf("%s could not delete %s in %s in %s", err.Error(), id, corpName, siteName)) + return err } return nil } // GetSiteListByID get site list by ID -func (sc Client) GetSiteListByID(corpName, siteName string, id string) (ResponseListBody, error) { +func (sc *Client) GetSiteListByID(corpName, siteName string, id string) (ResponseListBody, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s/lists/%s", corpName, siteName, id), "") if err != nil { return ResponseListBody{}, err @@ -1969,10 +2072,10 @@ func (sc Client) GetSiteListByID(corpName, siteName string, id string) (Response } //GetAllSiteLists get all site lists -func (sc Client) GetAllSiteLists(corpName, siteName string) (ResponseListBodyList, error) { +func (sc *Client) GetAllSiteLists(corpName, siteName string) (ResponseListBodyList, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s/lists", corpName, siteName), "") if err != nil { - return ResponseListBodyList{}, logError(1, fmt.Errorf("%s with %s %s ", err.Error(), corpName, siteName)) + return ResponseListBodyList{}, err } var responseListBodyList ResponseListBodyList err = json.Unmarshal(resp, &responseListBodyList) @@ -2007,14 +2110,14 @@ type ResponseSiteRedactionBodyList struct { } //CreateSiteRedaction Create a site list -func (sc Client) CreateSiteRedaction(corpName, siteName string, body CreateSiteRedactionBody) (ResponseSiteRedactionBody, error) { +func (sc *Client) CreateSiteRedaction(corpName, siteName string, body CreateSiteRedactionBody) (ResponseSiteRedactionBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseSiteRedactionBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseSiteRedactionBody{}, err } resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/redactions", corpName, siteName), string(b)) if err != nil { - return ResponseSiteRedactionBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseSiteRedactionBody{}, err } redactionsData, err := getResponseSiteRedactionListBody(resp) @@ -2044,7 +2147,7 @@ func getResponseSiteRedactionBody(response []byte) (ResponseSiteRedactionBody, e } //GetSiteRedactionByID get a site redaction by id -func (sc Client) GetSiteRedactionByID(corpName, siteName, id string) (ResponseSiteRedactionBody, error) { +func (sc *Client) GetSiteRedactionByID(corpName, siteName, id string) (ResponseSiteRedactionBody, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s/redactions/%s", corpName, siteName, id), "") if err != nil { return ResponseSiteRedactionBody{}, err @@ -2053,23 +2156,23 @@ func (sc Client) GetSiteRedactionByID(corpName, siteName, id string) (ResponseSi } // UpdateSiteRedactionByID updates a site redaction and returns a response -func (sc Client) UpdateSiteRedactionByID(corpName, siteName string, id string, body CreateSiteRedactionBody) (ResponseSiteRedactionBody, error) { +func (sc *Client) UpdateSiteRedactionByID(corpName, siteName string, id string, body CreateSiteRedactionBody) (ResponseSiteRedactionBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseSiteRedactionBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseSiteRedactionBody{}, err } resp, err := sc.doRequest("PATCH", fmt.Sprintf("/v0/corps/%s/sites/%s/redactions/%s", corpName, siteName, id), string(b)) if err != nil { - return ResponseSiteRedactionBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseSiteRedactionBody{}, err } return getResponseSiteRedactionBody(resp) } // DeleteSiteRedactionByID deletes a redaction and returns an error -func (sc Client) DeleteSiteRedactionByID(corpName, siteName string, id string) error { +func (sc *Client) DeleteSiteRedactionByID(corpName, siteName string, id string) error { _, err := sc.doRequest("DELETE", fmt.Sprintf("/v0/corps/%s/sites/%s/redactions/%s", corpName, siteName, id), "") if err != nil { - return logError(1, fmt.Errorf("%s could not delete %s in %s in %s", err.Error(), id, corpName, siteName)) + return err } return nil } @@ -2079,7 +2182,7 @@ func (sc *Client) GetAllSiteRedactions(corpName, siteName string) (ResponseSiteR resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s/redactions", corpName, siteName), "") if err != nil { - return ResponseSiteRedactionBodyList{}, logError(1, fmt.Errorf("%s with %s %s ", err.Error(), corpName, siteName)) + return ResponseSiteRedactionBodyList{}, err } var responseRulesList ResponseSiteRuleBodyList @@ -2094,7 +2197,7 @@ func (sc *Client) GetAllSiteRedactions(corpName, siteName string) (ResponseSiteR //CreateCorpRuleBody contains the rule of a Corp type CreateCorpRuleBody struct { SiteNames []string `json:"siteNames,omitempty"` //Sites with the rule available. Rules with a global corpScope will return '[]'. - Type string `json:"type,omitempty,omitempty"` //(group, single) + Type string `json:"type,omitempty,omitempty"` //(request, signal) CorpScope string `json:"corpScope,omitempty"` //Whether the rule is applied to all sites or to specific sites. (global, specificSites) Enabled bool `json:"enabled,omitempty"` GroupOperator string `json:"groupOperator,omitempty"` //type: group - Conditions that must be matched when evaluating the request (all, any) @@ -2124,29 +2227,29 @@ type ResponseCorpRuleBodyList struct { func (sc *Client) CreateCorpRule(corpName string, body CreateCorpRuleBody) (ResponseCorpRuleBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseCorpRuleBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseCorpRuleBody{}, err } resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/rules", corpName), string(b)) if err != nil { - return ResponseCorpRuleBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseCorpRuleBody{}, err } return getResponseCorpRuleBody(resp) } //GetCorpRuleByID get a site rule by id -func (sc Client) GetCorpRuleByID(corpName, id string) (ResponseCorpRuleBody, error) { +func (sc *Client) GetCorpRuleByID(corpName, id string) (ResponseCorpRuleBody, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/rules/%s", corpName, id), "") if err != nil { - return ResponseCorpRuleBody{}, logError(1, fmt.Errorf("%s could not get %s in %s", err.Error(), id, corpName)) + return ResponseCorpRuleBody{}, err } return getResponseCorpRuleBody(resp) } //GetAllCorpRules get all corp rules -func (sc Client) GetAllCorpRules(corpName string) (ResponseCorpRuleBodyList, error) { +func (sc *Client) GetAllCorpRules(corpName string) (ResponseCorpRuleBodyList, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/rules", corpName), "") if err != nil { - return ResponseCorpRuleBodyList{}, logError(1, fmt.Errorf("%s with %s", err.Error(), corpName)) + return ResponseCorpRuleBodyList{}, err } var responseRuleBodyList ResponseCorpRuleBodyList err = json.Unmarshal(resp, &responseRuleBodyList) @@ -2157,23 +2260,23 @@ func (sc Client) GetAllCorpRules(corpName string) (ResponseCorpRuleBodyList, err } // UpdateCorpRuleByID updates a rule and returns a response -func (sc Client) UpdateCorpRuleByID(corpName, id string, body CreateCorpRuleBody) (ResponseCorpRuleBody, error) { +func (sc *Client) UpdateCorpRuleByID(corpName, id string, body CreateCorpRuleBody) (ResponseCorpRuleBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseCorpRuleBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseCorpRuleBody{}, err } resp, err := sc.doRequest("PUT", fmt.Sprintf("/v0/corps/%s/rules/%s", corpName, id), string(b)) if err != nil { - return ResponseCorpRuleBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseCorpRuleBody{}, err } return getResponseCorpRuleBody(resp) } // DeleteCorpRuleByID deletes a rule and returns an error -func (sc Client) DeleteCorpRuleByID(corpName, id string) error { +func (sc *Client) DeleteCorpRuleByID(corpName, id string) error { _, err := sc.doRequest("DELETE", fmt.Sprintf("/v0/corps/%s/rules/%s", corpName, id), "") if err != nil { - return logError(1, fmt.Errorf("%s could not delete %s in %s", err.Error(), id, corpName)) + return err } return nil } @@ -2182,26 +2285,26 @@ func getResponseCorpRuleBody(response []byte) (ResponseCorpRuleBody, error) { var responseCorpRule ResponseCorpRuleBody err := json.Unmarshal(response, &responseCorpRule) if err != nil { - return ResponseCorpRuleBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), response)) + return ResponseCorpRuleBody{}, err } return responseCorpRule, nil } //CreateCorpList corp list -func (sc Client) CreateCorpList(corpName string, body CreateListBody) (ResponseListBody, error) { +func (sc *Client) CreateCorpList(corpName string, body CreateListBody) (ResponseListBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseListBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseListBody{}, err } resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/lists", corpName), string(b)) if err != nil { - return ResponseListBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseListBody{}, err } return getResponseListBody(resp) } // GetCorpListByID get corp list by ID -func (sc Client) GetCorpListByID(corpName string, id string) (ResponseListBody, error) { +func (sc *Client) GetCorpListByID(corpName string, id string) (ResponseListBody, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/lists/%s", corpName, id), "") if err != nil { return ResponseListBody{}, err @@ -2210,10 +2313,10 @@ func (sc Client) GetCorpListByID(corpName string, id string) (ResponseListBody, } //GetAllCorpLists get all corp lists -func (sc Client) GetAllCorpLists(corpName string) (ResponseListBodyList, error) { +func (sc *Client) GetAllCorpLists(corpName string) (ResponseListBodyList, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/lists", corpName), "") if err != nil { - return ResponseListBodyList{}, logError(1, fmt.Errorf("%s with %s", err.Error(), corpName)) + return ResponseListBodyList{}, err } var responseListBodyList ResponseListBodyList err = json.Unmarshal(resp, &responseListBodyList) @@ -2224,33 +2327,27 @@ func (sc Client) GetAllCorpLists(corpName string) (ResponseListBodyList, error) } // UpdateCorpListByID updates a corp list -func (sc Client) UpdateCorpListByID(corpName string, id string, body UpdateListBody) (ResponseListBody, error) { +func (sc *Client) UpdateCorpListByID(corpName string, id string, body UpdateListBody) (ResponseListBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseListBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseListBody{}, err } resp, err := sc.doRequest("PATCH", fmt.Sprintf("/v0/corps/%s/lists/%s", corpName, id), string(b)) if err != nil { - return ResponseListBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseListBody{}, err } return getResponseListBody(resp) } // DeleteCorpListByID deletes a rule and returns an error -func (sc Client) DeleteCorpListByID(corpName string, id string) error { +func (sc *Client) DeleteCorpListByID(corpName string, id string) error { _, err := sc.doRequest("DELETE", fmt.Sprintf("/v0/corps/%s/lists/%s", corpName, id), "") if err != nil { - return logError(1, fmt.Errorf("%s could not delete %s in %s", err.Error(), id, corpName)) + return err } return nil } -func logError(skip int, err error) error { - pc, _, line, _ := runtime.Caller(skip) - fn := runtime.FuncForPC(pc).Name() - return fmt.Errorf("[ERROR] %s:%d\t%s", fn, line, err.Error()) -} - //CreateSignalTagBody create a signal tag type CreateSignalTagBody struct { ShortName string `json:"shortName,omitempty"` //The display name of the signal tag @@ -2280,20 +2377,20 @@ type ResponseSignalTagBodyList struct { } //CreateCorpSignalTag create signal tag -func (sc Client) CreateCorpSignalTag(corpName string, body CreateSignalTagBody) (ResponseSignalTagBody, error) { +func (sc *Client) CreateCorpSignalTag(corpName string, body CreateSignalTagBody) (ResponseSignalTagBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseSignalTagBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseSignalTagBody{}, err } resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/tags", corpName), string(b)) if err != nil { - return ResponseSignalTagBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseSignalTagBody{}, err } return getResponseSignalTagBody(resp) } //GetCorpSignalTagByID get corp signal by id -func (sc Client) GetCorpSignalTagByID(corpName string, id string) (ResponseSignalTagBody, error) { +func (sc *Client) GetCorpSignalTagByID(corpName string, id string) (ResponseSignalTagBody, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/tags/%s", corpName, id), "") if err != nil { return ResponseSignalTagBody{}, err @@ -2302,10 +2399,10 @@ func (sc Client) GetCorpSignalTagByID(corpName string, id string) (ResponseSigna } //GetAllCorpSignalTags get all corp signals -func (sc Client) GetAllCorpSignalTags(corpName string) (ResponseSignalTagBodyList, error) { +func (sc *Client) GetAllCorpSignalTags(corpName string) (ResponseSignalTagBodyList, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/tags", corpName), "") if err != nil { - return ResponseSignalTagBodyList{}, logError(1, fmt.Errorf("%s with %s ", err.Error(), corpName)) + return ResponseSignalTagBodyList{}, err } var responseSignalTagBodyList ResponseSignalTagBodyList err = json.Unmarshal(resp, &responseSignalTagBodyList) @@ -2316,23 +2413,23 @@ func (sc Client) GetAllCorpSignalTags(corpName string) (ResponseSignalTagBodyLis } //UpdateCorpSignalTagByID update corp signal -func (sc Client) UpdateCorpSignalTagByID(corpName string, id string, body UpdateSignalTagBody) (ResponseSignalTagBody, error) { +func (sc *Client) UpdateCorpSignalTagByID(corpName string, id string, body UpdateSignalTagBody) (ResponseSignalTagBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseSignalTagBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseSignalTagBody{}, err } resp, err := sc.doRequest("PATCH", fmt.Sprintf("/v0/corps/%s/tags/%s", corpName, id), string(b)) if err != nil { - return ResponseSignalTagBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseSignalTagBody{}, err } return getResponseSignalTagBody(resp) } //DeleteCorpSignalTagByID delete signal tag by id -func (sc Client) DeleteCorpSignalTagByID(corpName string, id string) error { +func (sc *Client) DeleteCorpSignalTagByID(corpName string, id string) error { _, err := sc.doRequest("DELETE", fmt.Sprintf("/v0/corps/%s/tags/%s", corpName, id), "") if err != nil { - return logError(1, fmt.Errorf("%s could not delete %s in %s", err.Error(), id, corpName)) + return err } return nil } @@ -2346,20 +2443,20 @@ func getResponseSignalTagBody(response []byte) (ResponseSignalTagBody, error) { } //CreateSiteSignalTag create signal tag -func (sc Client) CreateSiteSignalTag(corpName, siteName string, body CreateSignalTagBody) (ResponseSignalTagBody, error) { +func (sc *Client) CreateSiteSignalTag(corpName, siteName string, body CreateSignalTagBody) (ResponseSignalTagBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseSignalTagBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseSignalTagBody{}, err } resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/tags", corpName, siteName), string(b)) if err != nil { - return ResponseSignalTagBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseSignalTagBody{}, err } return getResponseSignalTagBody(resp) } //GetSiteSignalTagByID get site signal by id -func (sc Client) GetSiteSignalTagByID(corpName, siteName, id string) (ResponseSignalTagBody, error) { +func (sc *Client) GetSiteSignalTagByID(corpName, siteName, id string) (ResponseSignalTagBody, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s/tags/%s", corpName, siteName, id), "") if err != nil { return ResponseSignalTagBody{}, err @@ -2368,10 +2465,10 @@ func (sc Client) GetSiteSignalTagByID(corpName, siteName, id string) (ResponseSi } //GetAllSiteSignalTags get all site signals -func (sc Client) GetAllSiteSignalTags(corpName, siteName string) (ResponseSignalTagBodyList, error) { +func (sc *Client) GetAllSiteSignalTags(corpName, siteName string) (ResponseSignalTagBodyList, error) { resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s/tags", corpName, siteName), "") if err != nil { - return ResponseSignalTagBodyList{}, logError(1, fmt.Errorf("%s with %s %s ", err.Error(), corpName, siteName)) + return ResponseSignalTagBodyList{}, err } var responseSignalTagBodyList ResponseSignalTagBodyList err = json.Unmarshal(resp, &responseSignalTagBodyList) @@ -2382,23 +2479,114 @@ func (sc Client) GetAllSiteSignalTags(corpName, siteName string) (ResponseSignal } //UpdateSiteSignalTagByID update site signal -func (sc Client) UpdateSiteSignalTagByID(corpName, siteName, id string, body UpdateSignalTagBody) (ResponseSignalTagBody, error) { +func (sc *Client) UpdateSiteSignalTagByID(corpName, siteName, id string, body UpdateSignalTagBody) (ResponseSignalTagBody, error) { b, err := json.Marshal(body) if err != nil { - return ResponseSignalTagBody{}, logError(1, fmt.Errorf("%s with input %#v", err.Error(), body)) + return ResponseSignalTagBody{}, err } resp, err := sc.doRequest("PATCH", fmt.Sprintf("/v0/corps/%s/sites/%s/tags/%s", corpName, siteName, id), string(b)) if err != nil { - return ResponseSignalTagBody{}, logError(1, fmt.Errorf("%s with input %v", err.Error(), string(b))) + return ResponseSignalTagBody{}, err } return getResponseSignalTagBody(resp) } //DeleteSiteSignalTagByID delete signal tag by id -func (sc Client) DeleteSiteSignalTagByID(corpName, siteName, id string) error { +func (sc *Client) DeleteSiteSignalTagByID(corpName, siteName, id string) error { _, err := sc.doRequest("DELETE", fmt.Sprintf("/v0/corps/%s/sites/%s/tags/%s", corpName, siteName, id), "") if err != nil { - return logError(1, fmt.Errorf("%s could not delete %s in %s in %s", err.Error(), id, corpName, siteName)) + return err } return nil } + +//ConfiguredDetectionField configuration for detection field in UpdateDetectionBody +type ConfiguredDetectionField struct { + Name string `json:"name,omitempty"` + Value interface{} `json:"value"` +} + +// DetectionUpdateBody body to update a detection +type DetectionUpdateBody struct { + ID string `json:"id,omitempty"` + Name string `json:"name"` // name of template + Enabled bool `json:"enabled"` + Fields []ConfiguredDetectionField `json:"fields"` +} + +//AlertUpdateBody body needed to update an alert +type AlertUpdateBody struct { + LongName string `json:"longName"` + Interval int `json:"interval"` // 1, 10 or 60 + Threshold int `json:"threshold"` // greater than 0, max 10000 + SkipNotifications bool `json:"skipNotifications,omitempty"` + Enabled bool `json:"enabled"` + Action string `json:"action"` +} + +// SiteTemplateRuleBody needed to update a site template rule +type SiteTemplateRuleBody struct { + DetectionAdds []Detection `json:"detectionAdds"` + DetectionUpdates []Detection `json:"detectionUpdates"` + DetectionDeletes []Detection `json:"detectionDeletes"` + + AlertAdds []Alert `json:"alertAdds"` + AlertUpdates []Alert `json:"alertUpdates"` + AlertDeletes []Alert `json:"alertDeletes"` +} + +//Detection basic struct for Detection +type Detection struct { + DetectionUpdateBody + Created *time.Time `json:"created,omitempty"` + CreatedBy string `json:"created_by,omitempty"` +} + +//Alert basic struct for an Alert +type Alert struct { + AlertUpdateBody + ID string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + TagName string `json:"tag_name,omitempty"` + FieldName string `json:"field_name,omitempty"` + Created *time.Time `json:"created,omitempty"` + CreatedBy string `json:"created_by,omitempty"` +} + +//SiteTemplate basic struct for a site template +type SiteTemplate struct { + Name string `json:"name,omitempty"` + Detections []Detection `json:"detections"` + Alerts []Alert `json:"alerts"` +} + +func getResponseSiteTemplateBody(response []byte) (SiteTemplate, error) { + var responseBody SiteTemplate + err := json.Unmarshal(response, &responseBody) + if err != nil { + return SiteTemplate{}, err + } + return responseBody, nil +} + +//UpdateSiteTemplateRuleByID updates a site template rule +func (sc *Client) UpdateSiteTemplateRuleByID(corpName, siteName, id string, body SiteTemplateRuleBody) (SiteTemplate, error) { + b, err := json.Marshal(body) + if err != nil { + return SiteTemplate{}, err + } + resp, err := sc.doRequest("POST", fmt.Sprintf("/v0/corps/%s/sites/%s/configuredtemplates/%s", corpName, siteName, id), string(b)) + if err != nil { + return SiteTemplate{}, err + } + return getResponseSiteTemplateBody(resp) +} + +//GetSiteTemplateRuleByID retrieves a site template rule +func (sc *Client) GetSiteTemplateRuleByID(corpName, siteName, id string) (SiteTemplate, error) { + resp, err := sc.doRequest("GET", fmt.Sprintf("/v0/corps/%s/sites/%s/configuredtemplates/%s", corpName, siteName, id), "") + if err != nil { + return SiteTemplate{}, err + } + return getResponseSiteTemplateBody(resp) +} diff --git a/api_test.go b/api_test.go index 8de6f1c..84862be 100644 --- a/api_test.go +++ b/api_test.go @@ -2,22 +2,26 @@ package sigsci import ( "encoding/json" + "fmt" "log" "os" + "reflect" "testing" "time" - - "github.com/stretchr/testify/assert" ) type TestCreds struct { email string token string + corp string + site string } var testcreds = TestCreds{ email: os.Getenv("SIGSCI_EMAIL"), - token: os.Getenv("SIGSCI_TOKEN"), //"6b62cee3-bd06-487e-9283-d565078b7a8f", + token: os.Getenv("SIGSCI_TOKEN"), + corp: os.Getenv("SIGSCI_CORP"), + site: os.Getenv("SIGSCI_SITE"), } func ExampleClient_InviteUser() { @@ -29,10 +33,10 @@ func ExampleClient_InviteUser() { } invite := NewCorpUserInvite(RoleCorpUser, []SiteMembership{ - NewSiteMembership("www.mysite.com", RoleSiteOwner), + NewSiteMembership(testcreds.site, RoleSiteOwner), }) - _, err = sc.InviteUser("testcorp", "test@test.net", invite) + _, err = sc.InviteUser(testcreds.corp, "test@test.net", invite) if err != nil { log.Fatal(err) } @@ -56,35 +60,97 @@ func TestGoUserTokenClient(t *testing.T) { if corps, err := sc.ListCorps(); err != nil { t.Fatal(err) } else { - assert.Equal(t, "splunk-testcorp", corps[0].Name) + if testcreds.corp != corps[0].Name { + t.Errorf("Corp ") + } } }) } } -func TestCreateDeleteSite(t *testing.T) { - t.Skip() +func TestCreateUpdateDeleteSite(t *testing.T) { sc := NewTokenClient(testcreds.email, testcreds.token) - corp := "splunk-testcorp" + corp := testcreds.corp siteBody := CreateSiteBody{ - Name: "janitha-test-site", - DisplayName: "Janitha Test Site", - AgentLevel: "Log", - BlockHTTPCode: 406, - BlockDurationSeconds: 86400, + Name: "test-site", + DisplayName: "Test Site", + AgentLevel: "block", + BlockHTTPCode: 406, // TODO test non-default value once api supports it + BlockDurationSeconds: 86400, // TODO test non-default value once api supports it AgentAnonMode: "", } siteresponse, err := sc.CreateSite(corp, siteBody) if err != nil { t.Fatal(err) } - assert.Equal(t, "Janitha Test Site", siteresponse.DisplayName) + if "Test Site" != siteresponse.DisplayName { + t.Errorf("Displayname got %s expected %s", siteresponse.DisplayName, "Test Site") + } + if "block" != siteresponse.AgentLevel { + t.Errorf("AgentLevel got %s expected %s", siteresponse.AgentLevel, "block") + } + if 406 != siteresponse.BlockHTTPCode { + t.Errorf("BlockHTTPCode got %d expected %d", siteresponse.BlockHTTPCode, 406) + } + if 86400 != siteresponse.BlockDurationSeconds { + t.Errorf("BlockDurationSeconds got %d expected %d", siteresponse.BlockDurationSeconds, 86400) + } + if "" != siteresponse.AgentAnonMode { + t.Errorf("AgentAnonMode got %s expected %s", siteresponse.AgentAnonMode, "") + } + + updateSite, err := sc.UpdateSite(corp, siteBody.Name, UpdateSiteBody{ + DisplayName: "Test Site 2", + AgentLevel: "off", + BlockDurationSeconds: 86402, + BlockHTTPCode: 406, // TODO increment this value once api supports it + AgentAnonMode: "EU", + }) + + if "Test Site 2" != updateSite.DisplayName { + t.Errorf("Displayname got %s expected %s", updateSite.DisplayName, "Test Site 2") + } + if "off" != updateSite.AgentLevel { + t.Errorf("AgentLevel got %s expected %s", updateSite.AgentLevel, "off") + } + if 406 != updateSite.BlockHTTPCode { + t.Errorf("BlockHTTPCode got %d expected %d", updateSite.BlockHTTPCode, 406) + } + if 86402 != updateSite.BlockDurationSeconds { + t.Errorf("BlockDurationSeconds got %d expected %d", updateSite.BlockDurationSeconds, 86402) + } + if "EU" != updateSite.AgentAnonMode { + t.Errorf("AgentAnonMode got %s expected %s", updateSite.AgentAnonMode, "EU") + } + err = sc.DeleteSite(corp, siteBody.Name) if err != nil { - t.Logf("%#v", err) + t.Errorf("%#v", err) } } +func compareSiteRuleBody(sr1, sr2 CreateSiteRuleBody) bool { + if sr1.Enabled != sr2.Enabled { + return false + } + if sr1.Reason != sr2.Reason { + return false + } + if sr1.Type != sr2.Type { + return false + } + if sr1.Signal != sr2.Signal { + return false + } + if sr1.Expiration != sr2.Expiration { + return false + } + if sr1.GroupOperator != sr2.GroupOperator { + return false + } + return true +} + func TestCreateReadUpdateDeleteSiteRules(t *testing.T) { createSiteRulesBody := CreateSiteRuleBody{ @@ -121,19 +187,23 @@ func TestCreateReadUpdateDeleteSiteRules(t *testing.T) { }, } sc := NewTokenClient(testcreds.email, testcreds.token) - corp := "splunk-tescorp" - site := "splunk-test" + corp := testcreds.corp + site := testcreds.site createResp, err := sc.CreateSiteRule(corp, site, createSiteRulesBody) if err != nil { t.Fatal(err) } - assert.Equal(t, createSiteRulesBody, createResp.CreateSiteRuleBody) + if !compareSiteRuleBody(createSiteRulesBody, createResp.CreateSiteRuleBody) { + t.Errorf("CreateSiteRulesgot: %v expected %v", createResp, createSiteRulesBody) + } readResp, err := sc.GetSiteRuleByID(corp, site, createResp.ID) if err != nil { t.Fatal(err) } - assert.Equal(t, createSiteRulesBody, readResp.CreateSiteRuleBody) + if !compareSiteRuleBody(createSiteRulesBody, readResp.CreateSiteRuleBody) { + t.Errorf("CreateSiteRulesgot: %v expected %v", createResp, createSiteRulesBody) + } updateSiteRuleBody := CreateSiteRuleBody{ Type: "signal", GroupOperator: "all", @@ -171,15 +241,23 @@ func TestCreateReadUpdateDeleteSiteRules(t *testing.T) { if err != nil { t.Fatal(err) } - assert.Equal(t, updateSiteRuleBody, updateResp.CreateSiteRuleBody) + if !compareSiteRuleBody(updateSiteRuleBody, updateResp.CreateSiteRuleBody) { + t.Errorf("CreateSiteRulesgot: %v expected %v", createResp, createSiteRulesBody) + } readall, err := sc.GetAllSiteRules(corp, site) if err != nil { t.Fatal(err) } - assert.Equal(t, 1, len(readall.Data)) - assert.Equal(t, 1, readall.TotalCount) - assert.Equal(t, updateSiteRuleBody, readall.Data[0].CreateSiteRuleBody) + if len(readall.Data) != 1 { + t.Error() + } + if readall.TotalCount != 1 { + t.Error() + } + if !compareSiteRuleBody(updateSiteRuleBody, readall.Data[0].CreateSiteRuleBody) { + + } err = sc.DeleteSiteRuleByID(corp, site, createResp.ID) if err != nil { @@ -188,13 +266,13 @@ func TestCreateReadUpdateDeleteSiteRules(t *testing.T) { } func TestUnMarshalListData(t *testing.T) { - resp := []byte(`{ + resp := []byte(fmt.Sprintf(`{ "totalCount": 1, "data": [ { "id": "5e84ec28bf612801c7f0f109", "siteNames": [ - "splunk-test" + "%s" ], "type": "signal", "enabled": true, @@ -215,33 +293,37 @@ func TestUnMarshalListData(t *testing.T) { "signal": "SQLI", "reason": "Example site rule", "expiration": "", - "createdBy": "janitha.jayaweera@gmail.com", + "createdBy": "test@gmail.com", "created": "2020-04-01T19:31:52Z", "updated": "2020-04-01T19:31:52Z" } ] - }`) + }`, testcreds.site)) var responseRulesList ResponseSiteRuleBodyList err := json.Unmarshal(resp, &responseRulesList) if err != nil { t.Fatal(err) } - assert.Equal(t, 1, responseRulesList.TotalCount) - assert.Equal(t, 1, len(responseRulesList.Data)) - assert.Equal(t, "5e84ec28bf612801c7f0f109", responseRulesList.Data[0].ID) + if responseRulesList.TotalCount != 1 { + t.Error() + } + if len(responseRulesList.Data) != 1 { + t.Error() + } + if responseRulesList.Data[0].ID != "5e84ec28bf612801c7f0f109" { + t.Error() + } } func TestDeleteAllSiteRules(t *testing.T) { - t.SkipNow() sc := NewTokenClient(testcreds.email, testcreds.token) - corp := "splunk-tescorp" - site := "splunk-test" + corp := testcreds.corp + site := testcreds.site respList, err := sc.GetAllSiteRules(corp, site) if err != nil { t.Fatal(err) } - // assert.Equal(t, 0, len(respList)) for _, rule := range respList.Data { sc.DeleteSiteRuleByID(corp, site, rule.ID) } @@ -249,13 +331,31 @@ func TestDeleteAllSiteRules(t *testing.T) { if err != nil { t.Fatal(err) } - assert.Equal(t, 0, len(respList.Data)) + if len(respList.Data) != 0 { + t.Error() + } +} + +func compareSiteListBody(sl1, sl2 CreateListBody) bool { + if sl1.Type != sl2.Type { + return false + } + if sl1.Description != sl2.Description { + return false + } + if sl1.Name != sl2.Name { + return false + } + if len(sl1.Entries) != len(sl2.Entries) { + return false + } + return true } func TestCreateReadUpdateDeleteSiteList(t *testing.T) { sc := NewTokenClient(testcreds.email, testcreds.token) - corp := "splunk-tescorp" - site := "splunk-test" + corp := testcreds.corp + site := testcreds.site createSiteListBody := CreateListBody{ Name: "My new list", Type: "ip", @@ -270,10 +370,14 @@ func TestCreateReadUpdateDeleteSiteList(t *testing.T) { if err != nil { t.Fatal(err) } - assert.Equal(t, createSiteListBody, createresp.CreateListBody) + if !reflect.DeepEqual(createSiteListBody, createresp.CreateListBody) { + t.Error("Site list body not equal after create") + } readresp, err := sc.GetSiteListByID(corp, site, createresp.ID) - assert.Equal(t, createSiteListBody, readresp.CreateListBody) + if !reflect.DeepEqual(createSiteListBody, readresp.CreateListBody) { + t.Error("Site list body not equal after read") + } updateSiteListBody := UpdateListBody{ Description: "Some IPs we are updating in the list", @@ -286,7 +390,7 @@ func TestCreateReadUpdateDeleteSiteList(t *testing.T) { if err != nil { t.Fatal(err) } - assert.NotEqual(t, createSiteListBody, updateresp.CreateListBody) + updatedSiteListBody := CreateListBody{ Name: "My new list", Type: "ip", @@ -297,10 +401,16 @@ func TestCreateReadUpdateDeleteSiteList(t *testing.T) { "3.4.5.6", }, } - assert.Equal(t, updatedSiteListBody, updateresp.CreateListBody) + if !reflect.DeepEqual(updatedSiteListBody, updateresp.CreateListBody) { + t.Error("Site list body not equal") + } readall, err := sc.GetAllSiteLists(corp, site) - assert.Equal(t, 1, len(readall.Data)) - assert.Equal(t, updatedSiteListBody, readall.Data[0].CreateListBody) + if len(readall.Data) != 1 { + t.Error() + } + if !reflect.DeepEqual(updatedSiteListBody, readall.Data[0].CreateListBody) { + t.Error("Site list body not equal") + } err = sc.DeleteSiteListByID(corp, site, readresp.ID) if err != nil { t.Fatal(err) @@ -309,8 +419,8 @@ func TestCreateReadUpdateDeleteSiteList(t *testing.T) { func TestCreateMultipleRedactions(t *testing.T) { sc := NewTokenClient(testcreds.email, testcreds.token) - corp := "splunk-tescorp" - site := "splunk-test" + corp := testcreds.corp + site := testcreds.site createSiteRedactionBody := CreateSiteRedactionBody{ Field: "privatefield", @@ -320,7 +430,9 @@ func TestCreateMultipleRedactions(t *testing.T) { if err != nil { t.Fatal(err) } - assert.Equal(t, createSiteRedactionBody, createresp.CreateSiteRedactionBody) + if !reflect.DeepEqual(createSiteRedactionBody, createresp.CreateSiteRedactionBody) { + t.Error("Site redaction body not equal after create") + } createSiteRedactionBody2 := CreateSiteRedactionBody{ Field: "cookie", @@ -330,7 +442,9 @@ func TestCreateMultipleRedactions(t *testing.T) { if err != nil { t.Fatal(err) } - assert.Equal(t, createSiteRedactionBody2, createresp2.CreateSiteRedactionBody) + if !reflect.DeepEqual(createSiteRedactionBody2, createresp2.CreateSiteRedactionBody) { + t.Error("Site redaction body not equal after create") + } createSiteRedactionBody3 := CreateSiteRedactionBody{ Field: "cookie", @@ -340,7 +454,9 @@ func TestCreateMultipleRedactions(t *testing.T) { if err != nil { t.Fatal(err) } - assert.Equal(t, createSiteRedactionBody3, createresp3.CreateSiteRedactionBody) + if !reflect.DeepEqual(createSiteRedactionBody3, createresp3.CreateSiteRedactionBody) { + t.Error("Site redaction body not equal after create") + } err = sc.DeleteSiteRedactionByID(corp, site, createresp.ID) if err != nil { @@ -357,8 +473,8 @@ func TestCreateMultipleRedactions(t *testing.T) { } func TestCreateListUpdateDeleteRedaction(t *testing.T) { sc := NewTokenClient(testcreds.email, testcreds.token) - corp := "splunk-tescorp" - site := "splunk-test" + corp := testcreds.corp + site := testcreds.site createSiteRedactionBody := CreateSiteRedactionBody{ Field: "privatefield", @@ -370,10 +486,14 @@ func TestCreateListUpdateDeleteRedaction(t *testing.T) { t.Fatal(err) } - assert.Equal(t, createSiteRedactionBody, createresp.CreateSiteRedactionBody) + if !reflect.DeepEqual(createSiteRedactionBody, createresp.CreateSiteRedactionBody) { + t.Error("Site redaction body not equal after create") + } readresp, err := sc.GetSiteRedactionByID(corp, site, createresp.ID) - assert.Equal(t, createSiteRedactionBody, readresp.CreateSiteRedactionBody) + if !reflect.DeepEqual(createSiteRedactionBody, readresp.CreateSiteRedactionBody) { + t.Error("Site redaction body not equal after read") + } updateSiteRedactionBody := CreateSiteRedactionBody{ Field: "cookie", @@ -383,12 +503,16 @@ func TestCreateListUpdateDeleteRedaction(t *testing.T) { if err != nil { t.Fatal(err) } - assert.NotEqual(t, createSiteRedactionBody, updatedresp.CreateSiteRedactionBody) - assert.Equal(t, updateSiteRedactionBody, updatedresp.CreateSiteRedactionBody) + if !reflect.DeepEqual(updateSiteRedactionBody, updatedresp.CreateSiteRedactionBody) { + t.Error("Site redaction body not equal after update") + } readall, err := sc.GetAllSiteRedactions(corp, site) - assert.Equal(t, 1, len(readall.Data)) - // assert.Equal(t, 1, readall.TotalCount) - assert.Equal(t, updateSiteRedactionBody, readall.Data[0].CreateSiteRedactionBody) + if len(readall.Data) != 1 { + t.Error("incorrect number of site redactions, make sure you didnt add any manually") + } + if !reflect.DeepEqual(updateSiteRedactionBody, readall.Data[0].CreateSiteRedactionBody) { + t.Error("Site redaction body not equal after update") + } err = sc.DeleteSiteRedactionByID(corp, site, createresp.ID) if err != nil { t.Fatal(err) @@ -397,62 +521,140 @@ func TestCreateListUpdateDeleteRedaction(t *testing.T) { func TestSiteCreateReadUpdateDeleteAlerts(t *testing.T) { sc := NewTokenClient(testcreds.email, testcreds.token) - corp := "splunk-tescorp" - site := "splunk-test" + corp := testcreds.corp + site := testcreds.site - createCustomAlert := CreateCustomAlertBody{ - TagName: "SQLI", - LongName: "Example Alert", - BlockDurationSeconds: 1, - Interval: 1, - Threshold: 10, - Enabled: true, - Action: "flagged", - } - createresp, err := sc.CreateSiteCustomAlert(corp, site, createCustomAlert) - // t.Logf("%#v", createresp.Data) + createCustomAlert := CustomAlertBody{ + TagName: "SQLI", + LongName: "Example Alert", + Interval: 1, + Threshold: 10, + Enabled: true, + Action: "flagged", + } + createresp, err := sc.CreateCustomAlert(corp, site, createCustomAlert) if err != nil { t.Fatal(err) } - assert.Equal(t, createCustomAlert, createresp.CreateCustomAlertBody) - readresp, err := sc.GetSiteCustomAlertByID(corp, site, createresp.ID) + // set unknown fields just for equality + if createCustomAlert.TagName != createresp.TagName { + t.Error("tag names not equal") + } + if createCustomAlert.LongName != createresp.LongName { + t.Error("tag names not equal") + } + if createCustomAlert.Interval != createresp.Interval { + t.Error("tag names not equal") + } + if createCustomAlert.Threshold != createresp.Threshold { + t.Error("tag names not equal") + } + if createCustomAlert.Enabled != createresp.Enabled { + t.Error("tag names not equal") + } + if createCustomAlert.Action != createresp.Action { + t.Error("tag names not equal") + } + + readresp, err := sc.GetCustomAlert(corp, site, createresp.ID) if err != nil { t.Fatal(err) } - assert.Equal(t, createCustomAlert, readresp.CreateCustomAlertBody) - - updateCustomAlert := CreateCustomAlertBody{ - TagName: "SQLI", - LongName: "Example Alert Updated", - BlockDurationSeconds: 1, - Interval: 10, - Threshold: 10, - Enabled: true, - Action: "flagged", + if createCustomAlert.TagName != readresp.TagName { + t.Error("tag names not equal") + } + if createCustomAlert.LongName != readresp.LongName { + t.Error("tag names not equal") + } + if createCustomAlert.Interval != readresp.Interval { + t.Error("tag names not equal") + } + if createCustomAlert.Threshold != readresp.Threshold { + t.Error("tag names not equal") } - updateresp, err := sc.UpdateSiteCustomAlertByID(corp, site, readresp.ID, updateCustomAlert) + if createCustomAlert.Enabled != readresp.Enabled { + t.Error("tag names not equal") + } + if createCustomAlert.Action != readresp.Action { + t.Error("tag names not equal") + } + + updateCustomAlert := CustomAlertBody{ + TagName: "SQLI", + LongName: "Example Alert Updated", + Interval: 10, + Threshold: 10, + Enabled: true, + Action: "flagged", + } + updateResp, err := sc.UpdateCustomAlert(corp, site, readresp.ID, updateCustomAlert) + if err != nil { t.Fatal(err) } - // t.Logf("%#v", updateresp) - assert.NotEqual(t, createCustomAlert, updateresp.CreateCustomAlertBody) - assert.Equal(t, updateCustomAlert, updateresp.CreateCustomAlertBody) - allalerts, err := sc.GetAllSiteCustomAlerts(corp, site) + + if updateCustomAlert.TagName != updateResp.TagName { + t.Error("tag names not equal") + } + if updateCustomAlert.LongName != updateResp.LongName { + t.Error("tag names not equal") + } + if updateCustomAlert.Interval != updateResp.Interval { + t.Error("tag names not equal") + } + if updateCustomAlert.Threshold != updateResp.Threshold { + t.Error("tag names not equal") + } + if updateCustomAlert.Enabled != updateResp.Enabled { + t.Error("tag names not equal") + } + if updateCustomAlert.Action != updateResp.Action { + t.Error("tag names not equal") + } + + allalerts, err := sc.ListCustomAlerts(corp, site) if err != nil { t.Fatal(err) } - assert.Equal(t, 1, len(allalerts.Data)) - assert.Equal(t, updateCustomAlert, allalerts.Data[0].CreateCustomAlertBody) - // for _, createresp := range allalerts.Data { - err = sc.DeleteSiteCustomAlertByID(corp, site, createresp.ID) + if len(allalerts) != 1 { + t.Error("alerts length incorrect. make sure none we added outside") + } + if updateCustomAlert.TagName != allalerts[0].TagName { + t.Error("tag names not equal") + } + if updateCustomAlert.LongName != allalerts[0].LongName { + t.Error("long names not equal") + } + if updateCustomAlert.Interval != allalerts[0].Interval { + t.Error("interval not equal") + } + if updateCustomAlert.Threshold != allalerts[0].Threshold { + t.Error("threshold not equal") + } + if updateCustomAlert.Enabled != allalerts[0].Enabled { + t.Error("enbled not equal") + } + if updateCustomAlert.Action != allalerts[0].Action { + t.Error("action not equal") + } + + err = sc.DeleteCustomAlert(corp, site, createresp.ID) if err != nil { t.Fatal(err) } - // } } func TestCreateReadUpdateDeleteCorpRule(t *testing.T) { + + sc := NewTokenClient(testcreds.email, testcreds.token) + corp := testcreds.corp + // Get initial counts + initialCorps, err := sc.GetAllCorpRules(corp) + if err != nil { + t.Fatal(err) + } + createCorpRuleBody := CreateCorpRuleBody{ - SiteNames: []string{"splunk-test"}, + SiteNames: []string{testcreds.site}, Type: "signal", GroupOperator: "all", Conditions: []Condition{ @@ -486,22 +688,23 @@ func TestCreateReadUpdateDeleteCorpRule(t *testing.T) { Expiration: "", CorpScope: "specificSites", } - sc := NewTokenClient(testcreds.email, testcreds.token) - corp := "splunk-tescorp" createResp, err := sc.CreateCorpRule(corp, createCorpRuleBody) if err != nil { t.Fatal(err) } - // t.Logf("%#v", createResp.CreateCorpRuleBody) - assert.Equal(t, createCorpRuleBody, createResp.CreateCorpRuleBody) + if !reflect.DeepEqual(createCorpRuleBody, createResp.CreateCorpRuleBody) { + t.Error("Corp rule body not equal after create") + } readResp, err := sc.GetCorpRuleByID(corp, createResp.ID) if err != nil { t.Fatal(err) } - assert.Equal(t, readResp, createResp) + if !reflect.DeepEqual(readResp, createResp) { + t.Error("Corp rule body not equal after read") + } updateCorpRuleBody := CreateCorpRuleBody{ - SiteNames: []string{"splunk-test"}, + SiteNames: []string{testcreds.site}, Type: "signal", GroupOperator: "all", Conditions: []Condition{ @@ -539,24 +742,58 @@ func TestCreateReadUpdateDeleteCorpRule(t *testing.T) { if err != nil { t.Fatal(err) } - assert.Equal(t, updateCorpRuleBody, updateResp.CreateCorpRuleBody) + if !reflect.DeepEqual(updateCorpRuleBody, updateResp.CreateCorpRuleBody) { + t.Error("Corp rule body not equal after update") + } readall, err := sc.GetAllCorpRules(corp) if err != nil { t.Fatal(err) } - assert.Equal(t, 1, len(readall.Data)) - assert.Equal(t, 1, readall.TotalCount) - assert.Equal(t, updateCorpRuleBody, readall.Data[0].CreateCorpRuleBody) + if len(initialCorps.Data)+1 != len(readall.Data) { + t.Error() + } + if initialCorps.TotalCount+1 != readall.TotalCount { + t.Error() + } + if !reflect.DeepEqual(updateCorpRuleBody, readall.Data[0].CreateCorpRuleBody) { + t.Error("Corp rule body not equal after get all. make sure nothing was added externally") + } err = sc.DeleteCorpRuleByID(corp, createResp.ID) if err != nil { t.Fatal(err) } + readall, err = sc.GetAllCorpRules(corp) + if err != nil { + t.Fatal(err) + } + if len(initialCorps.Data) != len(readall.Data) { + t.Error() + } + if initialCorps.TotalCount != readall.TotalCount { + t.Error() + } +} + +func compareCorpListBody(cl1, cl2 CreateListBody) bool { + if cl1.Name != cl2.Name { + return false + } + if cl1.Type != cl2.Type { + return false + } + if cl1.Description != cl2.Description { + return false + } + if len(cl1.Entries) != len(cl2.Entries) { + return false + } + return true } func TestCreateReadUpdateDeleteCorpList(t *testing.T) { sc := NewTokenClient(testcreds.email, testcreds.token) - corp := "splunk-tescorp" + corp := testcreds.corp createCorpListBody := CreateListBody{ Name: "My new List", Type: "ip", @@ -571,7 +808,10 @@ func TestCreateReadUpdateDeleteCorpList(t *testing.T) { if err != nil { t.Fatal(err) } - assert.Equal(t, createCorpListBody, createresp.CreateListBody) + if !compareCorpListBody(createCorpListBody, createresp.CreateListBody) { + t.Error("corp list not equal after create") + } + now := time.Now() expectedCreateResponse := ResponseListBody{ CreateListBody: CreateListBody{ Name: "My new List", @@ -585,19 +825,23 @@ func TestCreateReadUpdateDeleteCorpList(t *testing.T) { }, ID: "corp.my-new-list", CreatedBy: "", - Created: time.Time{}, //wall: 0x0, ext: 63725163294, loc: (*time.Location)(nil)}, - Updated: time.Time{}, //wall: 0x0, ext: 63725163294, loc: (*time.Location)(nil)}, + Created: now, + Updated: now, } - createresp.Created = time.Time{} - createresp.Updated = time.Time{} + createresp.Created = now + createresp.Updated = now createresp.CreatedBy = "" - assert.Equal(t, expectedCreateResponse, createresp) + if !reflect.DeepEqual(expectedCreateResponse, createresp) { + t.Error("corp list not equal after get") + } readresp, err := sc.GetCorpListByID(corp, createresp.ID) if err != nil { t.Fatal(err) } - assert.Equal(t, createCorpListBody, readresp.CreateListBody) + if !compareCorpListBody(createCorpListBody, readresp.CreateListBody) { + t.Error("corp list not equal after read") + } updateCorpListBody := UpdateListBody{ Description: "Some IPs we are updating in the list", @@ -608,9 +852,24 @@ func TestCreateReadUpdateDeleteCorpList(t *testing.T) { } updateresp, err := sc.UpdateCorpListByID(corp, readresp.ID, updateCorpListBody) if err != nil { - t.Fatal(err) + t.Error(err) + } + + if updateCorpListBody.Description != updateresp.Description { + t.Error("descriptions not equal after update") + } + hasNewEntry := false + for _, e := range updateresp.Entries { + if e == "4.5.6.7" { + t.Fail() + } + if e == "3.4.5.6" { + hasNewEntry = true + } + } + if !hasNewEntry { + t.Error() } - assert.NotEqual(t, createCorpListBody, updateresp.CreateListBody) updatedCorpListBody := CreateListBody{ Name: "My new List", Type: "ip", @@ -621,13 +880,19 @@ func TestCreateReadUpdateDeleteCorpList(t *testing.T) { "3.4.5.6", }, } - assert.Equal(t, updatedCorpListBody, updateresp.CreateListBody) + if !compareCorpListBody(updatedCorpListBody, updateresp.CreateListBody) { + t.Error("corp list not equal after update") + } readall, err := sc.GetAllCorpLists(corp) if err != nil { t.Fatal(err) } - assert.Equal(t, 1, len(readall.Data)) - assert.Equal(t, updatedCorpListBody, readall.Data[0].CreateListBody) + if len(readall.Data) != 1 { + t.Error() + } + if !compareCorpListBody(updatedCorpListBody, readall.Data[0].CreateListBody) { + t.Error("corp list not equal after update") + } err = sc.DeleteCorpListByID(corp, readresp.ID) if err != nil { t.Fatal(err) @@ -636,7 +901,7 @@ func TestCreateReadUpdateDeleteCorpList(t *testing.T) { func TestCreateReadUpdateDeleteCorpTag(t *testing.T) { sc := NewTokenClient(testcreds.email, testcreds.token) - corp := "splunk-tescorp" + corp := testcreds.corp createSignalTagBody := CreateSignalTagBody{ ShortName: "Example Signal Tag 1", Description: "An example of a custom signal tag", @@ -645,7 +910,9 @@ func TestCreateReadUpdateDeleteCorpTag(t *testing.T) { if err != nil { t.Fatal(err) } - assert.Equal(t, createSignalTagBody, createresp.CreateSignalTagBody) + if !reflect.DeepEqual(createSignalTagBody, createresp.CreateSignalTagBody) { + t.Fatal() + } expectedCreateResponse := ResponseSignalTagBody{ CreateSignalTagBody: CreateSignalTagBody{ ShortName: "Example Signal Tag 1", @@ -661,12 +928,16 @@ func TestCreateReadUpdateDeleteCorpTag(t *testing.T) { } createresp.Created = time.Time{} createresp.CreatedBy = "" - assert.Equal(t, expectedCreateResponse, createresp) + if !reflect.DeepEqual(expectedCreateResponse, createresp) { + t.Fail() + } readresp, err := sc.GetCorpSignalTagByID(corp, createresp.TagName) if err != nil { t.Fatal(err) } - assert.Equal(t, createSignalTagBody, readresp.CreateSignalTagBody) + if !reflect.DeepEqual(createSignalTagBody, readresp.CreateSignalTagBody) { + t.Fail() + } updateSignalTagBody := UpdateSignalTagBody{ Description: "An example of a custom signal tag - UPDATE", } @@ -678,13 +949,19 @@ func TestCreateReadUpdateDeleteCorpTag(t *testing.T) { ShortName: "Example Signal Tag 1", Description: "An example of a custom signal tag - UPDATE", } - assert.Equal(t, updatedSignalTagBody, updateresp.CreateSignalTagBody) + if !reflect.DeepEqual(updatedSignalTagBody, updateresp.CreateSignalTagBody) { + t.Fail() + } readall, err := sc.GetAllCorpSignalTags(corp) if err != nil { t.Fatal(err) } - assert.Equal(t, 1, len(readall.Data)) - assert.Equal(t, updatedSignalTagBody, readall.Data[0].CreateSignalTagBody) + if len(readall.Data) != 1 { + t.Fail() + } + if !reflect.DeepEqual(updatedSignalTagBody, readall.Data[0].CreateSignalTagBody) { + t.Fail() + } err = sc.DeleteCorpSignalTagByID(corp, readresp.TagName) if err != nil { t.Fatal(err) @@ -693,8 +970,8 @@ func TestCreateReadUpdateDeleteCorpTag(t *testing.T) { func TestCreateReadUpdateDeleteSignalTag(t *testing.T) { sc := NewTokenClient(testcreds.email, testcreds.token) - corp := "splunk-tescorp" - site := "splunk-test" + corp := testcreds.corp + site := testcreds.site createSignalTagBody := CreateSignalTagBody{ ShortName: "example-signal-tag", Description: "An example of a custom signal tag", @@ -707,7 +984,9 @@ func TestCreateReadUpdateDeleteSignalTag(t *testing.T) { if err != nil { t.Fatal(err) } - assert.Equal(t, createSignalTagBody, readresp.CreateSignalTagBody) + if !reflect.DeepEqual(createSignalTagBody, readresp.CreateSignalTagBody) { + t.Fail() + } updateSignalTagBody := UpdateSignalTagBody{ Description: "An example of a custom signal tag - UPDATE", } @@ -719,15 +998,264 @@ func TestCreateReadUpdateDeleteSignalTag(t *testing.T) { ShortName: "example-signal-tag", Description: "An example of a custom signal tag - UPDATE", } - assert.Equal(t, updatedSignalTagBody, updateresp.CreateSignalTagBody) + if !reflect.DeepEqual(updatedSignalTagBody, updateresp.CreateSignalTagBody) { + t.Fail() + } readall, err := sc.GetAllSiteSignalTags(corp, site) if err != nil { t.Fatal(err) } - assert.Equal(t, 1, len(readall.Data)) - assert.Equal(t, updatedSignalTagBody, readall.Data[0].CreateSignalTagBody) + if len(readall.Data) != 1 { + t.Fail() + } + if !reflect.DeepEqual(updatedSignalTagBody, readall.Data[0].CreateSignalTagBody) { + t.Fail() + } err = sc.DeleteSiteSignalTagByID(corp, site, readresp.TagName) if err != nil { t.Fatal(err) } } + +func TestCreateReadUpdateDeleteSiteTemplate(t *testing.T) { + sc := NewTokenClient(testcreds.email, testcreds.token) + corp := testcreds.corp + site := testcreds.site + createresp, err := sc.UpdateSiteTemplateRuleByID(corp, site, "LOGINATTEMPT", SiteTemplateRuleBody{ + DetectionAdds: []Detection{ + { + DetectionUpdateBody: DetectionUpdateBody{ + Name: "path", + Enabled: true, + Fields: []ConfiguredDetectionField{ + { + Name: "path", + Value: "/auth/*", + }, + }, + }, + }, + }, + DetectionUpdates: []Detection{}, + DetectionDeletes: []Detection{}, + AlertAdds: []Alert{ + { + AlertUpdateBody: AlertUpdateBody{ + LongName: "LOGINATTEMPT-50-in-1", + Interval: 1, + Threshold: 50, + SkipNotifications: true, + Enabled: true, + Action: "info", + }}, + }, + AlertUpdates: []Alert{}, + AlertDeletes: []Alert{}, + }) + if err != nil { + t.Fatal(err) + } + readresp, err := sc.GetSiteTemplateRuleByID(corp, site, createresp.Name) + if err != nil { + t.Fatal(err) + } + + fmt.Println(createresp) + fmt.Println(readresp) +} + +func TestCRUDCorpIntegrations(t *testing.T) { + sc := NewTokenClient(testcreds.email, testcreds.token) + corp := testcreds.corp + + url := "https://www.signalsciences.com" + + createResp, err := sc.AddCorpIntegration(corp, IntegrationBody{ + URL: url, + Type: "slack", + Events: []string{"webhookEvents"}, + }) + if err != nil { + t.Fatal(err) + } + + readResp, err := sc.GetCorpIntegration(corp, createResp.ID) + if err != nil { + t.Fatal(err) + } + if createResp.ID != readResp.ID { + t.Fail() + } + if createResp.URL != readResp.URL { + t.Fail() + } + if createResp.Type != readResp.Type { + t.Fail() + } + if !reflect.DeepEqual([]string{"webhookEvents"}, readResp.Events) { + t.Fail() + } + + newURL := url + "/blah" + err = sc.UpdateCorpIntegration(corp, readResp.ID, UpdateIntegrationBody{ + URL: newURL, + Events: []string{"corpUpdated", "listDeleted"}, + }) + if err != nil { + t.Fatal(err) + } + readResp2, err := sc.GetCorpIntegration(corp, createResp.ID) + if err != nil { + t.Fatal(err) + } + if newURL != readResp2.URL { + t.Fail() + } + if !reflect.DeepEqual([]string{"corpUpdated", "listDeleted"}, readResp2.Events) { + t.Fail() + } + + err = sc.DeleteCorpIntegration(corp, readResp2.ID) + if err != nil { + t.Fatal(err) + } +} + +func TestCRUDSiteMonitorDashboard(t *testing.T) { + sc := NewTokenClient(testcreds.email, testcreds.token) + corp := testcreds.corp + site := testcreds.site + + createResp, err := sc.GenerateSiteMonitorDashboard(corp, site, "000000000000000000000001") + if err != nil { + t.Fatal(err) + } + + monitors, err := sc.GetSiteMonitor(corp, site, createResp.ID) + if err != nil { + t.Fatal(err) + } + var monitor SiteMonitor + for _, m := range monitors { + if m.ID == createResp.ID { + monitor = m + } + } + if monitor.ID == "" { + t.Fatal("couldnt find newly created site monitor") + } + if createResp.ID != monitor.ID { + t.Fail() + } + if createResp.URL != monitor.URL { + t.Fail() + } + if createResp.Share != monitor.Share { + t.Fail() + } + + err = sc.UpdateSiteMonitor(corp, site, createResp.ID, UpdateSiteMonitorBody{ + ID: createResp.ID, + Share: false, + }) + if err != nil { + t.Fatal(err) + } + monitors2, err := sc.GetSiteMonitor(corp, site, createResp.ID) + if err != nil { + t.Fatal(err) + } + var monitor2 SiteMonitor + for _, m := range monitors2 { + if m.ID == createResp.ID { + monitor2 = m + } + } + if monitor2.ID == "" { + t.Fatal("couldnt find newly created site monitor") + } + + if createResp.ID != monitor2.ID { + t.Fail() + } + if createResp.URL != monitor2.URL { + t.Fail() + } + if monitor2.Share != false { + t.Fail() + } + + err = sc.DeleteSiteMonitor(corp, site, createResp.ID) + if err != nil { + t.Fatal(err) + } +} + +func TestCRUDSiteMonitor(t *testing.T) { + sc := NewTokenClient(testcreds.email, testcreds.token) + corp := testcreds.corp + site := testcreds.site + + createResp, err := sc.GenerateSiteMonitor(corp, site) + if err != nil { + t.Fatal(err) + } + + monitors, err := sc.GetSiteMonitor(corp, site, createResp.ID) + if err != nil { + t.Fatal(err) + } + var monitor SiteMonitor + for _, m := range monitors { + if m.ID == createResp.ID { + monitor = m + } + } + if monitor.ID == "" { + t.Fatal("couldnt find newly created site monitor") + } + if createResp.ID != monitor.ID { + t.Fail() + } + if createResp.URL != monitor.URL { + t.Fail() + } + if createResp.Share != monitor.Share { + t.Fail() + } + + err = sc.UpdateSiteMonitor(corp, site, createResp.ID, UpdateSiteMonitorBody{ + ID: createResp.ID, + Share: false, + }) + if err != nil { + t.Fatal(err) + } + monitors2, err := sc.GetSiteMonitor(corp, site, createResp.ID) + if err != nil { + t.Fatal(err) + } + var monitor2 SiteMonitor + for _, m := range monitors2 { + if m.ID == createResp.ID { + monitor2 = m + } + } + if monitor2.ID == "" { + t.Fatal("couldnt find newly created site monitor") + } + if createResp.ID != monitor2.ID { + t.Fail() + } + if createResp.URL != monitor2.URL { + t.Fail() + } + if monitor2.Share != false { + t.Fail() + } + + err = sc.DeleteSiteMonitor(corp, site, createResp.ID) + if err != nil { + t.Fatal(err) + } +} diff --git a/go.mod b/go.mod index 6b279d5..abebda9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/signalsciences/go-sigsci -go 1.12 +go 1.14 require ( github.com/stretchr/testify v1.5.1