mirror of
https://github.com/crowdsecurity/crowdsec.git
synced 2025-05-11 12:25:53 +02:00
cscli refact: package clialert, clidecision (#3203)
* cscli refact: package clialert, clidecision * refact: function SanitizeScope() * lint
This commit is contained in:
parent
5a50fd06bb
commit
bc6be99b97
11 changed files with 98 additions and 89 deletions
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package clialert
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/cstable"
|
||||
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/apiclient"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwversion"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
|
@ -183,12 +184,14 @@ func (cli *cliAlerts) displayOneAlert(alert *models.Alert, withDetail bool) erro
|
|||
return nil
|
||||
}
|
||||
|
||||
type configGetter func() *csconfig.Config
|
||||
|
||||
type cliAlerts struct {
|
||||
client *apiclient.ApiClient
|
||||
cfg configGetter
|
||||
}
|
||||
|
||||
func NewCLIAlerts(getconfig configGetter) *cliAlerts {
|
||||
func New(getconfig configGetter) *cliAlerts {
|
||||
return &cliAlerts{
|
||||
cfg: getconfig,
|
||||
}
|
||||
|
@ -235,8 +238,10 @@ func (cli *cliAlerts) NewCommand() *cobra.Command {
|
|||
}
|
||||
|
||||
func (cli *cliAlerts) list(alertListFilter apiclient.AlertsListOpts, limit *int, contained *bool, printMachine bool) error {
|
||||
if err := manageCliDecisionAlerts(alertListFilter.IPEquals, alertListFilter.RangeEquals,
|
||||
alertListFilter.ScopeEquals, alertListFilter.ValueEquals); err != nil {
|
||||
var err error
|
||||
|
||||
*alertListFilter.ScopeEquals, err = SanitizeScope(*alertListFilter.ScopeEquals, *alertListFilter.IPEquals, *alertListFilter.RangeEquals)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -378,8 +383,8 @@ func (cli *cliAlerts) delete(alertDeleteFilter apiclient.AlertsDeleteOpts, Activ
|
|||
var err error
|
||||
|
||||
if !AlertDeleteAll {
|
||||
if err = manageCliDecisionAlerts(alertDeleteFilter.IPEquals, alertDeleteFilter.RangeEquals,
|
||||
alertDeleteFilter.ScopeEquals, alertDeleteFilter.ValueEquals); err != nil {
|
||||
*alertDeleteFilter.ScopeEquals, err = SanitizeScope(*alertDeleteFilter.ScopeEquals, *alertDeleteFilter.IPEquals, *alertDeleteFilter.RangeEquals)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
26
cmd/crowdsec-cli/clialert/sanitize.go
Normal file
26
cmd/crowdsec-cli/clialert/sanitize.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package clialert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
)
|
||||
|
||||
// SanitizeScope validates ip and range and sets the scope accordingly to our case convention.
|
||||
func SanitizeScope(scope, ip, ipRange string) (string, error) {
|
||||
if ipRange != "" {
|
||||
_, _, err := net.ParseCIDR(ipRange)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s is not a valid range", ipRange)
|
||||
}
|
||||
}
|
||||
|
||||
if ip != "" {
|
||||
if net.ParseIP(ip) == nil {
|
||||
return "", fmt.Errorf("%s is not a valid ip", ip)
|
||||
}
|
||||
}
|
||||
|
||||
return types.NormalizeScope(scope), nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package clialert
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package clidecision
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -17,7 +17,9 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/clialert"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/apiclient"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/cwversion"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
|
@ -114,12 +116,14 @@ func (cli *cliDecisions) decisionsToTable(alerts *models.GetAlertsResponse, prin
|
|||
return nil
|
||||
}
|
||||
|
||||
type configGetter func() *csconfig.Config
|
||||
|
||||
type cliDecisions struct {
|
||||
client *apiclient.ApiClient
|
||||
cfg configGetter
|
||||
}
|
||||
|
||||
func NewCLIDecisions(cfg configGetter) *cliDecisions {
|
||||
func New(cfg configGetter) *cliDecisions {
|
||||
return &cliDecisions{
|
||||
cfg: cfg,
|
||||
}
|
||||
|
@ -170,8 +174,9 @@ func (cli *cliDecisions) NewCommand() *cobra.Command {
|
|||
|
||||
func (cli *cliDecisions) list(filter apiclient.AlertsListOpts, NoSimu *bool, contained *bool, printMachine bool) error {
|
||||
var err error
|
||||
/*take care of shorthand options*/
|
||||
if err = manageCliDecisionAlerts(filter.IPEquals, filter.RangeEquals, filter.ScopeEquals, filter.ValueEquals); err != nil {
|
||||
|
||||
*filter.ScopeEquals, err = clialert.SanitizeScope(*filter.ScopeEquals, *filter.IPEquals, *filter.RangeEquals)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -326,8 +331,10 @@ func (cli *cliDecisions) add(addIP, addRange, addDuration, addValue, addScope, a
|
|||
stopAt := time.Now().UTC().Format(time.RFC3339)
|
||||
createdAt := time.Now().UTC().Format(time.RFC3339)
|
||||
|
||||
/*take care of shorthand options*/
|
||||
if err := manageCliDecisionAlerts(&addIP, &addRange, &addScope, &addValue); err != nil {
|
||||
var err error
|
||||
|
||||
addScope, err = clialert.SanitizeScope(addScope, addIP, addRange)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -381,7 +388,7 @@ func (cli *cliDecisions) add(addIP, addRange, addDuration, addValue, addScope, a
|
|||
}
|
||||
alerts = append(alerts, &alert)
|
||||
|
||||
_, _, err := cli.client.Alerts.Add(context.Background(), alerts)
|
||||
_, _, err = cli.client.Alerts.Add(context.Background(), alerts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -435,7 +442,8 @@ func (cli *cliDecisions) delete(delFilter apiclient.DecisionsDeleteOpts, delDeci
|
|||
var err error
|
||||
|
||||
/*take care of shorthand options*/
|
||||
if err = manageCliDecisionAlerts(delFilter.IPEquals, delFilter.RangeEquals, delFilter.ScopeEquals, delFilter.ValueEquals); err != nil {
|
||||
*delFilter.ScopeEquals, err = clialert.SanitizeScope(*delFilter.ScopeEquals, *delFilter.IPEquals, *delFilter.RangeEquals)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package clidecision
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
@ -122,8 +122,8 @@ func (cli *cliDecisions) runImport(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
|
||||
var (
|
||||
content []byte
|
||||
fin *os.File
|
||||
content []byte
|
||||
fin *os.File
|
||||
)
|
||||
|
||||
// set format if the file has a json or csv extension
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package clidecision
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -14,9 +14,11 @@ import (
|
|||
|
||||
"github.com/crowdsecurity/go-cs-lib/trace"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/clialert"
|
||||
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/clibouncer"
|
||||
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/clicapi"
|
||||
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/cliconsole"
|
||||
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/clidecision"
|
||||
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/cliexplain"
|
||||
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/clihub"
|
||||
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/clihubtest"
|
||||
|
@ -257,8 +259,8 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
|
|||
cmd.AddCommand(clihub.New(cli.cfg).NewCommand())
|
||||
cmd.AddCommand(climetrics.New(cli.cfg).NewCommand())
|
||||
cmd.AddCommand(NewCLIDashboard(cli.cfg).NewCommand())
|
||||
cmd.AddCommand(NewCLIDecisions(cli.cfg).NewCommand())
|
||||
cmd.AddCommand(NewCLIAlerts(cli.cfg).NewCommand())
|
||||
cmd.AddCommand(clidecision.New(cli.cfg).NewCommand())
|
||||
cmd.AddCommand(clialert.New(cli.cfg).NewCommand())
|
||||
cmd.AddCommand(clisimulation.New(cli.cfg).NewCommand())
|
||||
cmd.AddCommand(clibouncer.New(cli.cfg).NewCommand())
|
||||
cmd.AddCommand(climachine.New(cli.cfg).NewCommand())
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
)
|
||||
|
||||
func manageCliDecisionAlerts(ip *string, ipRange *string, scope *string, value *string) error {
|
||||
/*if a range is provided, change the scope*/
|
||||
if *ipRange != "" {
|
||||
_, _, err := net.ParseCIDR(*ipRange)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s isn't a valid range", *ipRange)
|
||||
}
|
||||
}
|
||||
|
||||
if *ip != "" {
|
||||
ipRepr := net.ParseIP(*ip)
|
||||
if ipRepr == nil {
|
||||
return fmt.Errorf("%s isn't a valid ip", *ip)
|
||||
}
|
||||
}
|
||||
|
||||
// avoid confusion on scope (ip vs Ip and range vs Range)
|
||||
switch strings.ToLower(*scope) {
|
||||
case "ip":
|
||||
*scope = types.Ip
|
||||
case "range":
|
||||
*scope = types.Range
|
||||
case "country":
|
||||
*scope = types.Country
|
||||
case "as":
|
||||
*scope = types.AS
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
@ -124,21 +123,6 @@ func (c *Controller) sendAlertToPluginChannel(alert *models.Alert, profileID uin
|
|||
}
|
||||
}
|
||||
|
||||
func normalizeScope(scope string) string {
|
||||
switch strings.ToLower(scope) {
|
||||
case "ip":
|
||||
return types.Ip
|
||||
case "range":
|
||||
return types.Range
|
||||
case "as":
|
||||
return types.AS
|
||||
case "country":
|
||||
return types.Country
|
||||
default:
|
||||
return scope
|
||||
}
|
||||
}
|
||||
|
||||
// CreateAlert writes the alerts received in the body to the database
|
||||
func (c *Controller) CreateAlert(gctx *gin.Context) {
|
||||
var input models.AddAlertsRequest
|
||||
|
@ -160,12 +144,12 @@ func (c *Controller) CreateAlert(gctx *gin.Context) {
|
|||
for _, alert := range input {
|
||||
// normalize scope for alert.Source and decisions
|
||||
if alert.Source.Scope != nil {
|
||||
*alert.Source.Scope = normalizeScope(*alert.Source.Scope)
|
||||
*alert.Source.Scope = types.NormalizeScope(*alert.Source.Scope)
|
||||
}
|
||||
|
||||
for _, decision := range alert.Decisions {
|
||||
if decision.Scope != nil {
|
||||
*decision.Scope = normalizeScope(*decision.Scope)
|
||||
*decision.Scope = types.NormalizeScope(*decision.Scope)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,8 +280,8 @@ func (c *Controller) FindAlerts(gctx *gin.Context) {
|
|||
// FindAlertByID returns the alert associated with the ID
|
||||
func (c *Controller) FindAlertByID(gctx *gin.Context) {
|
||||
alertIDStr := gctx.Param("alert_id")
|
||||
alertID, err := strconv.Atoi(alertIDStr)
|
||||
|
||||
alertID, err := strconv.Atoi(alertIDStr)
|
||||
if err != nil {
|
||||
gctx.JSON(http.StatusBadRequest, gin.H{"message": "alert_id must be valid integer"})
|
||||
return
|
||||
|
|
|
@ -2,6 +2,7 @@ package types
|
|||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/expr-lang/expr/vm"
|
||||
|
@ -19,11 +20,11 @@ const (
|
|||
// Event is the structure representing a runtime event (log or overflow)
|
||||
type Event struct {
|
||||
/* is it a log or an overflow */
|
||||
Type int `yaml:"Type,omitempty" json:"Type,omitempty"` //Can be types.LOG (0) or types.OVFLOW (1)
|
||||
ExpectMode int `yaml:"ExpectMode,omitempty" json:"ExpectMode,omitempty"` //how to buckets should handle event : types.TIMEMACHINE or types.LIVE
|
||||
Type int `yaml:"Type,omitempty" json:"Type,omitempty"` // Can be types.LOG (0) or types.OVFLOW (1)
|
||||
ExpectMode int `yaml:"ExpectMode,omitempty" json:"ExpectMode,omitempty"` // how to buckets should handle event : types.TIMEMACHINE or types.LIVE
|
||||
Whitelisted bool `yaml:"Whitelisted,omitempty" json:"Whitelisted,omitempty"`
|
||||
WhitelistReason string `yaml:"WhitelistReason,omitempty" json:"whitelist_reason,omitempty"`
|
||||
//should add whitelist reason ?
|
||||
// should add whitelist reason ?
|
||||
/* the current stage of the line being parsed */
|
||||
Stage string `yaml:"Stage,omitempty" json:"Stage,omitempty"`
|
||||
/* original line (produced by acquisition) */
|
||||
|
@ -36,11 +37,11 @@ type Event struct {
|
|||
Unmarshaled map[string]interface{} `yaml:"Unmarshaled,omitempty" json:"Unmarshaled,omitempty"`
|
||||
/* Overflow */
|
||||
Overflow RuntimeAlert `yaml:"Overflow,omitempty" json:"Alert,omitempty"`
|
||||
Time time.Time `yaml:"Time,omitempty" json:"Time,omitempty"` //parsed time `json:"-"` ``
|
||||
Time time.Time `yaml:"Time,omitempty" json:"Time,omitempty"` // parsed time `json:"-"` ``
|
||||
StrTime string `yaml:"StrTime,omitempty" json:"StrTime,omitempty"`
|
||||
StrTimeFormat string `yaml:"StrTimeFormat,omitempty" json:"StrTimeFormat,omitempty"`
|
||||
MarshaledTime string `yaml:"MarshaledTime,omitempty" json:"MarshaledTime,omitempty"`
|
||||
Process bool `yaml:"Process,omitempty" json:"Process,omitempty"` //can be set to false to avoid processing line
|
||||
Process bool `yaml:"Process,omitempty" json:"Process,omitempty"` // can be set to false to avoid processing line
|
||||
Appsec AppsecEvent `yaml:"Appsec,omitempty" json:"Appsec,omitempty"`
|
||||
/* Meta is the only part that will make it to the API - it should be normalized */
|
||||
Meta map[string]string `yaml:"Meta,omitempty" json:"Meta,omitempty"`
|
||||
|
@ -50,7 +51,9 @@ func (e *Event) SetMeta(key string, value string) bool {
|
|||
if e.Meta == nil {
|
||||
e.Meta = make(map[string]string)
|
||||
}
|
||||
|
||||
e.Meta[key] = value
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -58,7 +61,9 @@ func (e *Event) SetParsed(key string, value string) bool {
|
|||
if e.Parsed == nil {
|
||||
e.Parsed = make(map[string]string)
|
||||
}
|
||||
|
||||
e.Parsed[key] = value
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -90,11 +95,13 @@ func (e *Event) GetMeta(key string) string {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e *Event) ParseIPSources() []net.IP {
|
||||
var srcs []net.IP
|
||||
|
||||
switch e.Type {
|
||||
case LOG:
|
||||
if _, ok := e.Meta["source_ip"]; ok {
|
||||
|
@ -105,6 +112,7 @@ func (e *Event) ParseIPSources() []net.IP {
|
|||
srcs = append(srcs, net.ParseIP(k))
|
||||
}
|
||||
}
|
||||
|
||||
return srcs
|
||||
}
|
||||
|
||||
|
@ -131,8 +139,8 @@ type RuntimeAlert struct {
|
|||
Whitelisted bool `yaml:"Whitelisted,omitempty" json:"Whitelisted,omitempty"`
|
||||
Reprocess bool `yaml:"Reprocess,omitempty" json:"Reprocess,omitempty"`
|
||||
Sources map[string]models.Source `yaml:"Sources,omitempty" json:"Sources,omitempty"`
|
||||
Alert *models.Alert `yaml:"Alert,omitempty" json:"Alert,omitempty"` //this one is a pointer to APIAlerts[0] for convenience.
|
||||
//APIAlerts will be populated at the end when there is more than one source
|
||||
Alert *models.Alert `yaml:"Alert,omitempty" json:"Alert,omitempty"` // this one is a pointer to APIAlerts[0] for convenience.
|
||||
// APIAlerts will be populated at the end when there is more than one source
|
||||
APIAlerts []models.Alert `yaml:"APIAlerts,omitempty" json:"APIAlerts,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -141,5 +149,21 @@ func (r RuntimeAlert) GetSources() []string {
|
|||
for key := range r.Sources {
|
||||
ret = append(ret, key)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func NormalizeScope(scope string) string {
|
||||
switch strings.ToLower(scope) {
|
||||
case "ip":
|
||||
return Ip
|
||||
case "range":
|
||||
return Range
|
||||
case "as":
|
||||
return AS
|
||||
case "country":
|
||||
return Country
|
||||
default:
|
||||
return scope
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,12 +108,12 @@ teardown() {
|
|||
# invalid json
|
||||
rune -1 cscli decisions import -i - <<<'{"blah":"blah"}' --format json
|
||||
assert_stderr --partial 'Parsing json'
|
||||
assert_stderr --partial 'json: cannot unmarshal object into Go value of type []main.decisionRaw'
|
||||
assert_stderr --partial 'json: cannot unmarshal object into Go value of type []clidecision.decisionRaw'
|
||||
|
||||
# json with extra data
|
||||
rune -1 cscli decisions import -i - <<<'{"values":"1.2.3.4","blah":"blah"}' --format json
|
||||
assert_stderr --partial 'Parsing json'
|
||||
assert_stderr --partial 'json: cannot unmarshal object into Go value of type []main.decisionRaw'
|
||||
assert_stderr --partial 'json: cannot unmarshal object into Go value of type []clidecision.decisionRaw'
|
||||
|
||||
#----------
|
||||
# CSV
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue