bitbucket.org/Aishee/synsec@v0.0.0-20210414005726-236fc01a153d/pkg/apiclient/alerts_service_test.go (about)

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