github.com/crowdsecurity/crowdsec@v1.6.1/pkg/apiclient/alerts_service_test.go (about) 1 package apiclient 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 "net/url" 8 "testing" 9 10 log "github.com/sirupsen/logrus" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 "github.com/crowdsecurity/go-cs-lib/cstest" 15 "github.com/crowdsecurity/go-cs-lib/ptr" 16 "github.com/crowdsecurity/go-cs-lib/version" 17 18 "github.com/crowdsecurity/crowdsec/pkg/models" 19 ) 20 21 func TestAlertsListAsMachine(t *testing.T) { 22 log.SetLevel(log.DebugLevel) 23 24 mux, urlx, teardown := setup() 25 mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) { 26 w.WriteHeader(http.StatusOK) 27 w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`)) 28 }) 29 30 log.Printf("URL is %s", urlx) 31 32 apiURL, err := url.Parse(urlx + "/") 33 require.NoError(t, err) 34 35 client, err := NewClient(&Config{ 36 MachineID: "test_login", 37 Password: "test_password", 38 UserAgent: fmt.Sprintf("crowdsec/%s", version.String()), 39 URL: apiURL, 40 VersionPrefix: "v1", 41 }) 42 require.NoError(t, err) 43 44 defer teardown() 45 46 mux.HandleFunc("/alerts", func(w http.ResponseWriter, r *http.Request) { 47 if r.URL.RawQuery == "ip=1.2.3.4" { 48 testMethod(t, r, "GET") 49 w.WriteHeader(http.StatusOK) 50 fmt.Fprintf(w, `null`) 51 52 return 53 } 54 55 testMethod(t, r, "GET") 56 w.WriteHeader(http.StatusOK) 57 fmt.Fprint(w, `[ 58 {"capacity":5,"created_at":"2020-11-28T10:20:47+01:00", 59 "decisions":[ 60 {"duration":"59m49.264032632s", 61 "id":1, 62 "origin":"crowdsec", 63 "scenario":"crowdsecurity/ssh-bf", 64 "scope":"Ip", 65 "simulated":false, 66 "type":"ban", 67 "value":"1.1.1.172"} 68 ], 69 "events":[ 70 {"meta":[ 71 {"key":"target_user","value":"netflix"}, 72 {"key":"service","value":"ssh"} 73 ], 74 "timestamp":"2020-11-28 10:20:46 +0000 UTC"}, 75 {"meta":[ 76 {"key":"target_user","value":"netflix"}, 77 {"key":"service","value":"ssh"} 78 ], 79 "timestamp":"2020-11-28 10:20:46 +0000 UTC"} 80 ], 81 "events_count":6, 82 "id":1, 83 "labels":null, 84 "leakspeed":"10s", 85 "machine_id":"test", 86 "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", 87 "scenario":"crowdsecurity/ssh-bf", 88 "scenario_hash":"4441dcff07020f6690d998b7101e642359ba405c2abb83565bbbdcee36de280f", 89 "scenario_version":"0.1", 90 "simulated":false, 91 "source":{ 92 "as_name":"Cloudflare Inc", 93 "cn":"AU", 94 "ip":"1.1.1.172", 95 "latitude":-37.7, 96 "longitude":145.1833, 97 "range":"1.1.1.0/24", 98 "scope":"Ip", 99 "value":"1.1.1.172" 100 }, 101 "start_at":"2020-11-28 10:20:46.842701127 +0100 +0100", 102 "stop_at":"2020-11-28 10:20:46.845621385 +0100 +0100" 103 } 104 ]`) 105 }) 106 107 tscenario := "crowdsecurity/ssh-bf" 108 tscope := "Ip" 109 tvalue := "1.1.1.172" 110 ttimestamp := "2020-11-28 10:20:46 +0000 UTC" 111 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" 112 113 expected := models.GetAlertsResponse{ 114 &models.Alert{ 115 Capacity: ptr.Of(int32(5)), 116 CreatedAt: "2020-11-28T10:20:47+01:00", 117 Decisions: []*models.Decision{ 118 { 119 Duration: ptr.Of("59m49.264032632s"), 120 ID: 1, 121 Origin: ptr.Of("crowdsec"), 122 Scenario: &tscenario, 123 124 Scope: &tscope, 125 Simulated: ptr.Of(false), 126 Type: ptr.Of("ban"), 127 Value: &tvalue, 128 }, 129 }, 130 Events: []*models.Event{ 131 { 132 Meta: models.Meta{ 133 &models.MetaItems0{ 134 Key: "target_user", 135 Value: "netflix", 136 }, 137 &models.MetaItems0{ 138 Key: "service", 139 Value: "ssh", 140 }, 141 }, 142 Timestamp: &ttimestamp, 143 }, { 144 Meta: models.Meta{ 145 &models.MetaItems0{ 146 Key: "target_user", 147 Value: "netflix", 148 }, 149 &models.MetaItems0{ 150 Key: "service", 151 Value: "ssh", 152 }, 153 }, 154 Timestamp: &ttimestamp, 155 }, 156 }, 157 EventsCount: ptr.Of(int32(6)), 158 ID: 1, 159 Leakspeed: ptr.Of("10s"), 160 MachineID: "test", 161 Message: &tmessage, 162 Remediation: false, 163 Scenario: &tscenario, 164 ScenarioHash: ptr.Of("4441dcff07020f6690d998b7101e642359ba405c2abb83565bbbdcee36de280f"), 165 ScenarioVersion: ptr.Of("0.1"), 166 Simulated: ptr.Of(false), 167 Source: &models.Source{ 168 AsName: "Cloudflare Inc", 169 AsNumber: "", 170 Cn: "AU", 171 IP: "1.1.1.172", 172 Latitude: -37.7, 173 Longitude: 145.1833, 174 Range: "1.1.1.0/24", 175 Scope: &tscope, 176 Value: &tvalue, 177 }, 178 StartAt: ptr.Of("2020-11-28 10:20:46.842701127 +0100 +0100"), 179 StopAt: ptr.Of("2020-11-28 10:20:46.845621385 +0100 +0100"), 180 }, 181 } 182 183 //log.Debugf("data : -> %s", spew.Sdump(alerts)) 184 //log.Debugf("resp : -> %s", spew.Sdump(resp)) 185 //log.Debugf("expected : -> %s", spew.Sdump(expected)) 186 //first one returns data 187 alerts, resp, err := client.Alerts.List(context.Background(), AlertsListOpts{}) 188 require.NoError(t, err) 189 assert.Equal(t, http.StatusOK, resp.Response.StatusCode) 190 assert.Equal(t, expected, *alerts) 191 192 //this one doesn't 193 filter := AlertsListOpts{IPEquals: ptr.Of("1.2.3.4")} 194 195 alerts, resp, err = client.Alerts.List(context.Background(), filter) 196 require.NoError(t, err) 197 assert.Equal(t, http.StatusOK, resp.Response.StatusCode) 198 assert.Empty(t, *alerts) 199 } 200 201 func TestAlertsGetAsMachine(t *testing.T) { 202 log.SetLevel(log.DebugLevel) 203 204 mux, urlx, teardown := setup() 205 mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) { 206 w.WriteHeader(http.StatusOK) 207 w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`)) 208 }) 209 log.Printf("URL is %s", urlx) 210 211 apiURL, err := url.Parse(urlx + "/") 212 require.NoError(t, err) 213 214 client, err := NewClient(&Config{ 215 MachineID: "test_login", 216 Password: "test_password", 217 UserAgent: fmt.Sprintf("crowdsec/%s", version.String()), 218 URL: apiURL, 219 VersionPrefix: "v1", 220 }) 221 require.NoError(t, err) 222 223 defer teardown() 224 225 mux.HandleFunc("/alerts/2", func(w http.ResponseWriter, r *http.Request) { 226 testMethod(t, r, "GET") 227 w.WriteHeader(http.StatusNotFound) 228 fmt.Fprintf(w, `{"message":"object not found"}`) 229 }) 230 231 mux.HandleFunc("/alerts/1", func(w http.ResponseWriter, r *http.Request) { 232 testMethod(t, r, "GET") 233 w.WriteHeader(http.StatusOK) 234 fmt.Fprint(w, `{"capacity":5,"created_at":"2020-11-28T10:20:47+01:00", 235 "decisions":[ 236 {"duration":"59m49.264032632s", 237 "end_ip":16843180, 238 "id":1, 239 "origin":"crowdsec", 240 "scenario":"crowdsecurity/ssh-bf", 241 "scope":"Ip", 242 "simulated":false, 243 "start_ip":16843180, 244 "type":"ban", 245 "value":"1.1.1.172"} 246 ], 247 "events":[ 248 {"meta":[ 249 {"key":"target_user","value":"netflix"}, 250 {"key":"service","value":"ssh"} 251 ], 252 "timestamp":"2020-11-28 10:20:46 +0000 UTC"}, 253 {"meta":[ 254 {"key":"target_user","value":"netflix"}, 255 {"key":"service","value":"ssh"} 256 ], 257 "timestamp":"2020-11-28 10:20:46 +0000 UTC"} 258 ], 259 "events_count":6, 260 "id":1, 261 "labels":null, 262 "leakspeed":"10s", 263 "machine_id":"test", 264 "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", 265 "scenario":"crowdsecurity/ssh-bf", 266 "scenario_hash":"4441dcff07020f6690d998b7101e642359ba405c2abb83565bbbdcee36de280f", 267 "scenario_version":"0.1", 268 "simulated":false, 269 "source":{ 270 "as_name":"Cloudflare Inc", 271 "cn":"AU", 272 "ip":"1.1.1.172", 273 "latitude":-37.7, 274 "longitude":145.1833, 275 "range":"1.1.1.0/24", 276 "scope":"Ip", 277 "value":"1.1.1.172" 278 }, 279 "start_at":"2020-11-28 10:20:46.842701127 +0100 +0100", 280 "stop_at":"2020-11-28 10:20:46.845621385 +0100 +0100" 281 }`) 282 }) 283 284 tscenario := "crowdsecurity/ssh-bf" 285 tscope := "Ip" 286 ttype := "ban" 287 tvalue := "1.1.1.172" 288 ttimestamp := "2020-11-28 10:20:46 +0000 UTC" 289 290 expected := &models.Alert{ 291 Capacity: ptr.Of(int32(5)), 292 CreatedAt: "2020-11-28T10:20:47+01:00", 293 Decisions: []*models.Decision{ 294 { 295 Duration: ptr.Of("59m49.264032632s"), 296 ID: 1, 297 Origin: ptr.Of("crowdsec"), 298 Scenario: &tscenario, 299 300 Scope: &tscope, 301 Simulated: ptr.Of(false), 302 Type: &ttype, 303 Value: &tvalue, 304 }, 305 }, 306 Events: []*models.Event{ 307 { 308 Meta: models.Meta{ 309 &models.MetaItems0{ 310 Key: "target_user", 311 Value: "netflix", 312 }, 313 &models.MetaItems0{ 314 Key: "service", 315 Value: "ssh", 316 }, 317 }, 318 Timestamp: &ttimestamp, 319 }, { 320 Meta: models.Meta{ 321 &models.MetaItems0{ 322 Key: "target_user", 323 Value: "netflix", 324 }, 325 &models.MetaItems0{ 326 Key: "service", 327 Value: "ssh", 328 }, 329 }, 330 Timestamp: &ttimestamp, 331 }, 332 }, 333 EventsCount: ptr.Of(int32(6)), 334 ID: 1, 335 Leakspeed: ptr.Of("10s"), 336 MachineID: "test", 337 Message: ptr.Of("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"), 338 Remediation: false, 339 Scenario: &tscenario, 340 ScenarioHash: ptr.Of("4441dcff07020f6690d998b7101e642359ba405c2abb83565bbbdcee36de280f"), 341 ScenarioVersion: ptr.Of("0.1"), 342 Simulated: ptr.Of(false), 343 Source: &models.Source{ 344 AsName: "Cloudflare Inc", 345 AsNumber: "", 346 Cn: "AU", 347 IP: "1.1.1.172", 348 Latitude: -37.7, 349 Longitude: 145.1833, 350 Range: "1.1.1.0/24", 351 Scope: &tscope, 352 Value: &tvalue, 353 }, 354 StartAt: ptr.Of("2020-11-28 10:20:46.842701127 +0100 +0100"), 355 StopAt: ptr.Of("2020-11-28 10:20:46.845621385 +0100 +0100"), 356 } 357 358 alerts, resp, err := client.Alerts.GetByID(context.Background(), 1) 359 require.NoError(t, err) 360 assert.Equal(t, http.StatusOK, resp.Response.StatusCode) 361 assert.Equal(t, *expected, *alerts) 362 363 //fail 364 _, _, err = client.Alerts.GetByID(context.Background(), 2) 365 cstest.RequireErrorMessage(t, err, "API error: object not found") 366 } 367 368 func TestAlertsCreateAsMachine(t *testing.T) { 369 log.SetLevel(log.DebugLevel) 370 371 mux, urlx, teardown := setup() 372 mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) { 373 w.WriteHeader(http.StatusOK) 374 w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`)) 375 }) 376 377 mux.HandleFunc("/alerts", func(w http.ResponseWriter, r *http.Request) { 378 testMethod(t, r, "POST") 379 w.WriteHeader(http.StatusOK) 380 w.Write([]byte(`["3"]`)) 381 }) 382 383 log.Printf("URL is %s", urlx) 384 385 apiURL, err := url.Parse(urlx + "/") 386 require.NoError(t, err) 387 388 client, err := NewClient(&Config{ 389 MachineID: "test_login", 390 Password: "test_password", 391 UserAgent: fmt.Sprintf("crowdsec/%s", version.String()), 392 URL: apiURL, 393 VersionPrefix: "v1", 394 }) 395 require.NoError(t, err) 396 397 defer teardown() 398 399 alert := models.AddAlertsRequest{} 400 alerts, resp, err := client.Alerts.Add(context.Background(), alert) 401 require.NoError(t, err) 402 403 expected := &models.AddAlertsResponse{"3"} 404 405 assert.Equal(t, http.StatusOK, resp.Response.StatusCode) 406 assert.Equal(t, *expected, *alerts) 407 } 408 409 func TestAlertsDeleteAsMachine(t *testing.T) { 410 log.SetLevel(log.DebugLevel) 411 412 mux, urlx, teardown := setup() 413 mux.HandleFunc("/watchers/login", func(w http.ResponseWriter, r *http.Request) { 414 w.WriteHeader(http.StatusOK) 415 w.Write([]byte(`{"code": 200, "expire": "2030-01-02T15:04:05Z", "token": "oklol"}`)) 416 }) 417 418 mux.HandleFunc("/alerts", func(w http.ResponseWriter, r *http.Request) { 419 testMethod(t, r, "DELETE") 420 assert.Equal(t, "ip=1.2.3.4", r.URL.RawQuery) 421 w.WriteHeader(http.StatusOK) 422 w.Write([]byte(`{"message":"0 deleted alerts"}`)) 423 }) 424 425 log.Printf("URL is %s", urlx) 426 427 apiURL, err := url.Parse(urlx + "/") 428 require.NoError(t, err) 429 430 client, err := NewClient(&Config{ 431 MachineID: "test_login", 432 Password: "test_password", 433 UserAgent: fmt.Sprintf("crowdsec/%s", version.String()), 434 URL: apiURL, 435 VersionPrefix: "v1", 436 }) 437 require.NoError(t, err) 438 439 defer teardown() 440 441 alert := AlertsDeleteOpts{IPEquals: ptr.Of("1.2.3.4")} 442 alerts, resp, err := client.Alerts.Delete(context.Background(), alert) 443 require.NoError(t, err) 444 445 expected := &models.DeleteAlertsResponse{NbDeleted: ""} 446 447 assert.Equal(t, http.StatusOK, resp.Response.StatusCode) 448 assert.Equal(t, *expected, *alerts) 449 }