Apiclient tests (#484)
Co-authored-by: AlteredCoder Co-authored-by: erenJag
This commit is contained in:
parent
000fec27df
commit
71ac0d2fce
28 changed files with 1385 additions and 74 deletions
|
@ -1,30 +0,0 @@
|
|||
# Contributing
|
||||
|
||||
You have an idea, a suggestion or you spotted a mistake ?
|
||||
Help us improve the software and the user experience, to make the internet a safer place together !
|
||||
|
||||
|
||||
|
||||
## Contributing to the documentation
|
||||
|
||||
If you spotted some mistakes in the documentation or have improvement suggestions, you can :
|
||||
|
||||
- open a {{v0X.doc.new_issue}} if you are comfortable with github
|
||||
- let us know on {{v0X.doc.discourse}} if you want to discuss about it
|
||||
|
||||
Let us as well know if you have some improvement suggestions !
|
||||
|
||||
|
||||
|
||||
## Contributing to the code
|
||||
|
||||
- If you want to report a bug, you can use [the github bugtracker]({{v0X.crowdsec.bugreport}})
|
||||
- If you want to suggest an improvement you can use either [the github bugtracker]({{v0X.crowdsec.bugreport}}) or the {{v0X.doc.discourse}} if you want to discuss
|
||||
|
||||
|
||||
## Contributing to the parsers/scenarios
|
||||
|
||||
If you want to contribute your parser or scenario to the community and have them appear on the {{v0X.hub.htmlname}}, you should [open a merge request](https://github.com/crowdsecurity/hub/pulls) on the hub.
|
||||
|
||||
We are currently working on a proper [CI](https://en.wikipedia.org/wiki/Continuous_integration) for the {{v0X.hub.htmlname}}, so for now all contribution are subject to peer-review, please bear with us !
|
||||
|
|
@ -37,7 +37,6 @@ nav:
|
|||
- Expressions: write_configurations/expressions.md
|
||||
- bouncers: bouncers/index.md
|
||||
- Contributing:
|
||||
- General: contributing.md
|
||||
- Writing Output Plugins: references/plugins_api.md
|
||||
- Cscli commands:
|
||||
- Cscli: cscli/cscli.md
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# Crowdsec
|
||||
|
||||
{{macros_info() }}
|
|
@ -75,10 +75,5 @@ nav:
|
|||
- Admin Guide:
|
||||
- Services Configuration: admin_guide/services_configuration.md
|
||||
- Architecture: admin_guide/architecture.md
|
||||
- Contributing:
|
||||
- General: contributing.md
|
||||
- Reporting bugs: contributing.md
|
||||
- Asking questions: contributing.md
|
||||
- Publishing parsers & scenarios: contributing.md
|
||||
- Upgrade V0.X to V1.X: migration.md
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ nav:
|
|||
- Developers : https://crowdsecurity.github.io/api_doc/index.html?urls.primaryName=LAPI" target="_blank
|
||||
- Hub : https://hub.crowdsec.net/" target="_blank
|
||||
- Releases : https://github.com/crowdsecurity/crowdsec/releases" target="_blank
|
||||
- Contributing: contributing.md
|
||||
- FAQ: faq.md
|
||||
|
||||
|
||||
|
@ -42,7 +43,7 @@ google_analytics:
|
|||
- auto
|
||||
|
||||
extra:
|
||||
swagger_url: "https://raw.githubusercontent.com/crowdsecurity/crowdsec/wip_lapi/pkg/models/localapi_swagger.yaml"
|
||||
swagger_url: "https://raw.githubusercontent.com/crowdsecurity/crowdsec/master/pkg/models/localapi_swagger.yaml"
|
||||
v0X:
|
||||
doc:
|
||||
new_issue: "[new documentation issue](https://github.com/crowdsecurity/crowdsec/issues/new)"
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
qs "github.com/google/go-querystring/query"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// type ApiAlerts service
|
||||
|
@ -65,7 +66,7 @@ func (s *AlertsService) List(ctx context.Context, opts AlertsListOpts) (*models.
|
|||
u := fmt.Sprintf("%s/alerts", s.client.URLPrefix)
|
||||
params, err := qs.Values(opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, errors.Wrap(err, "building query")
|
||||
}
|
||||
if len(params) > 0 {
|
||||
URI = fmt.Sprintf("%s?%s", u, params.Encode())
|
||||
|
@ -75,12 +76,12 @@ func (s *AlertsService) List(ctx context.Context, opts AlertsListOpts) (*models.
|
|||
|
||||
req, err := s.client.NewRequest("GET", URI, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, errors.Wrap(err, "building request")
|
||||
}
|
||||
|
||||
resp, err := s.client.Do(ctx, req, &alerts)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
return nil, resp, errors.Wrap(err, "performing request")
|
||||
}
|
||||
return &alerts, resp, nil
|
||||
}
|
||||
|
@ -117,7 +118,7 @@ func (s *AlertsService) GetByID(ctx context.Context, alertID int) (*models.Alert
|
|||
|
||||
resp, err := s.client.Do(ctx, req, &alert)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
return nil, nil, err
|
||||
}
|
||||
return &alert, resp, nil
|
||||
}
|
||||
|
|
496
pkg/apiclient/alerts_service_test.go
Normal file
496
pkg/apiclient/alerts_service_test.go
Normal file
|
@ -0,0 +1,496 @@
|
|||
package apiclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwversion"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAlertsListAsMachine(t *testing.T) {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
mux, urlx, teardown := setup()
|
||||
mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`))
|
||||
})
|
||||
log.Printf("URL is %s", urlx)
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
client, err := NewClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
defer teardown()
|
||||
|
||||
mux.HandleFunc("/alerts", func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if r.URL.RawQuery == "ip=1.2.3.4" {
|
||||
testMethod(t, r, "GET")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, `null`)
|
||||
return
|
||||
}
|
||||
|
||||
testMethod(t, r, "GET")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprint(w, `[
|
||||
{"capacity":5,"created_at":"2020-11-28T10:20:47+01:00",
|
||||
"decisions":[
|
||||
{"duration":"59m49.264032632s",
|
||||
"end_ip":16843180,
|
||||
"id":1,
|
||||
"origin":"crowdsec",
|
||||
"scenario":"crowdsecurity/ssh-bf",
|
||||
"scope":"Ip",
|
||||
"simulated":false,
|
||||
"start_ip":16843180,
|
||||
"type":"ban",
|
||||
"value":"1.1.1.172"}
|
||||
],
|
||||
"events":[
|
||||
{"meta":[
|
||||
{"key":"target_user","value":"netflix"},
|
||||
{"key":"service","value":"ssh"}
|
||||
],
|
||||
"timestamp":"2020-11-28 10:20:46 +0000 UTC"},
|
||||
{"meta":[
|
||||
{"key":"target_user","value":"netflix"},
|
||||
{"key":"service","value":"ssh"}
|
||||
],
|
||||
"timestamp":"2020-11-28 10:20:46 +0000 UTC"}
|
||||
],
|
||||
"events_count":6,
|
||||
"id":1,
|
||||
"labels":null,
|
||||
"leakspeed":"10s",
|
||||
"machine_id":"test",
|
||||
"message":"Ip 1.1.1.172 performed 'crowdsecurity/ssh-bf' (6 events over 2.920062ms) at 2020-11-28 10:20:46.845619968 +0100 CET m=+5.903899761",
|
||||
"scenario":"crowdsecurity/ssh-bf",
|
||||
"scenario_hash":"4441dcff07020f6690d998b7101e642359ba405c2abb83565bbbdcee36de280f",
|
||||
"scenario_version":"0.1",
|
||||
"simulated":false,
|
||||
"source":{
|
||||
"as_name":"Cloudflare Inc",
|
||||
"cn":"AU",
|
||||
"ip":"1.1.1.172",
|
||||
"latitude":-37.7,
|
||||
"longitude":145.1833,
|
||||
"range":"1.1.1.0/24",
|
||||
"scope":"Ip",
|
||||
"value":"1.1.1.172"
|
||||
},
|
||||
"start_at":"2020-11-28 10:20:46.842701127 +0100 +0100",
|
||||
"stop_at":"2020-11-28 10:20:46.845621385 +0100 +0100"
|
||||
}
|
||||
]`)
|
||||
})
|
||||
|
||||
tcapacity := int32(5)
|
||||
tduration := "59m49.264032632s"
|
||||
torigin := "crowdsec"
|
||||
tscenario := "crowdsecurity/ssh-bf"
|
||||
tscope := "Ip"
|
||||
ttype := "ban"
|
||||
tvalue := "1.1.1.172"
|
||||
ttimestamp := "2020-11-28 10:20:46 +0000 UTC"
|
||||
teventscount := int32(6)
|
||||
tleakspeed := "10s"
|
||||
tmessage := "Ip 1.1.1.172 performed 'crowdsecurity/ssh-bf' (6 events over 2.920062ms) at 2020-11-28 10:20:46.845619968 +0100 CET m=+5.903899761"
|
||||
tscenariohash := "4441dcff07020f6690d998b7101e642359ba405c2abb83565bbbdcee36de280f"
|
||||
tscenarioversion := "0.1"
|
||||
tstartat := "2020-11-28 10:20:46.842701127 +0100 +0100"
|
||||
tstopat := "2020-11-28 10:20:46.845621385 +0100 +0100"
|
||||
|
||||
expected := models.GetAlertsResponse{
|
||||
&models.Alert{
|
||||
Capacity: &tcapacity,
|
||||
CreatedAt: "2020-11-28T10:20:47+01:00",
|
||||
Decisions: []*models.Decision{
|
||||
&models.Decision{
|
||||
Duration: &tduration,
|
||||
EndIP: 16843180,
|
||||
ID: 1,
|
||||
Origin: &torigin,
|
||||
Scenario: &tscenario,
|
||||
|
||||
Scope: &tscope,
|
||||
Simulated: new(bool), //false,
|
||||
StartIP: 16843180,
|
||||
Type: &ttype,
|
||||
Value: &tvalue,
|
||||
},
|
||||
},
|
||||
Events: []*models.Event{
|
||||
&models.Event{
|
||||
Meta: models.Meta{
|
||||
&models.MetaItems0{
|
||||
Key: "target_user",
|
||||
Value: "netflix",
|
||||
},
|
||||
&models.MetaItems0{
|
||||
Key: "service",
|
||||
Value: "ssh",
|
||||
},
|
||||
},
|
||||
Timestamp: &ttimestamp,
|
||||
},
|
||||
&models.Event{
|
||||
Meta: models.Meta{
|
||||
&models.MetaItems0{
|
||||
Key: "target_user",
|
||||
Value: "netflix",
|
||||
},
|
||||
&models.MetaItems0{
|
||||
Key: "service",
|
||||
Value: "ssh",
|
||||
},
|
||||
},
|
||||
Timestamp: &ttimestamp,
|
||||
},
|
||||
},
|
||||
EventsCount: &teventscount,
|
||||
ID: 1,
|
||||
Leakspeed: &tleakspeed,
|
||||
MachineID: "test",
|
||||
Message: &tmessage,
|
||||
Remediation: false,
|
||||
Scenario: &tscenario,
|
||||
ScenarioHash: &tscenariohash,
|
||||
ScenarioVersion: &tscenarioversion,
|
||||
Simulated: new(bool), //(false),
|
||||
Source: &models.Source{
|
||||
AsName: "Cloudflare Inc",
|
||||
AsNumber: "",
|
||||
Cn: "AU",
|
||||
IP: "1.1.1.172",
|
||||
Latitude: -37.7,
|
||||
Longitude: 145.1833,
|
||||
Range: "1.1.1.0/24",
|
||||
Scope: &tscope,
|
||||
Value: &tvalue,
|
||||
},
|
||||
StartAt: &tstartat,
|
||||
StopAt: &tstopat,
|
||||
},
|
||||
}
|
||||
|
||||
//log.Debugf("data : -> %s", spew.Sdump(alerts))
|
||||
//log.Debugf("resp : -> %s", spew.Sdump(resp))
|
||||
//log.Debugf("expected : -> %s", spew.Sdump(expected))
|
||||
//first one returns data
|
||||
alerts, resp, err := client.Alerts.List(context.Background(), AlertsListOpts{})
|
||||
if err != nil {
|
||||
log.Errorf("test Unable to list alerts : %+v", err)
|
||||
}
|
||||
if resp.Response.StatusCode != http.StatusOK {
|
||||
t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(*alerts, expected) {
|
||||
t.Errorf("client.Alerts.List returned %+v, want %+v", resp, expected)
|
||||
}
|
||||
//this one doesn't
|
||||
filter := AlertsListOpts{IPEquals: new(string)}
|
||||
*filter.IPEquals = "1.2.3.4"
|
||||
alerts, resp, err = client.Alerts.List(context.Background(), filter)
|
||||
if err != nil {
|
||||
log.Errorf("test Unable to list alerts : %+v", err)
|
||||
}
|
||||
if resp.Response.StatusCode != http.StatusOK {
|
||||
t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
|
||||
}
|
||||
assert.Equal(t, 0, len(*alerts))
|
||||
}
|
||||
|
||||
func TestAlertsGetAsMachine(t *testing.T) {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
mux, urlx, teardown := setup()
|
||||
mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`))
|
||||
})
|
||||
log.Printf("URL is %s", urlx)
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
client, err := NewClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
defer teardown()
|
||||
mux.HandleFunc("/alerts/2", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "GET")
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
fmt.Fprintf(w, `{"message":"object not found"}`)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/alerts/1", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "GET")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprint(w, `{"capacity":5,"created_at":"2020-11-28T10:20:47+01:00",
|
||||
"decisions":[
|
||||
{"duration":"59m49.264032632s",
|
||||
"end_ip":16843180,
|
||||
"id":1,
|
||||
"origin":"crowdsec",
|
||||
"scenario":"crowdsecurity/ssh-bf",
|
||||
"scope":"Ip",
|
||||
"simulated":false,
|
||||
"start_ip":16843180,
|
||||
"type":"ban",
|
||||
"value":"1.1.1.172"}
|
||||
],
|
||||
"events":[
|
||||
{"meta":[
|
||||
{"key":"target_user","value":"netflix"},
|
||||
{"key":"service","value":"ssh"}
|
||||
],
|
||||
"timestamp":"2020-11-28 10:20:46 +0000 UTC"},
|
||||
{"meta":[
|
||||
{"key":"target_user","value":"netflix"},
|
||||
{"key":"service","value":"ssh"}
|
||||
],
|
||||
"timestamp":"2020-11-28 10:20:46 +0000 UTC"}
|
||||
],
|
||||
"events_count":6,
|
||||
"id":1,
|
||||
"labels":null,
|
||||
"leakspeed":"10s",
|
||||
"machine_id":"test",
|
||||
"message":"Ip 1.1.1.172 performed 'crowdsecurity/ssh-bf' (6 events over 2.920062ms) at 2020-11-28 10:20:46.845619968 +0100 CET m=+5.903899761",
|
||||
"scenario":"crowdsecurity/ssh-bf",
|
||||
"scenario_hash":"4441dcff07020f6690d998b7101e642359ba405c2abb83565bbbdcee36de280f",
|
||||
"scenario_version":"0.1",
|
||||
"simulated":false,
|
||||
"source":{
|
||||
"as_name":"Cloudflare Inc",
|
||||
"cn":"AU",
|
||||
"ip":"1.1.1.172",
|
||||
"latitude":-37.7,
|
||||
"longitude":145.1833,
|
||||
"range":"1.1.1.0/24",
|
||||
"scope":"Ip",
|
||||
"value":"1.1.1.172"
|
||||
},
|
||||
"start_at":"2020-11-28 10:20:46.842701127 +0100 +0100",
|
||||
"stop_at":"2020-11-28 10:20:46.845621385 +0100 +0100"
|
||||
}`)
|
||||
})
|
||||
|
||||
tcapacity := int32(5)
|
||||
tduration := "59m49.264032632s"
|
||||
torigin := "crowdsec"
|
||||
tscenario := "crowdsecurity/ssh-bf"
|
||||
tscope := "Ip"
|
||||
ttype := "ban"
|
||||
tvalue := "1.1.1.172"
|
||||
ttimestamp := "2020-11-28 10:20:46 +0000 UTC"
|
||||
teventscount := int32(6)
|
||||
tleakspeed := "10s"
|
||||
tmessage := "Ip 1.1.1.172 performed 'crowdsecurity/ssh-bf' (6 events over 2.920062ms) at 2020-11-28 10:20:46.845619968 +0100 CET m=+5.903899761"
|
||||
tscenariohash := "4441dcff07020f6690d998b7101e642359ba405c2abb83565bbbdcee36de280f"
|
||||
tscenarioversion := "0.1"
|
||||
tstartat := "2020-11-28 10:20:46.842701127 +0100 +0100"
|
||||
tstopat := "2020-11-28 10:20:46.845621385 +0100 +0100"
|
||||
|
||||
expected := &models.Alert{
|
||||
Capacity: &tcapacity,
|
||||
CreatedAt: "2020-11-28T10:20:47+01:00",
|
||||
Decisions: []*models.Decision{
|
||||
&models.Decision{
|
||||
Duration: &tduration,
|
||||
EndIP: 16843180,
|
||||
ID: 1,
|
||||
Origin: &torigin,
|
||||
Scenario: &tscenario,
|
||||
|
||||
Scope: &tscope,
|
||||
Simulated: new(bool), //false,
|
||||
StartIP: 16843180,
|
||||
Type: &ttype,
|
||||
Value: &tvalue,
|
||||
},
|
||||
},
|
||||
Events: []*models.Event{
|
||||
&models.Event{
|
||||
Meta: models.Meta{
|
||||
&models.MetaItems0{
|
||||
Key: "target_user",
|
||||
Value: "netflix",
|
||||
},
|
||||
&models.MetaItems0{
|
||||
Key: "service",
|
||||
Value: "ssh",
|
||||
},
|
||||
},
|
||||
Timestamp: &ttimestamp,
|
||||
},
|
||||
&models.Event{
|
||||
Meta: models.Meta{
|
||||
&models.MetaItems0{
|
||||
Key: "target_user",
|
||||
Value: "netflix",
|
||||
},
|
||||
&models.MetaItems0{
|
||||
Key: "service",
|
||||
Value: "ssh",
|
||||
},
|
||||
},
|
||||
Timestamp: &ttimestamp,
|
||||
},
|
||||
},
|
||||
EventsCount: &teventscount,
|
||||
ID: 1,
|
||||
Leakspeed: &tleakspeed,
|
||||
MachineID: "test",
|
||||
Message: &tmessage,
|
||||
Remediation: false,
|
||||
Scenario: &tscenario,
|
||||
ScenarioHash: &tscenariohash,
|
||||
ScenarioVersion: &tscenarioversion,
|
||||
Simulated: new(bool), //(false),
|
||||
Source: &models.Source{
|
||||
AsName: "Cloudflare Inc",
|
||||
AsNumber: "",
|
||||
Cn: "AU",
|
||||
IP: "1.1.1.172",
|
||||
Latitude: -37.7,
|
||||
Longitude: 145.1833,
|
||||
Range: "1.1.1.0/24",
|
||||
Scope: &tscope,
|
||||
Value: &tvalue,
|
||||
},
|
||||
StartAt: &tstartat,
|
||||
StopAt: &tstopat,
|
||||
}
|
||||
|
||||
alerts, resp, err := client.Alerts.GetByID(context.Background(), 1)
|
||||
|
||||
if resp.Response.StatusCode != http.StatusOK {
|
||||
t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(*alerts, *expected) {
|
||||
t.Errorf("client.Alerts.List returned %+v, want %+v", resp, expected)
|
||||
}
|
||||
|
||||
//fail
|
||||
alerts, resp, err = client.Alerts.GetByID(context.Background(), 2)
|
||||
assert.Contains(t, fmt.Sprintf("%s", err), "API error: object not found")
|
||||
|
||||
}
|
||||
|
||||
func TestAlertsCreateAsMachine(t *testing.T) {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
mux, urlx, teardown := setup()
|
||||
mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`))
|
||||
})
|
||||
mux.HandleFunc("/alerts", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "POST")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`["3"]`))
|
||||
})
|
||||
log.Printf("URL is %s", urlx)
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
client, err := NewClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
defer teardown()
|
||||
alert := models.AddAlertsRequest{}
|
||||
alerts, resp, err := client.Alerts.Add(context.Background(), alert)
|
||||
expected := &models.AddAlertsResponse{"3"}
|
||||
if resp.Response.StatusCode != http.StatusOK {
|
||||
t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
|
||||
}
|
||||
if !reflect.DeepEqual(*alerts, *expected) {
|
||||
t.Errorf("client.Alerts.List returned %+v, want %+v", resp, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlertsDeleteAsMachine(t *testing.T) {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
mux, urlx, teardown := setup()
|
||||
mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`))
|
||||
})
|
||||
mux.HandleFunc("/alerts", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "DELETE")
|
||||
assert.Equal(t, r.URL.RawQuery, "ip=1.2.3.4")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"message":"0 deleted alerts"}`))
|
||||
})
|
||||
log.Printf("URL is %s", urlx)
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
client, err := NewClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
defer teardown()
|
||||
alert := AlertsDeleteOpts{IPEquals: new(string)}
|
||||
*alert.IPEquals = "1.2.3.4"
|
||||
alerts, resp, err := client.Alerts.Delete(context.Background(), alert)
|
||||
expected := &models.DeleteAlertsResponse{""}
|
||||
if resp.Response.StatusCode != http.StatusOK {
|
||||
t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
|
||||
}
|
||||
if !reflect.DeepEqual(*alerts, *expected) {
|
||||
t.Errorf("client.Alerts.List returned %+v, want %+v", resp, expected)
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@ type APIKeyTransport struct {
|
|||
// RoundTrip implements the RoundTripper interface.
|
||||
func (t *APIKeyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if t.APIKey == "" {
|
||||
return nil, errors.New("t.APIKey is empty")
|
||||
return nil, errors.New("APIKey is empty")
|
||||
}
|
||||
|
||||
// We must make a copy of the Request so
|
||||
|
@ -97,7 +97,7 @@ func (t *JWTTransport) refreshJwtToken() error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("can't update scenario list: %s", err)
|
||||
}
|
||||
log.Infof("scenarios liste updated for '%s'", *t.MachineID)
|
||||
log.Infof("scenarios list updated for '%s'", *t.MachineID)
|
||||
}
|
||||
|
||||
var auth = models.WatcherAuthRequest{
|
||||
|
|
181
pkg/apiclient/auth_service_test.go
Normal file
181
pkg/apiclient/auth_service_test.go
Normal file
|
@ -0,0 +1,181 @@
|
|||
package apiclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwversion"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWatcherAuth(t *testing.T) {
|
||||
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
//body: models.WatcherRegistrationRequest{MachineID: &config.MachineID, Password: &config.Password}
|
||||
|
||||
mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "POST")
|
||||
buf := new(bytes.Buffer)
|
||||
_, _ = buf.ReadFrom(r.Body)
|
||||
newStr := buf.String()
|
||||
log.Printf("--> %s", newStr)
|
||||
if newStr == `{"machine_id":"test_login","password":"test_password","scenarios":["crowdsecurity/test"]}
|
||||
` {
|
||||
log.Printf("ok cool")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, `{"code":200,"expire":"2029-11-30T14:14:24+01:00","token":"toto"}`)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
log.Printf("badbad")
|
||||
fmt.Fprintf(w, `{"message":"access forbidden"}`)
|
||||
}
|
||||
})
|
||||
log.Printf("URL is %s", urlx)
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
|
||||
//ok auth
|
||||
mycfg := &Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
Scenarios: []string{"crowdsecurity/test"},
|
||||
}
|
||||
client, err := NewClient(mycfg)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
_, err = client.Auth.AuthenticateWatcher(context.Background(), models.WatcherAuthRequest{
|
||||
MachineID: &mycfg.MachineID,
|
||||
Password: &mycfg.Password,
|
||||
Scenarios: mycfg.Scenarios,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpect auth err 0: %s", err)
|
||||
}
|
||||
|
||||
//bad auth
|
||||
mycfg = &Config{
|
||||
MachineID: "BADtest_login",
|
||||
Password: "BADtest_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
Scenarios: []string{"crowdsecurity/test"},
|
||||
}
|
||||
client, err = NewClient(mycfg)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
_, err = client.Auth.AuthenticateWatcher(context.Background(), models.WatcherAuthRequest{
|
||||
MachineID: &mycfg.MachineID,
|
||||
Password: &mycfg.Password,
|
||||
})
|
||||
assert.Contains(t, err.Error(), "403 Forbidden")
|
||||
|
||||
}
|
||||
|
||||
func TestWatcherRegister(t *testing.T) {
|
||||
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
//body: models.WatcherRegistrationRequest{MachineID: &config.MachineID, Password: &config.Password}
|
||||
|
||||
mux.HandleFunc("/watchers", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "POST")
|
||||
buf := new(bytes.Buffer)
|
||||
_, _ = buf.ReadFrom(r.Body)
|
||||
newStr := buf.String()
|
||||
assert.Equal(t, newStr, `{"machine_id":"test_login","password":"test_password"}
|
||||
`)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
log.Printf("URL is %s", urlx)
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
client, err := RegisterClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
}, &http.Client{})
|
||||
if err != nil {
|
||||
t.Fatalf("while registering client : %s", err)
|
||||
}
|
||||
log.Printf("->%T", client)
|
||||
}
|
||||
|
||||
func TestWatcherUnregister(t *testing.T) {
|
||||
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
//body: models.WatcherRegistrationRequest{MachineID: &config.MachineID, Password: &config.Password}
|
||||
|
||||
mux.HandleFunc("/watchers", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "DELETE")
|
||||
assert.Equal(t, r.ContentLength, int64(0))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "POST")
|
||||
buf := new(bytes.Buffer)
|
||||
_, _ = buf.ReadFrom(r.Body)
|
||||
newStr := buf.String()
|
||||
if newStr == `{"machine_id":"test_login","password":"test_password","scenarios":["crowdsecurity/test"]}
|
||||
` {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, `{"code":200,"expire":"2029-11-30T14:14:24+01:00","token":"toto"}`)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
fmt.Fprintf(w, `{"message":"access forbidden"}`)
|
||||
}
|
||||
})
|
||||
|
||||
log.Printf("URL is %s", urlx)
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
mycfg := &Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
Scenarios: []string{"crowdsecurity/test"},
|
||||
}
|
||||
client, err := NewClient(mycfg)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
_, err = client.Auth.UnregisterWatcher(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("while registering client : %s", err)
|
||||
}
|
||||
log.Printf("->%T", client)
|
||||
}
|
83
pkg/apiclient/auth_test.go
Normal file
83
pkg/apiclient/auth_test.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
package apiclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestApiAuth(t *testing.T) {
|
||||
log.SetLevel(log.TraceLevel)
|
||||
|
||||
mux, urlx, teardown := setup()
|
||||
mux.HandleFunc("/decisions", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "GET")
|
||||
if r.Header.Get("X-Api-Key") == "ixu" {
|
||||
assert.Equal(t, r.URL.RawQuery, "ip=1.2.3.4")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`null`))
|
||||
} else {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write([]byte(`{"message":"access forbidden"}`))
|
||||
}
|
||||
})
|
||||
log.Printf("URL is %s", urlx)
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
|
||||
defer teardown()
|
||||
|
||||
//ok no answer
|
||||
auth := &APIKeyTransport{
|
||||
APIKey: "ixu",
|
||||
}
|
||||
|
||||
newcli, err := NewDefaultClient(apiURL, "v1", "toto", auth.Client())
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
alert := DecisionsListOpts{IPEquals: new(string)}
|
||||
*alert.IPEquals = "1.2.3.4"
|
||||
_, resp, err := newcli.Decisions.List(context.Background(), alert)
|
||||
|
||||
if resp.Response.StatusCode != http.StatusOK {
|
||||
t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
|
||||
}
|
||||
|
||||
//ko bad token
|
||||
auth = &APIKeyTransport{
|
||||
APIKey: "bad",
|
||||
}
|
||||
|
||||
newcli, err = NewDefaultClient(apiURL, "v1", "toto", auth.Client())
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
_, resp, err = newcli.Decisions.List(context.Background(), alert)
|
||||
|
||||
log.Infof("--> %s", err)
|
||||
if resp.Response.StatusCode != http.StatusForbidden {
|
||||
t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
|
||||
}
|
||||
assert.Contains(t, err.Error(), "API error: access forbidden")
|
||||
//ko empty token
|
||||
auth = &APIKeyTransport{}
|
||||
newcli, err = NewDefaultClient(apiURL, "v1", "toto", auth.Client())
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
_, resp, err = newcli.Decisions.List(context.Background(), alert)
|
||||
|
||||
log.Infof("--> %s", err)
|
||||
assert.Contains(t, err.Error(), "APIKey is empty")
|
||||
|
||||
}
|
|
@ -86,11 +86,14 @@ func RegisterClient(config *Config, client *http.Client) (*ApiClient, error) {
|
|||
c.Alerts = (*AlertsService)(&c.common)
|
||||
c.Auth = (*AuthService)(&c.common)
|
||||
|
||||
_, err := c.Auth.RegisterWatcher(context.Background(), models.WatcherRegistrationRequest{MachineID: &config.MachineID, Password: &config.Password})
|
||||
resp, err := c.Auth.RegisterWatcher(context.Background(), models.WatcherRegistrationRequest{MachineID: &config.MachineID, Password: &config.Password})
|
||||
/*if we have http status, return it*/
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "api register (%s): %s", c.BaseURL, err)
|
||||
if resp != nil && resp.Response != nil {
|
||||
return nil, errors.Wrapf(err, "api register (%s) http %s : %s", c.BaseURL, resp.Response.Status, err)
|
||||
}
|
||||
return nil, errors.Wrapf(err, "api register (%s) : %s", c.BaseURL, err)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
|
||||
}
|
||||
|
@ -107,7 +110,11 @@ type ErrorResponse struct {
|
|||
}
|
||||
|
||||
func (e *ErrorResponse) Error() string {
|
||||
return fmt.Sprintf("API error (%s) : %s", *e.Message, e.Errors)
|
||||
err := fmt.Sprintf("API error: %s", *e.Message)
|
||||
if len(e.Errors) > 0 {
|
||||
err += fmt.Sprintf(" (%s)", e.Errors)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func newResponse(r *http.Response) *Response {
|
||||
|
@ -123,7 +130,13 @@ func CheckResponse(r *http.Response) error {
|
|||
errorResponse := &ErrorResponse{}
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err == nil && data != nil {
|
||||
json.Unmarshal(data, errorResponse)
|
||||
err := json.Unmarshal(data, errorResponse)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "http code %d, invalid body", r.StatusCode)
|
||||
}
|
||||
} else {
|
||||
errorResponse.Message = new(string)
|
||||
*errorResponse.Message = fmt.Sprintf("http code %d, no error message", r.StatusCode)
|
||||
}
|
||||
return errorResponse
|
||||
}
|
||||
|
|
|
@ -71,11 +71,12 @@ func (c *ApiClient) Do(ctx context.Context, req *http.Request, v interface{}) (*
|
|||
if e, ok := err.(*url.Error); ok {
|
||||
if url, err := url.Parse(e.URL); err == nil {
|
||||
e.URL = url.String()
|
||||
return nil, e
|
||||
return newResponse(resp), e
|
||||
} else {
|
||||
return newResponse(resp), err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
return newResponse(resp), err
|
||||
}
|
||||
|
||||
response := newResponse(resp)
|
||||
|
@ -98,6 +99,5 @@ func (c *ApiClient) Do(ctx context.Context, req *http.Request, v interface{}) (*
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response, err
|
||||
}
|
||||
|
|
77
pkg/apiclient/client_http_test.go
Normal file
77
pkg/apiclient/client_http_test.go
Normal file
|
@ -0,0 +1,77 @@
|
|||
package apiclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwversion"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewRequestInvalid(t *testing.T) {
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
//missing slash in uri
|
||||
apiURL, err := url.Parse(urlx)
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
client, err := NewClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
/*mock login*/
|
||||
mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(`{"code": 401, "message" : "bad login/password"}`))
|
||||
})
|
||||
|
||||
mux.HandleFunc("/alerts", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "GET")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
_, _, err = client.Alerts.List(context.Background(), AlertsListOpts{})
|
||||
assert.Contains(t, err.Error(), `building request: BaseURL must have a trailing slash, but `)
|
||||
}
|
||||
|
||||
func TestNewRequestTimeout(t *testing.T) {
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
//missing slash in uri
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
client, err := NewClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
/*mock login*/
|
||||
mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
time.Sleep(2 * time.Second)
|
||||
})
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, _, err = client.Alerts.List(ctx, AlertsListOpts{})
|
||||
assert.Contains(t, err.Error(), `performing request: context deadline exceeded`)
|
||||
}
|
200
pkg/apiclient/client_test.go
Normal file
200
pkg/apiclient/client_test.go
Normal file
|
@ -0,0 +1,200 @@
|
|||
package apiclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwversion"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
/*this is a ripoff of google/go-github approach :
|
||||
- setup a test http server along with a client that is configured to talk to test server
|
||||
- each test will then bind handler for the method(s) they want to try
|
||||
*/
|
||||
|
||||
func setup() (mux *http.ServeMux, serverURL string, teardown func()) {
|
||||
// mux is the HTTP request multiplexer used with the test server.
|
||||
mux = http.NewServeMux()
|
||||
baseURLPath := "/v1"
|
||||
|
||||
apiHandler := http.NewServeMux()
|
||||
apiHandler.Handle(baseURLPath+"/", http.StripPrefix(baseURLPath, mux))
|
||||
|
||||
// server is a test HTTP server used to provide mock API responses.
|
||||
server := httptest.NewServer(apiHandler)
|
||||
|
||||
return mux, server.URL, server.Close
|
||||
}
|
||||
|
||||
func testMethod(t *testing.T, r *http.Request, want string) {
|
||||
t.Helper()
|
||||
if got := r.Method; got != want {
|
||||
t.Errorf("Request method: %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewClientOk(t *testing.T) {
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
client, err := NewClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
/*mock login*/
|
||||
mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`))
|
||||
})
|
||||
|
||||
mux.HandleFunc("/alerts", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "GET")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
_, resp, err := client.Alerts.List(context.Background(), AlertsListOpts{})
|
||||
if err != nil {
|
||||
t.Fatalf("test Unable to list alerts : %+v", err)
|
||||
}
|
||||
if resp.Response.StatusCode != http.StatusOK {
|
||||
t.Fatalf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusCreated)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewClientKo(t *testing.T) {
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
client, err := NewClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
/*mock login*/
|
||||
mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(`{"code": 401, "message" : "bad login/password"}`))
|
||||
})
|
||||
|
||||
mux.HandleFunc("/alerts", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "GET")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
_, _, err = client.Alerts.List(context.Background(), AlertsListOpts{})
|
||||
assert.Contains(t, err.Error(), `received response status "401 Unauthorized"`)
|
||||
log.Printf("err-> %s", err)
|
||||
}
|
||||
|
||||
func TestNewDefaultClient(t *testing.T) {
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
client, err := NewDefaultClient(apiURL, "/v1", "", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
mux.HandleFunc("/alerts", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(`{"code": 401, "message" : "brr"}`))
|
||||
})
|
||||
_, _, err = client.Alerts.List(context.Background(), AlertsListOpts{})
|
||||
assert.Contains(t, err.Error(), `performing request: API error: brr`)
|
||||
log.Printf("err-> %s", err)
|
||||
}
|
||||
|
||||
func TestNewClientRegisterKO(t *testing.T) {
|
||||
apiURL, err := url.Parse("http://127.0.0.1:4242/")
|
||||
if err != nil {
|
||||
t.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
_, err = RegisterClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
}, &http.Client{})
|
||||
assert.Contains(t, fmt.Sprintf("%s", err), "dial tcp 127.0.0.1:4242: connect: connection refused")
|
||||
}
|
||||
|
||||
func TestNewClientRegisterOK(t *testing.T) {
|
||||
log.SetLevel(log.TraceLevel)
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
/*mock login*/
|
||||
mux.HandleFunc("/watchers", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "POST")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`))
|
||||
})
|
||||
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
t.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
client, err := RegisterClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
}, &http.Client{})
|
||||
if err != nil {
|
||||
t.Fatalf("while registering client : %s", err)
|
||||
}
|
||||
log.Printf("->%T", client)
|
||||
}
|
||||
|
||||
func TestNewClientBadAnswer(t *testing.T) {
|
||||
log.SetLevel(log.TraceLevel)
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
/*mock login*/
|
||||
mux.HandleFunc("/watchers", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "POST")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(`bad`))
|
||||
})
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
t.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
_, err = RegisterClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
}, &http.Client{})
|
||||
assert.Contains(t, fmt.Sprintf("%s", err), `invalid body: invalid character 'b' looking for beginning of value`)
|
||||
}
|
|
@ -35,7 +35,7 @@ func (s *DecisionsService) List(ctx context.Context, opts DecisionsListOpts) (*m
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u := fmt.Sprintf("%s/decisions/?%s", s.client.URLPrefix, params.Encode())
|
||||
u := fmt.Sprintf("%s/decisions?%s", s.client.URLPrefix, params.Encode())
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
|
|
273
pkg/apiclient/decisions_service_test.go
Normal file
273
pkg/apiclient/decisions_service_test.go
Normal file
|
@ -0,0 +1,273 @@
|
|||
package apiclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwversion"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDecisionsList(t *testing.T) {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
mux.HandleFunc("/decisions", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "GET")
|
||||
if r.URL.RawQuery == "ip=1.2.3.4" {
|
||||
assert.Equal(t, r.URL.RawQuery, "ip=1.2.3.4")
|
||||
assert.Equal(t, r.Header.Get("X-Api-Key"), "ixu")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`[{"duration":"3h59m55.756182786s","end_ip":16909060,"id":4,"origin":"cscli","scenario":"manual 'ban' from '82929df7ee394b73b81252fe3b4e50203yaT2u6nXiaN7Ix9'","scope":"Ip","start_ip":16909060,"type":"ban","value":"1.2.3.4"}]`))
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`null`))
|
||||
//no results
|
||||
}
|
||||
})
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
|
||||
//ok answer
|
||||
auth := &APIKeyTransport{
|
||||
APIKey: "ixu",
|
||||
}
|
||||
|
||||
newcli, err := NewDefaultClient(apiURL, "v1", "toto", auth.Client())
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
tduration := "3h59m55.756182786s"
|
||||
torigin := "cscli"
|
||||
tscenario := "manual 'ban' from '82929df7ee394b73b81252fe3b4e50203yaT2u6nXiaN7Ix9'"
|
||||
tscope := "Ip"
|
||||
ttype := "ban"
|
||||
tvalue := "1.2.3.4"
|
||||
expected := &models.GetDecisionsResponse{
|
||||
&models.Decision{
|
||||
Duration: &tduration,
|
||||
EndIP: 16909060,
|
||||
ID: 4,
|
||||
Origin: &torigin,
|
||||
Scenario: &tscenario,
|
||||
Scope: &tscope,
|
||||
StartIP: 16909060,
|
||||
Type: &ttype,
|
||||
Value: &tvalue,
|
||||
},
|
||||
}
|
||||
|
||||
//OK decisions
|
||||
decisionsFilter := DecisionsListOpts{IPEquals: new(string)}
|
||||
*decisionsFilter.IPEquals = "1.2.3.4"
|
||||
decisions, resp, err := newcli.Decisions.List(context.Background(), decisionsFilter)
|
||||
|
||||
if resp.Response.StatusCode != http.StatusOK {
|
||||
t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(*decisions, *expected) {
|
||||
t.Fatalf("returned %+v, want %+v", resp, expected)
|
||||
}
|
||||
|
||||
//Empty return
|
||||
decisionsFilter = DecisionsListOpts{IPEquals: new(string)}
|
||||
*decisionsFilter.IPEquals = "1.2.3.5"
|
||||
decisions, resp, err = newcli.Decisions.List(context.Background(), decisionsFilter)
|
||||
|
||||
if resp.Response.StatusCode != http.StatusOK {
|
||||
t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
|
||||
}
|
||||
assert.Equal(t, len(*decisions), 0)
|
||||
|
||||
}
|
||||
|
||||
func TestDecisionsStream(t *testing.T) {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
|
||||
mux, urlx, teardown := setup()
|
||||
defer teardown()
|
||||
|
||||
mux.HandleFunc("/decisions/stream", func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
assert.Equal(t, r.Header.Get("X-Api-Key"), "ixu")
|
||||
testMethod(t, r, "GET")
|
||||
if r.Method == "GET" {
|
||||
|
||||
if r.URL.RawQuery == "startup=true" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"deleted":null,"new":[{"duration":"3h59m55.756182786s","end_ip":16909060,"id":4,"origin":"cscli","scenario":"manual 'ban' from '82929df7ee394b73b81252fe3b4e50203yaT2u6nXiaN7Ix9'","scope":"Ip","start_ip":16909060,"type":"ban","value":"1.2.3.4"}]}`))
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"deleted":null,"new":null}`))
|
||||
}
|
||||
}
|
||||
})
|
||||
mux.HandleFunc("/decisions", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, r.Header.Get("X-Api-Key"), "ixu")
|
||||
testMethod(t, r, "DELETE")
|
||||
if r.Method == "DELETE" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
})
|
||||
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
|
||||
//ok answer
|
||||
auth := &APIKeyTransport{
|
||||
APIKey: "ixu",
|
||||
}
|
||||
|
||||
newcli, err := NewDefaultClient(apiURL, "v1", "toto", auth.Client())
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
tduration := "3h59m55.756182786s"
|
||||
torigin := "cscli"
|
||||
tscenario := "manual 'ban' from '82929df7ee394b73b81252fe3b4e50203yaT2u6nXiaN7Ix9'"
|
||||
tscope := "Ip"
|
||||
ttype := "ban"
|
||||
tvalue := "1.2.3.4"
|
||||
expected := &models.DecisionsStreamResponse{
|
||||
New: models.GetDecisionsResponse{
|
||||
&models.Decision{
|
||||
Duration: &tduration,
|
||||
EndIP: 16909060,
|
||||
ID: 4,
|
||||
Origin: &torigin,
|
||||
Scenario: &tscenario,
|
||||
Scope: &tscope,
|
||||
StartIP: 16909060,
|
||||
Type: &ttype,
|
||||
Value: &tvalue,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
decisions, resp, err := newcli.Decisions.GetStream(context.Background(), true)
|
||||
|
||||
if resp.Response.StatusCode != http.StatusOK {
|
||||
t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(*decisions, *expected) {
|
||||
t.Fatalf("returned %+v, want %+v", resp, expected)
|
||||
}
|
||||
|
||||
//and second call, we get empty lists
|
||||
decisions, resp, err = newcli.Decisions.GetStream(context.Background(), false)
|
||||
|
||||
if resp.Response.StatusCode != http.StatusOK {
|
||||
t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
|
||||
}
|
||||
assert.Equal(t, 0, len(decisions.New))
|
||||
assert.Equal(t, 0, len(decisions.Deleted))
|
||||
|
||||
//delete stream
|
||||
resp, err = newcli.Decisions.StopStream(context.Background())
|
||||
|
||||
if resp.Response.StatusCode != http.StatusOK {
|
||||
t.Errorf("Alerts.List returned status: %d, want %d", resp.Response.StatusCode, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteDecisions(t *testing.T) {
|
||||
mux, urlx, teardown := setup()
|
||||
mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`))
|
||||
})
|
||||
mux.HandleFunc("/decisions", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, "DELETE")
|
||||
assert.Equal(t, r.URL.RawQuery, "ip=1.2.3.4")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"nbDeleted":"1"}`))
|
||||
//w.Write([]byte(`{"message":"0 deleted alerts"}`))
|
||||
})
|
||||
log.Printf("URL is %s", urlx)
|
||||
apiURL, err := url.Parse(urlx + "/")
|
||||
if err != nil {
|
||||
log.Fatalf("parsing api url: %s", apiURL)
|
||||
}
|
||||
client, err := NewClient(&Config{
|
||||
MachineID: "test_login",
|
||||
Password: "test_password",
|
||||
UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
URL: apiURL,
|
||||
VersionPrefix: "v1",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("new api client: %s", err.Error())
|
||||
}
|
||||
|
||||
filters := DecisionsDeleteOpts{IPEquals: new(string)}
|
||||
*filters.IPEquals = "1.2.3.4"
|
||||
deleted, _, err := client.Decisions.Delete(context.Background(), filters)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err : %s", err)
|
||||
}
|
||||
assert.Equal(t, "1", deleted.NbDeleted)
|
||||
|
||||
defer teardown()
|
||||
}
|
||||
|
||||
// func TestDeleteOneDecision(t *testing.T) {
|
||||
// mux, urlx, teardown := setup()
|
||||
// mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
// w.WriteHeader(http.StatusOK)
|
||||
// w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`))
|
||||
// })
|
||||
// mux.HandleFunc("/decisions/1", func(w http.ResponseWriter, r *http.Request) {
|
||||
// testMethod(t, r, "DELETE")
|
||||
// w.WriteHeader(http.StatusOK)
|
||||
// w.Write([]byte(`{"nbDeleted":"1"}`))
|
||||
// })
|
||||
// log.Printf("URL is %s", urlx)
|
||||
// apiURL, err := url.Parse(urlx + "/")
|
||||
// if err != nil {
|
||||
// log.Fatalf("parsing api url: %s", apiURL)
|
||||
// }
|
||||
// client, err := NewClient(&Config{
|
||||
// MachineID: "test_login",
|
||||
// Password: "test_password",
|
||||
// UserAgent: fmt.Sprintf("crowdsec/%s", cwversion.VersionStr()),
|
||||
// URL: apiURL,
|
||||
// VersionPrefix: "v1",
|
||||
// })
|
||||
|
||||
// if err != nil {
|
||||
// log.Fatalf("new api client: %s", err.Error())
|
||||
// }
|
||||
|
||||
// filters := DecisionsDeleteOpts{IPEquals: new(string)}
|
||||
// *filters.IPEquals = "1.2.3.4"
|
||||
// deleted, _, err := client.Decisions.Delete(context.Background(), filters)
|
||||
// if err != nil {
|
||||
// t.Fatalf("unexpected err : %s", err)
|
||||
// }
|
||||
// assert.Equal(t, "1", deleted.NbDeleted)
|
||||
|
||||
// defer teardown()
|
||||
// }
|
|
@ -130,7 +130,7 @@ func TestCreateAlert(t *testing.T) {
|
|||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", loginResp.Token))
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, 200, w.Code)
|
||||
assert.Equal(t, 201, w.Code)
|
||||
assert.Equal(t, "[\"1\"]", w.Body.String())
|
||||
}
|
||||
|
||||
|
@ -538,5 +538,5 @@ func TestDeleteAlert(t *testing.T) {
|
|||
req.RemoteAddr = "127.0.0.1:4242"
|
||||
router.ServeHTTP(w, req)
|
||||
assert.Equal(t, 200, w.Code)
|
||||
assert.Equal(t, `{"message":"1 deleted alerts"}`, w.Body.String())
|
||||
assert.Equal(t, `{"nbDeleted":"1"}`, w.Body.String())
|
||||
}
|
||||
|
|
|
@ -150,6 +150,5 @@ func TestUnknownPath(t *testing.T) {
|
|||
router.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, 404, w.Code)
|
||||
assert.Equal(t, "{\"message\":\"Page or Method not found\"}", w.Body.String())
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package controllers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
v1 "github.com/crowdsecurity/crowdsec/pkg/apiserver/controllers/v1"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
|
||||
|
@ -43,6 +44,14 @@ func (c *Controller) NewV1() error {
|
|||
}
|
||||
|
||||
c.Router.Use(v1.PrometheusMiddleware())
|
||||
c.Router.HandleMethodNotAllowed = true
|
||||
c.Router.NoRoute(func(ctx *gin.Context) {
|
||||
ctx.AbortWithStatus(http.StatusNotFound)
|
||||
})
|
||||
c.Router.NoMethod(func(ctx *gin.Context) {
|
||||
ctx.AbortWithStatus(http.StatusMethodNotAllowed)
|
||||
})
|
||||
|
||||
groupV1 := c.Router.Group("/v1")
|
||||
groupV1.POST("/watchers", handlerV1.CreateMachine)
|
||||
groupV1.POST("/watchers/login", handlerV1.Middlewares.JWT.Middleware.LoginHandler)
|
||||
|
|
|
@ -146,7 +146,7 @@ func (c *Controller) CreateAlert(gctx *gin.Context) {
|
|||
log.Warningf("Cannot send alert to Central API channel")
|
||||
}
|
||||
|
||||
gctx.JSON(http.StatusOK, alerts)
|
||||
gctx.JSON(http.StatusCreated, alerts)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -202,11 +202,15 @@ func (c *Controller) DeleteAlerts(gctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
var err error
|
||||
deleted, err := c.DBClient.DeleteAlertWithFilter(gctx.Request.URL.Query())
|
||||
nbDeleted, err := c.DBClient.DeleteAlertWithFilter(gctx.Request.URL.Query())
|
||||
if err != nil {
|
||||
c.HandleDBErrors(gctx, err)
|
||||
}
|
||||
|
||||
gctx.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("%d deleted alerts", len(deleted))})
|
||||
deleteAlertsResp := models.DeleteAlertsResponse{
|
||||
NbDeleted: strconv.Itoa(nbDeleted),
|
||||
}
|
||||
|
||||
gctx.JSON(http.StatusOK, deleteAlertsResp)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ import (
|
|||
|
||||
func (c *Controller) HandleDBErrors(gctx *gin.Context, err error) {
|
||||
switch errors.Cause(err) {
|
||||
case database.ItemNotFound:
|
||||
gctx.JSON(http.StatusNotFound, gin.H{"message": err.Error()})
|
||||
return
|
||||
case database.UserExists:
|
||||
gctx.JSON(http.StatusForbidden, gin.H{"message": err.Error()})
|
||||
return
|
||||
|
|
|
@ -28,6 +28,6 @@ func (c *Controller) CreateMachine(gctx *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
gctx.Status(http.StatusOK)
|
||||
gctx.Status(http.StatusCreated)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ func TestCreateMachine(t *testing.T) {
|
|||
req.Header.Add("User-Agent", UserAgent)
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, 200, w.Code)
|
||||
assert.Equal(t, 201, w.Code)
|
||||
assert.Equal(t, "", w.Body.String())
|
||||
|
||||
}
|
||||
|
|
|
@ -491,7 +491,7 @@ func (c *Client) DeleteAlertGraph(alertItem *ent.Alert) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteAlertWithFilter(filter map[string][]string) ([]*ent.Alert, error) {
|
||||
func (c *Client) DeleteAlertWithFilter(filter map[string][]string) (int, error) {
|
||||
var err error
|
||||
|
||||
// Get all the alerts that match the filter
|
||||
|
@ -501,10 +501,10 @@ func (c *Client) DeleteAlertWithFilter(filter map[string][]string) ([]*ent.Alert
|
|||
err = c.DeleteAlertGraph(alertItem)
|
||||
if err != nil {
|
||||
log.Warningf("DeleteAlertWithFilter : %s", err)
|
||||
return []*ent.Alert{}, errors.Wrapf(DeleteFail, "event with alert ID '%d'", alertItem.ID)
|
||||
return 0, errors.Wrapf(DeleteFail, "event with alert ID '%d'", alertItem.ID)
|
||||
}
|
||||
}
|
||||
return alertsToDelete, nil
|
||||
return len(alertsToDelete), nil
|
||||
}
|
||||
|
||||
func (c *Client) FlushAlerts(MaxAge string, MaxItems int) error {
|
||||
|
@ -521,12 +521,12 @@ func (c *Client) FlushAlerts(MaxAge string, MaxItems int) error {
|
|||
filter := map[string][]string{
|
||||
"created_before": {MaxAge},
|
||||
}
|
||||
deleted, err := c.DeleteAlertWithFilter(filter)
|
||||
nbDeleted, err := c.DeleteAlertWithFilter(filter)
|
||||
if err != nil {
|
||||
log.Warningf("FlushAlerts (max age) : %s", err)
|
||||
return errors.Wrapf(err, "unable to flush alerts with filter until: %s", MaxAge)
|
||||
}
|
||||
deletedByAge = len(deleted)
|
||||
deletedByAge = nbDeleted
|
||||
}
|
||||
if MaxItems > 0 {
|
||||
if totalAlerts > MaxItems {
|
||||
|
@ -563,8 +563,13 @@ func (c *Client) FlushAlerts(MaxAge string, MaxItems int) error {
|
|||
func (c *Client) GetAlertByID(alertID int) (*ent.Alert, error) {
|
||||
alert, err := c.Ent.Alert.Query().Where(alert.IDEQ(alertID)).WithDecisions().WithEvents().WithMetas().WithOwner().First(c.CTX)
|
||||
if err != nil {
|
||||
/*record not found, 404*/
|
||||
if ent.IsNotFound(err) {
|
||||
log.Warningf("GetAlertByID (not found): %s", err)
|
||||
return &ent.Alert{}, ItemNotFound
|
||||
}
|
||||
log.Warningf("GetAlertByID : %s", err)
|
||||
return &ent.Alert{}, errors.Wrapf(QueryFail, "alert id '%d'", alertID)
|
||||
return &ent.Alert{}, QueryFail
|
||||
}
|
||||
return alert, nil
|
||||
}
|
||||
|
|
|
@ -278,5 +278,9 @@ func (c *Client) SoftDeleteDecisionByID(decisionID int) error {
|
|||
log.Warningf("SoftDeleteDecisionByID : %v (nb soft deleted: %d)", err, nbUpdated)
|
||||
return errors.Wrapf(DeleteFail, "decision with id '%d' doesn't exist", decisionID)
|
||||
}
|
||||
|
||||
if nbUpdated == 0 {
|
||||
return ItemNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ var (
|
|||
QueryFail = errors.New("unable to query")
|
||||
UpdateFail = errors.New("unable to update")
|
||||
DeleteFail = errors.New("unable to delete")
|
||||
ItemNotFound = errors.New("object not found")
|
||||
ParseTimeFail = errors.New("unable to parse time")
|
||||
ParseDurationFail = errors.New("unable to parse duration")
|
||||
MarshalFail = errors.New("unable to marshal")
|
||||
|
|
|
@ -267,8 +267,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/definitions/WatcherRegistrationRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Watcher registered
|
||||
'201':
|
||||
description: Watcher Created
|
||||
headers: {}
|
||||
'400':
|
||||
description: "400 response"
|
||||
|
@ -322,8 +322,8 @@ paths:
|
|||
schema:
|
||||
$ref: '#/definitions/AddAlertsRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
'201':
|
||||
description: Alert(s) created
|
||||
schema:
|
||||
$ref: '#/definitions/AddAlertsResponse'
|
||||
headers: {}
|
||||
|
|
Loading…
Reference in a new issue