Compare commits
12 commits
master
...
cti-swagge
Author | SHA1 | Date | |
---|---|---|---|
|
d36425e471 | ||
|
b210b0f233 | ||
|
06e9ca4e4a | ||
|
f91e329efc | ||
|
3cb4a4c8d1 | ||
|
764bef719b | ||
|
5c6bddc070 | ||
|
75ff4e1e31 | ||
|
084c01ddc7 | ||
|
f82c5f34d3 | ||
|
0be5fbb07a | ||
|
4ecefdd849 |
21 changed files with 2444 additions and 138 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -42,6 +42,7 @@ vendor.tgz
|
||||||
cmd/crowdsec-cli/cscli
|
cmd/crowdsec-cli/cscli
|
||||||
cmd/crowdsec/crowdsec
|
cmd/crowdsec/crowdsec
|
||||||
cmd/notification-*/notification-*
|
cmd/notification-*/notification-*
|
||||||
|
cmd/cscti/cscti
|
||||||
|
|
||||||
# Test cache (downloaded files)
|
# Test cache (downloaded files)
|
||||||
.cache
|
.cache
|
||||||
|
|
|
@ -4,6 +4,8 @@ run:
|
||||||
skip-dirs:
|
skip-dirs:
|
||||||
- pkg/time/rate
|
- pkg/time/rate
|
||||||
skip-files:
|
skip-files:
|
||||||
|
- pkg/cti/client.go
|
||||||
|
- pkg/cti/types.go
|
||||||
- pkg/database/ent/generate.go
|
- pkg/database/ent/generate.go
|
||||||
- pkg/yamlpatch/merge.go
|
- pkg/yamlpatch/merge.go
|
||||||
- pkg/yamlpatch/merge_test.go
|
- pkg/yamlpatch/merge_test.go
|
||||||
|
|
7
Makefile
7
Makefile
|
@ -38,6 +38,7 @@ BUILD_CODENAME ?= alphaga
|
||||||
|
|
||||||
CROWDSEC_FOLDER = ./cmd/crowdsec
|
CROWDSEC_FOLDER = ./cmd/crowdsec
|
||||||
CSCLI_FOLDER = ./cmd/crowdsec-cli/
|
CSCLI_FOLDER = ./cmd/crowdsec-cli/
|
||||||
|
CSCTI_FOLDER = ./cmd/cscti/
|
||||||
PLUGINS_DIR_PREFIX = ./cmd/notification-
|
PLUGINS_DIR_PREFIX = ./cmd/notification-
|
||||||
|
|
||||||
CROWDSEC_BIN = crowdsec$(EXT)
|
CROWDSEC_BIN = crowdsec$(EXT)
|
||||||
|
@ -198,6 +199,10 @@ clean: clean-debian clean-rpm testclean ## Remove build artifacts
|
||||||
cscli: goversion ## Build cscli
|
cscli: goversion ## Build cscli
|
||||||
@$(MAKE) -C $(CSCLI_FOLDER) build $(MAKE_FLAGS)
|
@$(MAKE) -C $(CSCLI_FOLDER) build $(MAKE_FLAGS)
|
||||||
|
|
||||||
|
.PHONY: cscti
|
||||||
|
cscti: goversion ## Build cscti
|
||||||
|
@$(MAKE) -C $(CSCTI_FOLDER) build $(MAKE_FLAGS)
|
||||||
|
|
||||||
.PHONY: crowdsec
|
.PHONY: crowdsec
|
||||||
crowdsec: goversion ## Build crowdsec
|
crowdsec: goversion ## Build crowdsec
|
||||||
@$(MAKE) -C $(CROWDSEC_FOLDER) build $(MAKE_FLAGS)
|
@$(MAKE) -C $(CROWDSEC_FOLDER) build $(MAKE_FLAGS)
|
||||||
|
@ -206,6 +211,8 @@ crowdsec: goversion ## Build crowdsec
|
||||||
generate: ## Generate code for the database and APIs
|
generate: ## Generate code for the database and APIs
|
||||||
$(GO) generate ./pkg/database/ent
|
$(GO) generate ./pkg/database/ent
|
||||||
$(GO) generate ./pkg/models
|
$(GO) generate ./pkg/models
|
||||||
|
$(GO) generate ./pkg/cti
|
||||||
|
@echo "Code generation complete."
|
||||||
|
|
||||||
.PHONY: testclean
|
.PHONY: testclean
|
||||||
testclean: bats-clean ## Remove test artifacts
|
testclean: bats-clean ## Remove test artifacts
|
||||||
|
|
|
@ -334,7 +334,8 @@ func Serve(cConfig *csconfig.Config, agentReady chan bool) error {
|
||||||
log.Warningln("Exprhelpers loaded without database client.")
|
log.Warningln("Exprhelpers loaded without database client.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cConfig.API.CTI != nil && *cConfig.API.CTI.Enabled {
|
// XXX: just pass the CTICfg
|
||||||
|
if cConfig.API.CTI != nil && cConfig.API.CTI.Enabled != nil && *cConfig.API.CTI.Enabled {
|
||||||
log.Infof("Crowdsec CTI helper enabled")
|
log.Infof("Crowdsec CTI helper enabled")
|
||||||
|
|
||||||
if err := exprhelpers.InitCrowdsecCTI(cConfig.API.CTI.Key, cConfig.API.CTI.CacheTimeout, cConfig.API.CTI.CacheSize, cConfig.API.CTI.LogLevel); err != nil {
|
if err := exprhelpers.InitCrowdsecCTI(cConfig.API.CTI.Key, cConfig.API.CTI.CacheTimeout, cConfig.API.CTI.CacheSize, cConfig.API.CTI.LogLevel); err != nil {
|
||||||
|
|
32
cmd/cscti/Makefile
Normal file
32
cmd/cscti/Makefile
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
ifeq ($(OS), Windows_NT)
|
||||||
|
SHELL := pwsh.exe
|
||||||
|
.SHELLFLAGS := -NoProfile -Command
|
||||||
|
EXT = .exe
|
||||||
|
endif
|
||||||
|
|
||||||
|
GO = go
|
||||||
|
GOBUILD = $(GO) build
|
||||||
|
|
||||||
|
BINARY_NAME = cscti$(EXT)
|
||||||
|
PREFIX ?= "/"
|
||||||
|
BIN_PREFIX = $(PREFIX)"/usr/local/bin/"
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: clean build
|
||||||
|
|
||||||
|
build: clean
|
||||||
|
$(GOBUILD) $(LD_OPTS) -o $(BINARY_NAME)
|
||||||
|
|
||||||
|
.PHONY: install
|
||||||
|
install: install-conf install-bin
|
||||||
|
|
||||||
|
install-conf:
|
||||||
|
|
||||||
|
install-bin:
|
||||||
|
@install -v -m 755 -D "$(BINARY_NAME)" "$(BIN_PREFIX)/$(BINARY_NAME)" || exit
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
@$(RM) $(BIN_PREFIX)$(BINARY_NAME) $(WIN_IGNORE_ERR)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@$(RM) $(BINARY_NAME) $(WIN_IGNORE_ERR)
|
58
cmd/cscti/main.go
Normal file
58
cmd/cscti/main.go
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
cc "github.com/ivanpirog/coloredcobra"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrorNoAPIKey = errors.New("CTI_API_KEY is not set")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
API struct {
|
||||||
|
CTI struct {
|
||||||
|
Key string `yaml:"key"`
|
||||||
|
} `yaml:"cti"`
|
||||||
|
} `yaml:"api"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var configPath string
|
||||||
|
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "cscti",
|
||||||
|
Short: "cscti is a tool to query the CrowdSec CTI",
|
||||||
|
ValidArgs: []string{"smoke-ip"},
|
||||||
|
DisableAutoGenTag: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
cc.Init(&cc.Config{
|
||||||
|
RootCmd: cmd,
|
||||||
|
Headings: cc.Yellow,
|
||||||
|
Commands: cc.Green + cc.Bold,
|
||||||
|
CmdShortDescr: cc.Cyan,
|
||||||
|
Example: cc.Italic,
|
||||||
|
ExecName: cc.Bold,
|
||||||
|
Aliases: cc.Bold + cc.Italic,
|
||||||
|
FlagsDataType: cc.White,
|
||||||
|
Flags: cc.Green,
|
||||||
|
FlagsDescr: cc.Cyan,
|
||||||
|
})
|
||||||
|
cmd.SetOut(color.Output)
|
||||||
|
|
||||||
|
pflags := cmd.PersistentFlags()
|
||||||
|
|
||||||
|
pflags.StringVarP(&configPath, "config", "c", "", "Path to the configuration file")
|
||||||
|
|
||||||
|
cmd.AddCommand(NewCLISmokeIP().NewCommand())
|
||||||
|
|
||||||
|
if err := cmd.Execute(); err != nil {
|
||||||
|
color.Red(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
90
cmd/cscti/smokeip.go
Normal file
90
cmd/cscti/smokeip.go
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/cti"
|
||||||
|
)
|
||||||
|
|
||||||
|
type cliSmokeIP struct {}
|
||||||
|
|
||||||
|
func NewCLISmokeIP() *cliSmokeIP {
|
||||||
|
return &cliSmokeIP{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli *cliSmokeIP) smokeip(ip string) error {
|
||||||
|
// check if CTI_API_KEY is set
|
||||||
|
apiKey := os.Getenv("CTI_API_KEY")
|
||||||
|
if apiKey == "" {
|
||||||
|
return ErrorNoAPIKey
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := cti.NewAPIKeyProvider(apiKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new CTI client
|
||||||
|
client, err := cti.NewClientWithResponses("https://cti.api.crowdsec.net/v2/", cti.WithRequestEditorFn(provider.Intercept))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
resp, err := client.GetSmokeIpWithResponse(ctx, ip)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case resp.JSON404 != nil:
|
||||||
|
return errors.New("ip not found")
|
||||||
|
case resp.JSON403 != nil:
|
||||||
|
return errors.New("forbidden")
|
||||||
|
case resp.JSON500 != nil:
|
||||||
|
return errors.New("internal server error")
|
||||||
|
case resp.JSON429 != nil:
|
||||||
|
return errors.New("too many requests")
|
||||||
|
case resp.JSON400 != nil:
|
||||||
|
return errors.New("bad request")
|
||||||
|
case resp.JSON200 == nil:
|
||||||
|
return fmt.Errorf("unexpected error %d", resp.StatusCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
ctiObj := resp.JSON200
|
||||||
|
|
||||||
|
var out []byte
|
||||||
|
|
||||||
|
// re-encode (todo: yaml, human)
|
||||||
|
|
||||||
|
out, err = json.MarshalIndent(ctiObj, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(out))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli *cliSmokeIP) NewCommand() *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "smoke-ip",
|
||||||
|
Short: "Query the smoke data with a given IP",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
return cli.smokeip(args[0])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
30
go.mod
30
go.mod
|
@ -30,6 +30,7 @@ require (
|
||||||
github.com/crowdsecurity/grokky v0.2.1
|
github.com/crowdsecurity/grokky v0.2.1
|
||||||
github.com/crowdsecurity/machineid v1.0.2
|
github.com/crowdsecurity/machineid v1.0.2
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
|
github.com/deepmap/oapi-codegen v1.16.2
|
||||||
github.com/dghubble/sling v1.3.0
|
github.com/dghubble/sling v1.3.0
|
||||||
github.com/docker/docker v24.0.7+incompatible
|
github.com/docker/docker v24.0.7+incompatible
|
||||||
github.com/docker/go-connections v0.4.0
|
github.com/docker/go-connections v0.4.0
|
||||||
|
@ -46,7 +47,7 @@ require (
|
||||||
github.com/gofrs/uuid v4.0.0+incompatible
|
github.com/gofrs/uuid v4.0.0+incompatible
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||||
github.com/google/go-querystring v1.0.0
|
github.com/google/go-querystring v1.0.0
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.5.0
|
||||||
github.com/google/winops v0.0.0-20230712152054-af9b550d0601
|
github.com/google/winops v0.0.0-20230712152054-af9b550d0601
|
||||||
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e
|
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e
|
||||||
github.com/gorilla/websocket v1.5.0
|
github.com/gorilla/websocket v1.5.0
|
||||||
|
@ -59,10 +60,11 @@ require (
|
||||||
github.com/jarcoal/httpmock v1.1.0
|
github.com/jarcoal/httpmock v1.1.0
|
||||||
github.com/jszwec/csvutil v1.5.1
|
github.com/jszwec/csvutil v1.5.1
|
||||||
github.com/lithammer/dedent v1.1.0
|
github.com/lithammer/dedent v1.1.0
|
||||||
github.com/mattn/go-isatty v0.0.19
|
github.com/mattn/go-isatty v0.0.20
|
||||||
github.com/mattn/go-sqlite3 v1.14.16
|
github.com/mattn/go-sqlite3 v1.14.16
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||||
github.com/nxadm/tail v1.4.8
|
github.com/nxadm/tail v1.4.8
|
||||||
|
github.com/oapi-codegen/runtime v1.1.1
|
||||||
github.com/oschwald/geoip2-golang v1.4.0
|
github.com/oschwald/geoip2-golang v1.4.0
|
||||||
github.com/oschwald/maxminddb-golang v1.8.0
|
github.com/oschwald/maxminddb-golang v1.8.0
|
||||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
|
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
|
||||||
|
@ -82,7 +84,7 @@ require (
|
||||||
github.com/wasilibs/go-re2 v1.3.0
|
github.com/wasilibs/go-re2 v1.3.0
|
||||||
github.com/xhit/go-simple-mail/v2 v2.16.0
|
github.com/xhit/go-simple-mail/v2 v2.16.0
|
||||||
golang.org/x/crypto v0.17.0
|
golang.org/x/crypto v0.17.0
|
||||||
golang.org/x/mod v0.11.0
|
golang.org/x/mod v0.12.0
|
||||||
golang.org/x/sys v0.15.0
|
golang.org/x/sys v0.15.0
|
||||||
golang.org/x/text v0.14.0
|
golang.org/x/text v0.14.0
|
||||||
google.golang.org/grpc v1.56.3
|
google.golang.org/grpc v1.56.3
|
||||||
|
@ -99,11 +101,13 @@ require (
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||||
github.com/ahmetalpbalkan/dlog v0.0.0-20170105205344-4fb5f8204f26 // indirect
|
github.com/ahmetalpbalkan/dlog v0.0.0-20170105205344-4fb5f8204f26 // indirect
|
||||||
|
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
|
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bytedance/sonic v1.9.1 // indirect
|
github.com/bytedance/sonic v1.10.0-rc3 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||||
|
github.com/chenzhuoyu/iasm v0.9.0 // indirect
|
||||||
github.com/corazawaf/libinjection-go v0.1.2 // indirect
|
github.com/corazawaf/libinjection-go v0.1.2 // indirect
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||||
|
@ -123,7 +127,7 @@ require (
|
||||||
github.com/go-openapi/spec v0.20.0 // indirect
|
github.com/go-openapi/spec v0.20.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
github.com/go-playground/validator/v10 v10.14.1 // indirect
|
||||||
github.com/go-stack/stack v1.8.0 // indirect
|
github.com/go-stack/stack v1.8.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
@ -148,13 +152,13 @@ require (
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/klauspost/compress v1.17.3 // indirect
|
github.com/klauspost/compress v1.17.3 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
github.com/leodido/go-urn v1.2.4 // indirect
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||||
github.com/magefile/mage v1.15.0 // indirect
|
github.com/magefile/mage v1.15.0 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
|
@ -169,7 +173,7 @@ require (
|
||||||
github.com/oklog/run v1.0.0 // indirect
|
github.com/oklog/run v1.0.0 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
|
||||||
github.com/petar-dambovaliev/aho-corasick v0.0.0-20230725210150-fb29fc3c913e // indirect
|
github.com/petar-dambovaliev/aho-corasick v0.0.0-20230725210150-fb29fc3c913e // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.18 // indirect
|
github.com/pierrec/lz4/v4 v4.1.18 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
@ -197,13 +201,13 @@ require (
|
||||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||||
github.com/zclconf/go-cty v1.8.0 // indirect
|
github.com/zclconf/go-cty v1.8.0 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.9.4 // indirect
|
go.mongodb.org/mongo-driver v1.9.4 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.4.0 // indirect
|
||||||
golang.org/x/net v0.19.0 // indirect
|
golang.org/x/net v0.19.0 // indirect
|
||||||
golang.org/x/sync v0.6.0 // indirect
|
golang.org/x/sync v0.6.0 // indirect
|
||||||
golang.org/x/term v0.15.0 // indirect
|
golang.org/x/term v0.15.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
golang.org/x/tools v0.8.1-0.20230428195545-5283a0178901 // indirect
|
golang.org/x/tools v0.12.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
|
66
go.sum
66
go.sum
|
@ -26,6 +26,7 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDe
|
||||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
|
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
|
||||||
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
|
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
|
||||||
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||||
|
@ -41,6 +42,8 @@ github.com/alexliesenfeld/health v0.8.0/go.mod h1:TfNP0f+9WQVWMQRzvMUjlws4ceXKEL
|
||||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||||
github.com/antonmedv/expr v1.15.3 h1:q3hOJZNvLvhqE8OHBs1cFRdbXFNKuA+bHmRaI+AmRmI=
|
github.com/antonmedv/expr v1.15.3 h1:q3hOJZNvLvhqE8OHBs1cFRdbXFNKuA+bHmRaI+AmRmI=
|
||||||
github.com/antonmedv/expr v1.15.3/go.mod h1:0E/6TxnOlRNp81GMzX9QfDPAmHo2Phg00y4JUv1ihsE=
|
github.com/antonmedv/expr v1.15.3/go.mod h1:0E/6TxnOlRNp81GMzX9QfDPAmHo2Phg00y4JUv1ihsE=
|
||||||
|
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||||
|
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||||
github.com/appleboy/gin-jwt/v2 v2.8.0 h1:Glo7cb9eBR+hj8Y7WzgfkOlqCaNLjP+RV4dNO3fpdps=
|
github.com/appleboy/gin-jwt/v2 v2.8.0 h1:Glo7cb9eBR+hj8Y7WzgfkOlqCaNLjP+RV4dNO3fpdps=
|
||||||
|
@ -70,18 +73,23 @@ github.com/blackfireio/osinfo v1.0.3 h1:Yk2t2GTPjBcESv6nDSWZKO87bGMQgO+Hi9OoXPpx
|
||||||
github.com/blackfireio/osinfo v1.0.3/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA=
|
github.com/blackfireio/osinfo v1.0.3/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA=
|
||||||
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
||||||
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
||||||
|
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
||||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
github.com/bytedance/sonic v1.10.0-rc3 h1:uNSnscRapXTwUgTyOF0GVljYD08p9X/Lbr9MweSV3V0=
|
||||||
|
github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||||
github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU=
|
github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU=
|
||||||
github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
|
github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
|
||||||
|
github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
|
||||||
|
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||||
github.com/corazawaf/libinjection-go v0.1.2 h1:oeiV9pc5rvJ+2oqOqXEAMJousPpGiup6f7Y3nZj5GoM=
|
github.com/corazawaf/libinjection-go v0.1.2 h1:oeiV9pc5rvJ+2oqOqXEAMJousPpGiup6f7Y3nZj5GoM=
|
||||||
|
@ -112,6 +120,8 @@ github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/deepmap/oapi-codegen v1.16.2 h1:xGHx0dNqYfy9gE8a7AVgVM8Sd5oF9SEgePzP+UPAUXI=
|
||||||
|
github.com/deepmap/oapi-codegen v1.16.2/go.mod h1:rdYoEA2GE+riuZ91DvpmBX9hJbQpuY9wchXpfQ3n+ho=
|
||||||
github.com/dghubble/sling v1.3.0 h1:pZHjCJq4zJvc6qVQ5wN1jo5oNZlNE0+8T/h0XeXBUKU=
|
github.com/dghubble/sling v1.3.0 h1:pZHjCJq4zJvc6qVQ5wN1jo5oNZlNE0+8T/h0XeXBUKU=
|
||||||
github.com/dghubble/sling v1.3.0/go.mod h1:XXShWaBWKzNLhu2OxikSNFrlsvowtz4kyRuXUG7oQKY=
|
github.com/dghubble/sling v1.3.0/go.mod h1:XXShWaBWKzNLhu2OxikSNFrlsvowtz4kyRuXUG7oQKY=
|
||||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||||
|
@ -251,8 +261,8 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
|
||||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
|
@ -325,8 +335,8 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/winops v0.0.0-20230712152054-af9b550d0601 h1:XvlrmqZIuwxuRE88S9mkxX+FkV+YakqbiAC5Z4OzDnM=
|
github.com/google/winops v0.0.0-20230712152054-af9b550d0601 h1:XvlrmqZIuwxuRE88S9mkxX+FkV+YakqbiAC5Z4OzDnM=
|
||||||
github.com/google/winops v0.0.0-20230712152054-af9b550d0601/go.mod h1:rT1mcjzuvcDDbRmUTsoH6kV0DG91AkFe9UCjASraK5I=
|
github.com/google/winops v0.0.0-20230712152054-af9b550d0601/go.mod h1:rT1mcjzuvcDDbRmUTsoH6kV0DG91AkFe9UCjASraK5I=
|
||||||
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e h1:XmA6L9IPRdUr28a+SK/oMchGgQy159wvzXA5tJ7l+40=
|
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e h1:XmA6L9IPRdUr28a+SK/oMchGgQy159wvzXA5tJ7l+40=
|
||||||
|
@ -422,6 +432,7 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jszwec/csvutil v1.5.1 h1:c3GFBhj6DFMUl4dMK3+B6rz2+LWWS/e9VJiVJ9t9kfQ=
|
github.com/jszwec/csvutil v1.5.1 h1:c3GFBhj6DFMUl4dMK3+B6rz2+LWWS/e9VJiVJ9t9kfQ=
|
||||||
github.com/jszwec/csvutil v1.5.1/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg=
|
github.com/jszwec/csvutil v1.5.1/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg=
|
||||||
|
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
|
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
|
||||||
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
||||||
|
@ -436,8 +447,9 @@ github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHU
|
||||||
github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA=
|
github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA=
|
||||||
github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
@ -490,10 +502,10 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
@ -538,6 +550,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
|
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
|
||||||
|
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
||||||
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
||||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
|
@ -554,8 +568,8 @@ github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhM
|
||||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||||
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
|
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
|
||||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
github.com/petar-dambovaliev/aho-corasick v0.0.0-20230725210150-fb29fc3c913e h1:POJco99aNgosh92lGqmx7L1ei+kCymivB/419SD15PQ=
|
github.com/petar-dambovaliev/aho-corasick v0.0.0-20230725210150-fb29fc3c913e h1:POJco99aNgosh92lGqmx7L1ei+kCymivB/419SD15PQ=
|
||||||
github.com/petar-dambovaliev/aho-corasick v0.0.0-20230725210150-fb29fc3c913e/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw=
|
github.com/petar-dambovaliev/aho-corasick v0.0.0-20230725210150-fb29fc3c913e/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw=
|
||||||
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
|
@ -639,6 +653,7 @@ github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyh
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
|
@ -737,8 +752,8 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc=
|
||||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
@ -767,8 +782,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
@ -833,7 +848,6 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -868,8 +882,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
@ -891,15 +905,16 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.8.1-0.20230428195545-5283a0178901 h1:0wxTF6pSjIIhNt7mo9GvjDfzyCOiWhmICgtO/Ah948s=
|
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
|
||||||
golang.org/x/tools v0.8.1-0.20230428195545-5283a0178901/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
||||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||||
|
@ -954,6 +969,7 @@ k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
|
||||||
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||||
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk=
|
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk=
|
||||||
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
|
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
|
|
9
pkg/cti/auth.go
Normal file
9
pkg/cti/auth.go
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package cti
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/deepmap/oapi-codegen/pkg/securityprovider"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewAPIKeyProvider(apiKey string) (*securityprovider.SecurityProviderApiKey, error) {
|
||||||
|
return securityprovider.NewSecurityProviderApiKey("header", "x-api-key", apiKey)
|
||||||
|
}
|
639
pkg/cti/client.go
Normal file
639
pkg/cti/client.go
Normal file
|
@ -0,0 +1,639 @@
|
||||||
|
// Package cti provides primitives to interact with the openapi HTTP API.
|
||||||
|
//
|
||||||
|
// Code generated by github.com/deepmap/oapi-codegen/v2 version v2.1.0 DO NOT EDIT.
|
||||||
|
package cti
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/oapi-codegen/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RequestEditorFn is the function signature for the RequestEditor callback function
|
||||||
|
type RequestEditorFn func(ctx context.Context, req *http.Request) error
|
||||||
|
|
||||||
|
// Doer performs HTTP requests.
|
||||||
|
//
|
||||||
|
// The standard http.Client implements this interface.
|
||||||
|
type HttpRequestDoer interface {
|
||||||
|
Do(req *http.Request) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client which conforms to the OpenAPI3 specification for this service.
|
||||||
|
type Client struct {
|
||||||
|
// The endpoint of the server conforming to this interface, with scheme,
|
||||||
|
// https://api.deepmap.com for example. This can contain a path relative
|
||||||
|
// to the server, such as https://api.deepmap.com/dev-test, and all the
|
||||||
|
// paths in the swagger spec will be appended to the server.
|
||||||
|
Server string
|
||||||
|
|
||||||
|
// Doer for performing requests, typically a *http.Client with any
|
||||||
|
// customized settings, such as certificate chains.
|
||||||
|
Client HttpRequestDoer
|
||||||
|
|
||||||
|
// A list of callbacks for modifying requests which are generated before sending over
|
||||||
|
// the network.
|
||||||
|
RequestEditors []RequestEditorFn
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientOption allows setting custom parameters during construction
|
||||||
|
type ClientOption func(*Client) error
|
||||||
|
|
||||||
|
// Creates a new Client, with reasonable defaults
|
||||||
|
func NewClient(server string, opts ...ClientOption) (*Client, error) {
|
||||||
|
// create a client with sane default values
|
||||||
|
client := Client{
|
||||||
|
Server: server,
|
||||||
|
}
|
||||||
|
// mutate client and add all optional params
|
||||||
|
for _, o := range opts {
|
||||||
|
if err := o(&client); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ensure the server URL always has a trailing slash
|
||||||
|
if !strings.HasSuffix(client.Server, "/") {
|
||||||
|
client.Server += "/"
|
||||||
|
}
|
||||||
|
// create httpClient, if not already present
|
||||||
|
if client.Client == nil {
|
||||||
|
client.Client = &http.Client{}
|
||||||
|
}
|
||||||
|
return &client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHTTPClient allows overriding the default Doer, which is
|
||||||
|
// automatically created using http.Client. This is useful for tests.
|
||||||
|
func WithHTTPClient(doer HttpRequestDoer) ClientOption {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.Client = doer
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRequestEditorFn allows setting up a callback function, which will be
|
||||||
|
// called right before sending the request. This can be used to mutate the request.
|
||||||
|
func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.RequestEditors = append(c.RequestEditors, fn)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The interface specification for the client above.
|
||||||
|
type ClientInterface interface {
|
||||||
|
// GetFire request
|
||||||
|
GetFire(ctx context.Context, params *GetFireParams, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||||
|
|
||||||
|
// GetSmoke request
|
||||||
|
GetSmoke(ctx context.Context, params *GetSmokeParams, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||||
|
|
||||||
|
// GetSmokeIp request
|
||||||
|
GetSmokeIp(ctx context.Context, ip string, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetFire(ctx context.Context, params *GetFireParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||||
|
req, err := NewGetFireRequest(c.Server, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.Client.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetSmoke(ctx context.Context, params *GetSmokeParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||||
|
req, err := NewGetSmokeRequest(c.Server, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.Client.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetSmokeIp(ctx context.Context, ip string, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||||
|
req, err := NewGetSmokeIpRequest(c.Server, ip)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.Client.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetFireRequest generates requests for GetFire
|
||||||
|
func NewGetFireRequest(server string, params *GetFireParams) (*http.Request, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
serverURL, err := url.Parse(server)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
operationPath := fmt.Sprintf("/fire")
|
||||||
|
if operationPath[0] == '/' {
|
||||||
|
operationPath = "." + operationPath
|
||||||
|
}
|
||||||
|
|
||||||
|
queryURL, err := serverURL.Parse(operationPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if params != nil {
|
||||||
|
queryValues := queryURL.Query()
|
||||||
|
|
||||||
|
if params.Page != nil {
|
||||||
|
|
||||||
|
if queryFrag, err := runtime.StyleParamWithLocation("form", true, "page", runtime.ParamLocationQuery, *params.Page); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if parsed, err := url.ParseQuery(queryFrag); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
for k, v := range parsed {
|
||||||
|
for _, v2 := range v {
|
||||||
|
queryValues.Add(k, v2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Limit != nil {
|
||||||
|
|
||||||
|
if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if parsed, err := url.ParseQuery(queryFrag); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
for k, v := range parsed {
|
||||||
|
for _, v2 := range v {
|
||||||
|
queryValues.Add(k, v2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Since != nil {
|
||||||
|
|
||||||
|
if queryFrag, err := runtime.StyleParamWithLocation("form", true, "since", runtime.ParamLocationQuery, *params.Since); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if parsed, err := url.ParseQuery(queryFrag); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
for k, v := range parsed {
|
||||||
|
for _, v2 := range v {
|
||||||
|
queryValues.Add(k, v2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
queryURL.RawQuery = queryValues.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", queryURL.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetSmokeRequest generates requests for GetSmoke
|
||||||
|
func NewGetSmokeRequest(server string, params *GetSmokeParams) (*http.Request, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
serverURL, err := url.Parse(server)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
operationPath := fmt.Sprintf("/smoke")
|
||||||
|
if operationPath[0] == '/' {
|
||||||
|
operationPath = "." + operationPath
|
||||||
|
}
|
||||||
|
|
||||||
|
queryURL, err := serverURL.Parse(operationPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if params != nil {
|
||||||
|
queryValues := queryURL.Query()
|
||||||
|
|
||||||
|
if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ips", runtime.ParamLocationQuery, params.Ips); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if parsed, err := url.ParseQuery(queryFrag); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
for k, v := range parsed {
|
||||||
|
for _, v2 := range v {
|
||||||
|
queryValues.Add(k, v2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queryURL.RawQuery = queryValues.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", queryURL.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetSmokeIpRequest generates requests for GetSmokeIp
|
||||||
|
func NewGetSmokeIpRequest(server string, ip string) (*http.Request, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
var pathParam0 string
|
||||||
|
|
||||||
|
pathParam0, err = runtime.StyleParamWithLocation("simple", false, "ip", runtime.ParamLocationPath, ip)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
serverURL, err := url.Parse(server)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
operationPath := fmt.Sprintf("/smoke/%s", pathParam0)
|
||||||
|
if operationPath[0] == '/' {
|
||||||
|
operationPath = "." + operationPath
|
||||||
|
}
|
||||||
|
|
||||||
|
queryURL, err := serverURL.Parse(operationPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", queryURL.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
|
||||||
|
for _, r := range c.RequestEditors {
|
||||||
|
if err := r(ctx, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, r := range additionalEditors {
|
||||||
|
if err := r(ctx, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientWithResponses builds on ClientInterface to offer response payloads
|
||||||
|
type ClientWithResponses struct {
|
||||||
|
ClientInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClientWithResponses creates a new ClientWithResponses, which wraps
|
||||||
|
// Client with return type handling
|
||||||
|
func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
|
||||||
|
client, err := NewClient(server, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ClientWithResponses{client}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBaseURL overrides the baseURL.
|
||||||
|
func WithBaseURL(baseURL string) ClientOption {
|
||||||
|
return func(c *Client) error {
|
||||||
|
newBaseURL, err := url.Parse(baseURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Server = newBaseURL.String()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientWithResponsesInterface is the interface specification for the client with responses above.
|
||||||
|
type ClientWithResponsesInterface interface {
|
||||||
|
// GetFireWithResponse request
|
||||||
|
GetFireWithResponse(ctx context.Context, params *GetFireParams, reqEditors ...RequestEditorFn) (*GetFireResponse, error)
|
||||||
|
|
||||||
|
// GetSmokeWithResponse request
|
||||||
|
GetSmokeWithResponse(ctx context.Context, params *GetSmokeParams, reqEditors ...RequestEditorFn) (*GetSmokeResponse, error)
|
||||||
|
|
||||||
|
// GetSmokeIpWithResponse request
|
||||||
|
GetSmokeIpWithResponse(ctx context.Context, ip string, reqEditors ...RequestEditorFn) (*GetSmokeIpResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetFireResponse struct {
|
||||||
|
Body []byte
|
||||||
|
HTTPResponse *http.Response
|
||||||
|
JSON200 *FireCTIResponse
|
||||||
|
JSON400 *ErrorResponse
|
||||||
|
JSON403 *ErrorResponse
|
||||||
|
JSON404 *ErrorResponse
|
||||||
|
JSON429 *ErrorResponse
|
||||||
|
JSON500 *ErrorResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status returns HTTPResponse.Status
|
||||||
|
func (r GetFireResponse) Status() string {
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
return r.HTTPResponse.Status
|
||||||
|
}
|
||||||
|
return http.StatusText(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatusCode returns HTTPResponse.StatusCode
|
||||||
|
func (r GetFireResponse) StatusCode() int {
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
return r.HTTPResponse.StatusCode
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetSmokeResponse struct {
|
||||||
|
Body []byte
|
||||||
|
HTTPResponse *http.Response
|
||||||
|
JSON200 *SearchCTIResponse
|
||||||
|
JSON400 *ErrorResponse
|
||||||
|
JSON403 *ErrorResponse
|
||||||
|
JSON404 *ErrorResponse
|
||||||
|
JSON429 *ErrorResponse
|
||||||
|
JSON500 *ErrorResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status returns HTTPResponse.Status
|
||||||
|
func (r GetSmokeResponse) Status() string {
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
return r.HTTPResponse.Status
|
||||||
|
}
|
||||||
|
return http.StatusText(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatusCode returns HTTPResponse.StatusCode
|
||||||
|
func (r GetSmokeResponse) StatusCode() int {
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
return r.HTTPResponse.StatusCode
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetSmokeIpResponse struct {
|
||||||
|
Body []byte
|
||||||
|
HTTPResponse *http.Response
|
||||||
|
JSON200 *QueryCTIResponse
|
||||||
|
JSON400 *ErrorResponse
|
||||||
|
JSON403 *ErrorResponse
|
||||||
|
JSON404 *ErrorResponse
|
||||||
|
JSON429 *ErrorResponse
|
||||||
|
JSON500 *ErrorResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status returns HTTPResponse.Status
|
||||||
|
func (r GetSmokeIpResponse) Status() string {
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
return r.HTTPResponse.Status
|
||||||
|
}
|
||||||
|
return http.StatusText(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatusCode returns HTTPResponse.StatusCode
|
||||||
|
func (r GetSmokeIpResponse) StatusCode() int {
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
return r.HTTPResponse.StatusCode
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFireWithResponse request returning *GetFireResponse
|
||||||
|
func (c *ClientWithResponses) GetFireWithResponse(ctx context.Context, params *GetFireParams, reqEditors ...RequestEditorFn) (*GetFireResponse, error) {
|
||||||
|
rsp, err := c.GetFire(ctx, params, reqEditors...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ParseGetFireResponse(rsp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSmokeWithResponse request returning *GetSmokeResponse
|
||||||
|
func (c *ClientWithResponses) GetSmokeWithResponse(ctx context.Context, params *GetSmokeParams, reqEditors ...RequestEditorFn) (*GetSmokeResponse, error) {
|
||||||
|
rsp, err := c.GetSmoke(ctx, params, reqEditors...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ParseGetSmokeResponse(rsp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSmokeIpWithResponse request returning *GetSmokeIpResponse
|
||||||
|
func (c *ClientWithResponses) GetSmokeIpWithResponse(ctx context.Context, ip string, reqEditors ...RequestEditorFn) (*GetSmokeIpResponse, error) {
|
||||||
|
rsp, err := c.GetSmokeIp(ctx, ip, reqEditors...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ParseGetSmokeIpResponse(rsp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseGetFireResponse parses an HTTP response from a GetFireWithResponse call
|
||||||
|
func ParseGetFireResponse(rsp *http.Response) (*GetFireResponse, error) {
|
||||||
|
bodyBytes, err := io.ReadAll(rsp.Body)
|
||||||
|
defer func() { _ = rsp.Body.Close() }()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &GetFireResponse{
|
||||||
|
Body: bodyBytes,
|
||||||
|
HTTPResponse: rsp,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
|
||||||
|
var dest FireCTIResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON200 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON400 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON403 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON404 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 429:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON429 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON500 = &dest
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseGetSmokeResponse parses an HTTP response from a GetSmokeWithResponse call
|
||||||
|
func ParseGetSmokeResponse(rsp *http.Response) (*GetSmokeResponse, error) {
|
||||||
|
bodyBytes, err := io.ReadAll(rsp.Body)
|
||||||
|
defer func() { _ = rsp.Body.Close() }()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &GetSmokeResponse{
|
||||||
|
Body: bodyBytes,
|
||||||
|
HTTPResponse: rsp,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
|
||||||
|
var dest SearchCTIResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON200 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON400 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON403 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON404 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 429:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON429 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON500 = &dest
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseGetSmokeIpResponse parses an HTTP response from a GetSmokeIpWithResponse call
|
||||||
|
func ParseGetSmokeIpResponse(rsp *http.Response) (*GetSmokeIpResponse, error) {
|
||||||
|
bodyBytes, err := io.ReadAll(rsp.Body)
|
||||||
|
defer func() { _ = rsp.Body.Close() }()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &GetSmokeIpResponse{
|
||||||
|
Body: bodyBytes,
|
||||||
|
HTTPResponse: rsp,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
|
||||||
|
var dest QueryCTIResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON200 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON400 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON403 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON404 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 429:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON429 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500:
|
||||||
|
var dest ErrorResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON500 = &dest
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
19
pkg/cti/cticlient.go
Normal file
19
pkg/cti/cticlient.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package cti
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const CTIBaseURL = "https://cti.api.crowdsec.net/v2"
|
||||||
|
|
||||||
|
// NewCTIClient creates a new CTI client with the correct URL and any required configuration.
|
||||||
|
func NewCTIClient(apiKey string, opts ...ClientOption) (*ClientWithResponses, error) {
|
||||||
|
provider, err := NewAPIKeyProvider(apiKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create API key provider: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = append(opts, WithRequestEditorFn(provider.Intercept))
|
||||||
|
|
||||||
|
return NewClientWithResponses(CTIBaseURL, opts...)
|
||||||
|
}
|
12
pkg/cti/errors.go
Normal file
12
pkg/cti/errors.go
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package cti
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrDisabled = errors.New("CTI is disabled")
|
||||||
|
ErrLimit = errors.New("request quota exceeeded, please reduce your request rate")
|
||||||
|
ErrUnauthorized = errors.New("unauthorized")
|
||||||
|
ErrUnknown = errors.New("unknown error")
|
||||||
|
)
|
74
pkg/cti/example/fire.go
Normal file
74
pkg/cti/example/fire.go
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/csv"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/crowdsecurity/crowdsec/pkg/cti"
|
||||||
|
)
|
||||||
|
|
||||||
|
func float32ptr(f float32) *float32 {
|
||||||
|
return &f
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
client, err := cti.NewCTIClient(os.Getenv("CTI_API_KEY"))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
params := &cti.GetFireParams{
|
||||||
|
Page: float32ptr(1),
|
||||||
|
}
|
||||||
|
|
||||||
|
csvHeader := []string{
|
||||||
|
"value",
|
||||||
|
"reason",
|
||||||
|
"type",
|
||||||
|
"scope",
|
||||||
|
"duration",
|
||||||
|
}
|
||||||
|
csvFile, err := os.Create("fire.csv")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer csvFile.Close()
|
||||||
|
csvWriter := csv.NewWriter(csvFile)
|
||||||
|
allItems := make([][]string, 0)
|
||||||
|
|
||||||
|
for {
|
||||||
|
httpResp, err := client.GetFireWithResponse(context.Background(), params)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if httpResp.HTTPResponse.StatusCode != 200 {
|
||||||
|
panic(fmt.Errorf("unexpected status code %d", httpResp.HTTPResponse.StatusCode))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := httpResp.JSON200
|
||||||
|
|
||||||
|
for _, item := range resp.Items {
|
||||||
|
if *item.State == cti.Refused {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
banDuration := time.Until(item.Expiration.Time)
|
||||||
|
allItems = append(allItems, []string{
|
||||||
|
item.Ip,
|
||||||
|
"fire-import",
|
||||||
|
"ban",
|
||||||
|
"ip",
|
||||||
|
fmt.Sprintf("%ds", int(banDuration.Seconds())),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
csvWriter.Write(csvHeader)
|
||||||
|
csvWriter.WriteAll(allItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
8
pkg/cti/generate.go
Normal file
8
pkg/cti/generate.go
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package cti
|
||||||
|
|
||||||
|
// To update openapi.yaml:
|
||||||
|
// curl https://crowdsecurity.github.io/cti-api/v2/swagger.yaml > ./pkg/cti/openapi.yaml
|
||||||
|
|
||||||
|
//go:generate go run -mod=mod github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@v2.1.0 -package=cti -generate client -o ./client.go ./openapi.yaml
|
||||||
|
//go:generate go run -mod=mod github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@v2.1.0 -package=cti -generate types -o ./types.go ./openapi.yaml
|
||||||
|
|
655
pkg/cti/openapi.yaml
Normal file
655
pkg/cti/openapi.yaml
Normal file
|
@ -0,0 +1,655 @@
|
||||||
|
openapi: "3.0.1"
|
||||||
|
info:
|
||||||
|
description: "CTI by Crowdsec"
|
||||||
|
version: "2022-02-16T14:00:00"
|
||||||
|
title: "CTI v2"
|
||||||
|
contact:
|
||||||
|
name: "Crowdsec team"
|
||||||
|
url: "https://github.com/crowdsecurity/crowdsec"
|
||||||
|
email: "support@crowdsec.net"
|
||||||
|
externalDocs:
|
||||||
|
description: CTI Documentation
|
||||||
|
url: https://docs.crowdsec.net/docs/next/cti_api/intro/
|
||||||
|
servers:
|
||||||
|
- url: "https://cti.api.crowdsec.net/v2"
|
||||||
|
paths:
|
||||||
|
/smoke:
|
||||||
|
get:
|
||||||
|
description: "Search for CTI informations"
|
||||||
|
summary: "Search for CTI informations"
|
||||||
|
security:
|
||||||
|
- api_key: []
|
||||||
|
parameters:
|
||||||
|
- name: "ips"
|
||||||
|
in: "query"
|
||||||
|
required: true
|
||||||
|
description: "List of IPs to query, separated by comma"
|
||||||
|
example: "0.0.0.0,1.1.1.1"
|
||||||
|
schema:
|
||||||
|
type: "string"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "200 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/SearchCTIResponse"
|
||||||
|
"400":
|
||||||
|
description: "400 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
"500":
|
||||||
|
description: "500 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
"403":
|
||||||
|
description: "403 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
"404":
|
||||||
|
description: "404 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
"429":
|
||||||
|
description: "429 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
/smoke/{ip}:
|
||||||
|
get:
|
||||||
|
description: "Get CTI informations about the given IP"
|
||||||
|
summary: "CTI information on a given IP"
|
||||||
|
parameters:
|
||||||
|
- name: "ip"
|
||||||
|
in: "path"
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: "string"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "200 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/QueryCTIResponse"
|
||||||
|
"400":
|
||||||
|
description: "400 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
"500":
|
||||||
|
description: "500 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
"403":
|
||||||
|
description: "403 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
"404":
|
||||||
|
description: "404 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
"429":
|
||||||
|
description: "429 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
security:
|
||||||
|
- api_key: []
|
||||||
|
/fire:
|
||||||
|
get:
|
||||||
|
description: "Get fire CTI informations (IPs belonging to the community-blocklist)"
|
||||||
|
summary: "Get fire CTI informations (IPs belonging to the community-blocklist)"
|
||||||
|
security:
|
||||||
|
- api_key: []
|
||||||
|
parameters:
|
||||||
|
- name: "page"
|
||||||
|
in: "query"
|
||||||
|
required: false
|
||||||
|
description: "The page to fetch"
|
||||||
|
example: 1
|
||||||
|
schema:
|
||||||
|
type: "number"
|
||||||
|
- name: "limit"
|
||||||
|
in: "query"
|
||||||
|
required: false
|
||||||
|
description: "The number of items to fetch"
|
||||||
|
example: 50
|
||||||
|
schema:
|
||||||
|
type: "number"
|
||||||
|
- name: "since"
|
||||||
|
in: "query"
|
||||||
|
required: false
|
||||||
|
description: "Filter records updated since - duration in h (hours), d(days), m(minutes) )"
|
||||||
|
example: "3d"
|
||||||
|
schema:
|
||||||
|
type: "string"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "200 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/FireCTIResponse"
|
||||||
|
"400":
|
||||||
|
description: "400 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
"500":
|
||||||
|
description: "500 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
"403":
|
||||||
|
description: "403 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
"404":
|
||||||
|
description: "404 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
"429":
|
||||||
|
description: "429 response"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ErrorResponse"
|
||||||
|
|
||||||
|
components:
|
||||||
|
securitySchemes:
|
||||||
|
api_key:
|
||||||
|
type: "apiKey"
|
||||||
|
name: "x-api-key"
|
||||||
|
in: "header"
|
||||||
|
schemas:
|
||||||
|
CTIObject:
|
||||||
|
title: "IP CTI Object"
|
||||||
|
type: "object"
|
||||||
|
required:
|
||||||
|
- as_name
|
||||||
|
- as_num
|
||||||
|
- behaviors
|
||||||
|
- location
|
||||||
|
- history
|
||||||
|
- ip
|
||||||
|
- references
|
||||||
|
- ip_range
|
||||||
|
- ip_range_score
|
||||||
|
- classifications
|
||||||
|
- reverse_dns
|
||||||
|
- scores
|
||||||
|
- target_countries
|
||||||
|
- mitre_techniques
|
||||||
|
- cves
|
||||||
|
- background_noise_score
|
||||||
|
- background_noise
|
||||||
|
- attack_details
|
||||||
|
- reputation
|
||||||
|
- ip_range_24
|
||||||
|
- ip_range_24_reputation
|
||||||
|
- ip_range_24_score
|
||||||
|
properties:
|
||||||
|
ip:
|
||||||
|
type: string
|
||||||
|
description: Requested IP
|
||||||
|
example: "1.2.3.4"
|
||||||
|
reputation:
|
||||||
|
type: string
|
||||||
|
description: The reputation of the IP address
|
||||||
|
example: "malicious"
|
||||||
|
enum:
|
||||||
|
- malicious
|
||||||
|
- suspicious
|
||||||
|
- unknown
|
||||||
|
- known
|
||||||
|
- safe
|
||||||
|
ip_range:
|
||||||
|
type: string
|
||||||
|
description: The range to which the IP belongs
|
||||||
|
example: "1.2.3.0/16"
|
||||||
|
nullable: true
|
||||||
|
ip_range_score:
|
||||||
|
type: number
|
||||||
|
description: The score of the range (ip_range) the IP belongs to. 0 is good/unknown, 5 is worse
|
||||||
|
example: 2
|
||||||
|
enum:
|
||||||
|
- 0
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
- 5
|
||||||
|
ip_range_24:
|
||||||
|
type: string
|
||||||
|
description: The /24 range to which the IP belongs
|
||||||
|
example: "1.2.3.0/24"
|
||||||
|
nullable: true
|
||||||
|
ip_range_24_reputation:
|
||||||
|
type: string
|
||||||
|
description: The /24 range to which the IP belongs
|
||||||
|
nullable: true
|
||||||
|
example: "malicious"
|
||||||
|
enum:
|
||||||
|
- malicious
|
||||||
|
- suspicious
|
||||||
|
- unknown
|
||||||
|
- known
|
||||||
|
- safe
|
||||||
|
ip_range_24_score:
|
||||||
|
type: number
|
||||||
|
description: The score of the /24 range (ip_range_24) the IP belongs to. 0 is good/unknown, 5 is worse
|
||||||
|
nullable: true
|
||||||
|
example: 2
|
||||||
|
enum:
|
||||||
|
- 0
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
- 5
|
||||||
|
as_name:
|
||||||
|
type: string
|
||||||
|
description: The autonomous system name to which the IP belongs
|
||||||
|
example: ACME
|
||||||
|
nullable: true
|
||||||
|
as_num:
|
||||||
|
type: number
|
||||||
|
description: The autonomous system number to which the IP belongs
|
||||||
|
example: 99999
|
||||||
|
nullable: true
|
||||||
|
background_noise_score:
|
||||||
|
type: number
|
||||||
|
description: The background noise score of the IP ranging from 0 to 10 (highly noisy)
|
||||||
|
example: 8
|
||||||
|
nullable: true
|
||||||
|
background_noise:
|
||||||
|
type: string
|
||||||
|
description: The background noise level of the IP address
|
||||||
|
example: high
|
||||||
|
nullable: true
|
||||||
|
enum:
|
||||||
|
- low
|
||||||
|
- medium
|
||||||
|
- high
|
||||||
|
- none
|
||||||
|
location:
|
||||||
|
type: object
|
||||||
|
description: Location information about the IP address
|
||||||
|
required:
|
||||||
|
- country
|
||||||
|
- city
|
||||||
|
- latitude
|
||||||
|
- longitude
|
||||||
|
properties:
|
||||||
|
country:
|
||||||
|
type: string
|
||||||
|
description: The two letters country code of the IP
|
||||||
|
example: US
|
||||||
|
nullable: true
|
||||||
|
city:
|
||||||
|
type: "string"
|
||||||
|
description: The associated City of the IP
|
||||||
|
example: New York
|
||||||
|
nullable: true
|
||||||
|
latitude:
|
||||||
|
type: number
|
||||||
|
description: Coordinates of the IP
|
||||||
|
example: 40.7597
|
||||||
|
nullable: true
|
||||||
|
longitude:
|
||||||
|
type: number
|
||||||
|
description: Coordinates of the IP
|
||||||
|
example: 40.7597
|
||||||
|
nullable: true
|
||||||
|
reverse_dns:
|
||||||
|
type: string
|
||||||
|
description: Reverse dns lookup of the IP
|
||||||
|
example: acbd.my_domain.net
|
||||||
|
nullable: true
|
||||||
|
behaviors:
|
||||||
|
type: array
|
||||||
|
description: A list of the attack categories for which the IP was reported
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The category of the attack, often in the form "protocol-or-scope:attack_type"
|
||||||
|
example: "http:scan"
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
description: Human-friendly description of the category
|
||||||
|
example: HTTP Scan
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
description: Human-friendly description of the category
|
||||||
|
example: IP has been reported for performing actions related to HTTP vulnerability scanning and discovery
|
||||||
|
references:
|
||||||
|
type: array
|
||||||
|
description: A list of the references for which the IP was see
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The reference, often in the form "list:list_name"
|
||||||
|
example: "list:my_list"
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
description: Human-friendly description of the reference
|
||||||
|
example: My List
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
description: Human-friendly description of the reference
|
||||||
|
example: IP was referenced in My List
|
||||||
|
history:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
first_seen:
|
||||||
|
type: string
|
||||||
|
description: Date of the first time this IP was reported. Due to "progressive data degradation", this date might be later than the first time the IP was actually seen
|
||||||
|
example: "2021-03-03T23:00:00"
|
||||||
|
last_seen:
|
||||||
|
type: string
|
||||||
|
description: Date of the last time this IP was reported
|
||||||
|
example: "2021-03-03T23:30:00"
|
||||||
|
full_age:
|
||||||
|
type: number
|
||||||
|
description: Delta in days between first seen and today
|
||||||
|
example: 220
|
||||||
|
days_age:
|
||||||
|
type: number
|
||||||
|
description: Delta in days between first and last seen timestamps
|
||||||
|
example: 189
|
||||||
|
classifications:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
false_positives:
|
||||||
|
type: array
|
||||||
|
description: A list of false positives tags associated with the IP. Any IP with `false_positives` tags shouldn't be considered as malicious
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The name of the false positive, often in the form "protocol-or-scope:attack_type"
|
||||||
|
example: "seo:crawler"
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
description: Human-friendly name of the category
|
||||||
|
example: SEO crawler
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
description: Human-friendly description of the category
|
||||||
|
example: IP belongs to a known SEO crawler and should not be flagged as a threat.
|
||||||
|
classifications:
|
||||||
|
type: array
|
||||||
|
description: A list of categories associated with the IP. Those data can be sourced from 3rd parties (i.e. tor exit nodes list)
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The name of the category, often in the form "protocol-or-scope:attack_type"
|
||||||
|
example: "community-blocklist"
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
description: Human-friendly name of the category
|
||||||
|
example: CrowdSec Community Blocklist
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
description: Human-friendly description of the category
|
||||||
|
example: IP belong to the CrowdSec Community Blocklist
|
||||||
|
mitre_techniques:
|
||||||
|
type: array
|
||||||
|
description: A list of Mitre Enterprise Techniques associated with the IP.
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The ID of the Mitre technique"
|
||||||
|
example: "T1190"
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
description: The name of the Mitre technique
|
||||||
|
example: Exploit Public-Facing Application
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
description: Description of the Mitre technique
|
||||||
|
example: Adversaries may attempt to exploit a weakness in an Internet-facing host or system to initially access a network.
|
||||||
|
cves:
|
||||||
|
type: array
|
||||||
|
description: A list of CVEs reported for this IP.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
attack_details:
|
||||||
|
type: array
|
||||||
|
description: A more exhaustive list of the scenarios for which a given IP was reported
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: Name of the scenario (see hub.crowdsec.net)
|
||||||
|
example: crowdsecurity/http-bad-user-agent
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
description: Human-friendly descriptions of scenarios
|
||||||
|
example: Known Bad User-Agent
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
description: Human-friendly descriptions of scenarios
|
||||||
|
example: Detect bad user-agents
|
||||||
|
references:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
target_countries:
|
||||||
|
type: object
|
||||||
|
description: The top 10 reports repartition by country about the IP, as a percentage
|
||||||
|
scores:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
overall:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
aggressiveness:
|
||||||
|
type: number
|
||||||
|
description: Overall aggressiveness score
|
||||||
|
threat:
|
||||||
|
type: number
|
||||||
|
description: Overall threat score
|
||||||
|
trust:
|
||||||
|
type: number
|
||||||
|
description: Overall trust score
|
||||||
|
anomaly:
|
||||||
|
type: number
|
||||||
|
description: Overall anomaly score
|
||||||
|
total:
|
||||||
|
type: number
|
||||||
|
description: Overall score
|
||||||
|
last_day:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
aggressiveness:
|
||||||
|
type: number
|
||||||
|
description: Last day aggressiveness score
|
||||||
|
threat:
|
||||||
|
type: number
|
||||||
|
description: Last day threat score
|
||||||
|
trust:
|
||||||
|
type: number
|
||||||
|
description: Last day trust score
|
||||||
|
anomaly:
|
||||||
|
type: number
|
||||||
|
description: Last day anomaly score
|
||||||
|
total:
|
||||||
|
type: number
|
||||||
|
description: Last day score
|
||||||
|
last_week:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
aggressiveness:
|
||||||
|
type: number
|
||||||
|
description: Last week aggressiveness score
|
||||||
|
threat:
|
||||||
|
type: number
|
||||||
|
description: Last week threat score
|
||||||
|
trust:
|
||||||
|
type: number
|
||||||
|
description: Last week trust score
|
||||||
|
anomaly:
|
||||||
|
type: number
|
||||||
|
description: Last week anomaly score
|
||||||
|
total:
|
||||||
|
type: number
|
||||||
|
description: Last week score
|
||||||
|
last_month:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
aggressiveness:
|
||||||
|
type: number
|
||||||
|
description: Last month aggressiveness score
|
||||||
|
threat:
|
||||||
|
type: number
|
||||||
|
description: Last month threat score
|
||||||
|
trust:
|
||||||
|
type: number
|
||||||
|
description: Last month trust score
|
||||||
|
anomaly:
|
||||||
|
type: number
|
||||||
|
description: Last month anomaly score
|
||||||
|
total:
|
||||||
|
type: number
|
||||||
|
description: Last month score
|
||||||
|
|
||||||
|
FireIPCTIResponse:
|
||||||
|
title: "Fire IP CTI Response"
|
||||||
|
allOf:
|
||||||
|
- $ref: "#/components/schemas/CTIObject"
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
state:
|
||||||
|
type: string
|
||||||
|
description: "state of the IP in the community blocklist: validated means IP is currently part of community blocklist, refused means it was part of the community blocklist, but was manually purged (ie. false positive)"
|
||||||
|
enum:
|
||||||
|
- validated
|
||||||
|
- refused
|
||||||
|
example: validated
|
||||||
|
expiration:
|
||||||
|
type: string
|
||||||
|
description: Date at which the IP address expire from the community blocklist
|
||||||
|
example: "2022-03-04T10:00:00"
|
||||||
|
SearchCTIResponse:
|
||||||
|
title: "Search CTI Response"
|
||||||
|
type: "object"
|
||||||
|
required:
|
||||||
|
- items
|
||||||
|
- total
|
||||||
|
- not_found
|
||||||
|
properties:
|
||||||
|
total:
|
||||||
|
type: number
|
||||||
|
description: IP of the request
|
||||||
|
not_found:
|
||||||
|
type: number
|
||||||
|
items:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/CTIObject"
|
||||||
|
QueryCTIResponse:
|
||||||
|
title: "Query IP CTI Response"
|
||||||
|
$ref: "#/components/schemas/CTIObject"
|
||||||
|
FireCTIResponse:
|
||||||
|
title: "Fire CTI response"
|
||||||
|
type: "object"
|
||||||
|
required:
|
||||||
|
- _links
|
||||||
|
- items
|
||||||
|
properties:
|
||||||
|
_links:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- self
|
||||||
|
- next
|
||||||
|
- first
|
||||||
|
properties:
|
||||||
|
self:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- href
|
||||||
|
properties:
|
||||||
|
href:
|
||||||
|
type: string
|
||||||
|
description: "Url of the current result set"
|
||||||
|
example: https://cti.api.dev.crowdsec.net/v1/fire?page=3&since=4h
|
||||||
|
prev:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- href
|
||||||
|
properties:
|
||||||
|
href:
|
||||||
|
type: string
|
||||||
|
description: "Url of the previous page of result set"
|
||||||
|
example: https://cti.api.dev.crowdsec.net/v1/fire?page=2&since=4h
|
||||||
|
next:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- href
|
||||||
|
properties:
|
||||||
|
href:
|
||||||
|
type: string
|
||||||
|
description: "Url of the next page of result set"
|
||||||
|
example: https://cti.api.dev.crowdsec.net/v1/fire?page=4&since=4h
|
||||||
|
first:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- href
|
||||||
|
properties:
|
||||||
|
href:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
description: "Url of the first page of result set"
|
||||||
|
example: https://cti.api.dev.crowdsec.net/v1/fire?since=4
|
||||||
|
items:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/FireIPCTIResponse"
|
||||||
|
ErrorResponse:
|
||||||
|
type: "object"
|
||||||
|
required:
|
||||||
|
- "message"
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: "string"
|
||||||
|
description: "Error message"
|
||||||
|
errors:
|
||||||
|
type: "string"
|
||||||
|
description: "More details on individual errors"
|
||||||
|
title: "Error response"
|
||||||
|
description: "Error response return by the API"
|
636
pkg/cti/types.go
Normal file
636
pkg/cti/types.go
Normal file
|
@ -0,0 +1,636 @@
|
||||||
|
// Package cti provides primitives to interact with the openapi HTTP API.
|
||||||
|
//
|
||||||
|
// Code generated by github.com/deepmap/oapi-codegen/v2 version v2.1.0 DO NOT EDIT.
|
||||||
|
package cti
|
||||||
|
|
||||||
|
const (
|
||||||
|
Api_keyScopes = "api_key.Scopes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for CTIObjectBackgroundNoise.
|
||||||
|
const (
|
||||||
|
CTIObjectBackgroundNoiseHigh CTIObjectBackgroundNoise = "high"
|
||||||
|
CTIObjectBackgroundNoiseLow CTIObjectBackgroundNoise = "low"
|
||||||
|
CTIObjectBackgroundNoiseMedium CTIObjectBackgroundNoise = "medium"
|
||||||
|
CTIObjectBackgroundNoiseNone CTIObjectBackgroundNoise = "none"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for CTIObjectIpRange24Reputation.
|
||||||
|
const (
|
||||||
|
CTIObjectIpRange24ReputationKnown CTIObjectIpRange24Reputation = "known"
|
||||||
|
CTIObjectIpRange24ReputationMalicious CTIObjectIpRange24Reputation = "malicious"
|
||||||
|
CTIObjectIpRange24ReputationSafe CTIObjectIpRange24Reputation = "safe"
|
||||||
|
CTIObjectIpRange24ReputationSuspicious CTIObjectIpRange24Reputation = "suspicious"
|
||||||
|
CTIObjectIpRange24ReputationUnknown CTIObjectIpRange24Reputation = "unknown"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for CTIObjectIpRange24Score.
|
||||||
|
const (
|
||||||
|
CTIObjectIpRange24ScoreN0 CTIObjectIpRange24Score = 0
|
||||||
|
CTIObjectIpRange24ScoreN1 CTIObjectIpRange24Score = 1
|
||||||
|
CTIObjectIpRange24ScoreN2 CTIObjectIpRange24Score = 2
|
||||||
|
CTIObjectIpRange24ScoreN3 CTIObjectIpRange24Score = 3
|
||||||
|
CTIObjectIpRange24ScoreN4 CTIObjectIpRange24Score = 4
|
||||||
|
CTIObjectIpRange24ScoreN5 CTIObjectIpRange24Score = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for CTIObjectIpRangeScore.
|
||||||
|
const (
|
||||||
|
CTIObjectIpRangeScoreN0 CTIObjectIpRangeScore = 0
|
||||||
|
CTIObjectIpRangeScoreN1 CTIObjectIpRangeScore = 1
|
||||||
|
CTIObjectIpRangeScoreN2 CTIObjectIpRangeScore = 2
|
||||||
|
CTIObjectIpRangeScoreN3 CTIObjectIpRangeScore = 3
|
||||||
|
CTIObjectIpRangeScoreN4 CTIObjectIpRangeScore = 4
|
||||||
|
CTIObjectIpRangeScoreN5 CTIObjectIpRangeScore = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for CTIObjectReputation.
|
||||||
|
const (
|
||||||
|
CTIObjectReputationKnown CTIObjectReputation = "known"
|
||||||
|
CTIObjectReputationMalicious CTIObjectReputation = "malicious"
|
||||||
|
CTIObjectReputationSafe CTIObjectReputation = "safe"
|
||||||
|
CTIObjectReputationSuspicious CTIObjectReputation = "suspicious"
|
||||||
|
CTIObjectReputationUnknown CTIObjectReputation = "unknown"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for FireIPCTIResponseBackgroundNoise.
|
||||||
|
const (
|
||||||
|
FireIPCTIResponseBackgroundNoiseHigh FireIPCTIResponseBackgroundNoise = "high"
|
||||||
|
FireIPCTIResponseBackgroundNoiseLow FireIPCTIResponseBackgroundNoise = "low"
|
||||||
|
FireIPCTIResponseBackgroundNoiseMedium FireIPCTIResponseBackgroundNoise = "medium"
|
||||||
|
FireIPCTIResponseBackgroundNoiseNone FireIPCTIResponseBackgroundNoise = "none"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for FireIPCTIResponseIpRange24Reputation.
|
||||||
|
const (
|
||||||
|
FireIPCTIResponseIpRange24ReputationKnown FireIPCTIResponseIpRange24Reputation = "known"
|
||||||
|
FireIPCTIResponseIpRange24ReputationMalicious FireIPCTIResponseIpRange24Reputation = "malicious"
|
||||||
|
FireIPCTIResponseIpRange24ReputationSafe FireIPCTIResponseIpRange24Reputation = "safe"
|
||||||
|
FireIPCTIResponseIpRange24ReputationSuspicious FireIPCTIResponseIpRange24Reputation = "suspicious"
|
||||||
|
FireIPCTIResponseIpRange24ReputationUnknown FireIPCTIResponseIpRange24Reputation = "unknown"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for FireIPCTIResponseIpRange24Score.
|
||||||
|
const (
|
||||||
|
FireIPCTIResponseIpRange24ScoreN0 FireIPCTIResponseIpRange24Score = 0
|
||||||
|
FireIPCTIResponseIpRange24ScoreN1 FireIPCTIResponseIpRange24Score = 1
|
||||||
|
FireIPCTIResponseIpRange24ScoreN2 FireIPCTIResponseIpRange24Score = 2
|
||||||
|
FireIPCTIResponseIpRange24ScoreN3 FireIPCTIResponseIpRange24Score = 3
|
||||||
|
FireIPCTIResponseIpRange24ScoreN4 FireIPCTIResponseIpRange24Score = 4
|
||||||
|
FireIPCTIResponseIpRange24ScoreN5 FireIPCTIResponseIpRange24Score = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for FireIPCTIResponseIpRangeScore.
|
||||||
|
const (
|
||||||
|
FireIPCTIResponseIpRangeScoreN0 FireIPCTIResponseIpRangeScore = 0
|
||||||
|
FireIPCTIResponseIpRangeScoreN1 FireIPCTIResponseIpRangeScore = 1
|
||||||
|
FireIPCTIResponseIpRangeScoreN2 FireIPCTIResponseIpRangeScore = 2
|
||||||
|
FireIPCTIResponseIpRangeScoreN3 FireIPCTIResponseIpRangeScore = 3
|
||||||
|
FireIPCTIResponseIpRangeScoreN4 FireIPCTIResponseIpRangeScore = 4
|
||||||
|
FireIPCTIResponseIpRangeScoreN5 FireIPCTIResponseIpRangeScore = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for FireIPCTIResponseReputation.
|
||||||
|
const (
|
||||||
|
FireIPCTIResponseReputationKnown FireIPCTIResponseReputation = "known"
|
||||||
|
FireIPCTIResponseReputationMalicious FireIPCTIResponseReputation = "malicious"
|
||||||
|
FireIPCTIResponseReputationSafe FireIPCTIResponseReputation = "safe"
|
||||||
|
FireIPCTIResponseReputationSuspicious FireIPCTIResponseReputation = "suspicious"
|
||||||
|
FireIPCTIResponseReputationUnknown FireIPCTIResponseReputation = "unknown"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for FireIPCTIResponseState.
|
||||||
|
const (
|
||||||
|
Refused FireIPCTIResponseState = "refused"
|
||||||
|
Validated FireIPCTIResponseState = "validated"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CTIObject defines model for CTIObject.
|
||||||
|
type CTIObject struct {
|
||||||
|
// AsName The autonomous system name to which the IP belongs
|
||||||
|
AsName *string `json:"as_name"`
|
||||||
|
|
||||||
|
// AsNum The autonomous system number to which the IP belongs
|
||||||
|
AsNum *float32 `json:"as_num"`
|
||||||
|
|
||||||
|
// AttackDetails A more exhaustive list of the scenarios for which a given IP was reported
|
||||||
|
AttackDetails []struct {
|
||||||
|
// Description Human-friendly descriptions of scenarios
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Label Human-friendly descriptions of scenarios
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// Name Name of the scenario (see hub.crowdsec.net)
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
References *[]string `json:"references,omitempty"`
|
||||||
|
} `json:"attack_details"`
|
||||||
|
|
||||||
|
// BackgroundNoise The background noise level of the IP address
|
||||||
|
BackgroundNoise *CTIObjectBackgroundNoise `json:"background_noise"`
|
||||||
|
|
||||||
|
// BackgroundNoiseScore The background noise score of the IP ranging from 0 to 10 (highly noisy)
|
||||||
|
BackgroundNoiseScore *float32 `json:"background_noise_score"`
|
||||||
|
|
||||||
|
// Behaviors A list of the attack categories for which the IP was reported
|
||||||
|
Behaviors []struct {
|
||||||
|
// Description Human-friendly description of the category
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Label Human-friendly description of the category
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// Name The category of the attack, often in the form "protocol-or-scope:attack_type"
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
} `json:"behaviors"`
|
||||||
|
Classifications struct {
|
||||||
|
// Classifications A list of categories associated with the IP. Those data can be sourced from 3rd parties (i.e. tor exit nodes list)
|
||||||
|
Classifications *[]struct {
|
||||||
|
// Description Human-friendly description of the category
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Label Human-friendly name of the category
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// Name The name of the category, often in the form "protocol-or-scope:attack_type"
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
} `json:"classifications,omitempty"`
|
||||||
|
|
||||||
|
// FalsePositives A list of false positives tags associated with the IP. Any IP with `false_positives` tags shouldn't be considered as malicious
|
||||||
|
FalsePositives *[]struct {
|
||||||
|
// Description Human-friendly description of the category
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Label Human-friendly name of the category
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// Name The name of the false positive, often in the form "protocol-or-scope:attack_type"
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
} `json:"false_positives,omitempty"`
|
||||||
|
} `json:"classifications"`
|
||||||
|
|
||||||
|
// Cves A list of CVEs reported for this IP.
|
||||||
|
Cves []string `json:"cves"`
|
||||||
|
History struct {
|
||||||
|
// DaysAge Delta in days between first and last seen timestamps
|
||||||
|
DaysAge *float32 `json:"days_age,omitempty"`
|
||||||
|
|
||||||
|
// FirstSeen Date of the first time this IP was reported. Due to "progressive data degradation", this date might be later than the first time the IP was actually seen
|
||||||
|
FirstSeen *string `json:"first_seen,omitempty"`
|
||||||
|
|
||||||
|
// FullAge Delta in days between first seen and today
|
||||||
|
FullAge *float32 `json:"full_age,omitempty"`
|
||||||
|
|
||||||
|
// LastSeen Date of the last time this IP was reported
|
||||||
|
LastSeen *string `json:"last_seen,omitempty"`
|
||||||
|
} `json:"history"`
|
||||||
|
|
||||||
|
// Ip Requested IP
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
|
||||||
|
// IpRange The range to which the IP belongs
|
||||||
|
IpRange *string `json:"ip_range"`
|
||||||
|
|
||||||
|
// IpRange24 The /24 range to which the IP belongs
|
||||||
|
IpRange24 *string `json:"ip_range_24"`
|
||||||
|
|
||||||
|
// IpRange24Reputation The /24 range to which the IP belongs
|
||||||
|
IpRange24Reputation *CTIObjectIpRange24Reputation `json:"ip_range_24_reputation"`
|
||||||
|
|
||||||
|
// IpRange24Score The score of the /24 range (ip_range_24) the IP belongs to. 0 is good/unknown, 5 is worse
|
||||||
|
IpRange24Score *CTIObjectIpRange24Score `json:"ip_range_24_score"`
|
||||||
|
|
||||||
|
// IpRangeScore The score of the range (ip_range) the IP belongs to. 0 is good/unknown, 5 is worse
|
||||||
|
IpRangeScore CTIObjectIpRangeScore `json:"ip_range_score"`
|
||||||
|
|
||||||
|
// Location Location information about the IP address
|
||||||
|
Location struct {
|
||||||
|
// City The associated City of the IP
|
||||||
|
City *string `json:"city"`
|
||||||
|
|
||||||
|
// Country The two letters country code of the IP
|
||||||
|
Country *string `json:"country"`
|
||||||
|
|
||||||
|
// Latitude Coordinates of the IP
|
||||||
|
Latitude *float32 `json:"latitude"`
|
||||||
|
|
||||||
|
// Longitude Coordinates of the IP
|
||||||
|
Longitude *float32 `json:"longitude"`
|
||||||
|
} `json:"location"`
|
||||||
|
|
||||||
|
// MitreTechniques A list of Mitre Enterprise Techniques associated with the IP.
|
||||||
|
MitreTechniques []struct {
|
||||||
|
// Description Description of the Mitre technique
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Label The name of the Mitre technique
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// Name The ID of the Mitre technique"
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
} `json:"mitre_techniques"`
|
||||||
|
|
||||||
|
// References A list of the references for which the IP was see
|
||||||
|
References []struct {
|
||||||
|
// Description Human-friendly description of the reference
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Label Human-friendly description of the reference
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// Name The reference, often in the form "list:list_name"
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
} `json:"references"`
|
||||||
|
|
||||||
|
// Reputation The reputation of the IP address
|
||||||
|
Reputation CTIObjectReputation `json:"reputation"`
|
||||||
|
|
||||||
|
// ReverseDns Reverse dns lookup of the IP
|
||||||
|
ReverseDns *string `json:"reverse_dns"`
|
||||||
|
Scores struct {
|
||||||
|
LastDay *struct {
|
||||||
|
// Aggressiveness Last day aggressiveness score
|
||||||
|
Aggressiveness *float32 `json:"aggressiveness,omitempty"`
|
||||||
|
|
||||||
|
// Anomaly Last day anomaly score
|
||||||
|
Anomaly *float32 `json:"anomaly,omitempty"`
|
||||||
|
|
||||||
|
// Threat Last day threat score
|
||||||
|
Threat *float32 `json:"threat,omitempty"`
|
||||||
|
|
||||||
|
// Total Last day score
|
||||||
|
Total *float32 `json:"total,omitempty"`
|
||||||
|
|
||||||
|
// Trust Last day trust score
|
||||||
|
Trust *float32 `json:"trust,omitempty"`
|
||||||
|
} `json:"last_day,omitempty"`
|
||||||
|
LastMonth *struct {
|
||||||
|
// Aggressiveness Last month aggressiveness score
|
||||||
|
Aggressiveness *float32 `json:"aggressiveness,omitempty"`
|
||||||
|
|
||||||
|
// Anomaly Last month anomaly score
|
||||||
|
Anomaly *float32 `json:"anomaly,omitempty"`
|
||||||
|
|
||||||
|
// Threat Last month threat score
|
||||||
|
Threat *float32 `json:"threat,omitempty"`
|
||||||
|
|
||||||
|
// Total Last month score
|
||||||
|
Total *float32 `json:"total,omitempty"`
|
||||||
|
|
||||||
|
// Trust Last month trust score
|
||||||
|
Trust *float32 `json:"trust,omitempty"`
|
||||||
|
} `json:"last_month,omitempty"`
|
||||||
|
LastWeek *struct {
|
||||||
|
// Aggressiveness Last week aggressiveness score
|
||||||
|
Aggressiveness *float32 `json:"aggressiveness,omitempty"`
|
||||||
|
|
||||||
|
// Anomaly Last week anomaly score
|
||||||
|
Anomaly *float32 `json:"anomaly,omitempty"`
|
||||||
|
|
||||||
|
// Threat Last week threat score
|
||||||
|
Threat *float32 `json:"threat,omitempty"`
|
||||||
|
|
||||||
|
// Total Last week score
|
||||||
|
Total *float32 `json:"total,omitempty"`
|
||||||
|
|
||||||
|
// Trust Last week trust score
|
||||||
|
Trust *float32 `json:"trust,omitempty"`
|
||||||
|
} `json:"last_week,omitempty"`
|
||||||
|
Overall *struct {
|
||||||
|
// Aggressiveness Overall aggressiveness score
|
||||||
|
Aggressiveness *float32 `json:"aggressiveness,omitempty"`
|
||||||
|
|
||||||
|
// Anomaly Overall anomaly score
|
||||||
|
Anomaly *float32 `json:"anomaly,omitempty"`
|
||||||
|
|
||||||
|
// Threat Overall threat score
|
||||||
|
Threat *float32 `json:"threat,omitempty"`
|
||||||
|
|
||||||
|
// Total Overall score
|
||||||
|
Total *float32 `json:"total,omitempty"`
|
||||||
|
|
||||||
|
// Trust Overall trust score
|
||||||
|
Trust *float32 `json:"trust,omitempty"`
|
||||||
|
} `json:"overall,omitempty"`
|
||||||
|
} `json:"scores"`
|
||||||
|
|
||||||
|
// TargetCountries The top 10 reports repartition by country about the IP, as a percentage
|
||||||
|
TargetCountries map[string]interface{} `json:"target_countries"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CTIObjectBackgroundNoise The background noise level of the IP address
|
||||||
|
type CTIObjectBackgroundNoise string
|
||||||
|
|
||||||
|
// CTIObjectIpRange24Reputation The /24 range to which the IP belongs
|
||||||
|
type CTIObjectIpRange24Reputation string
|
||||||
|
|
||||||
|
// CTIObjectIpRange24Score The score of the /24 range (ip_range_24) the IP belongs to. 0 is good/unknown, 5 is worse
|
||||||
|
type CTIObjectIpRange24Score float32
|
||||||
|
|
||||||
|
// CTIObjectIpRangeScore The score of the range (ip_range) the IP belongs to. 0 is good/unknown, 5 is worse
|
||||||
|
type CTIObjectIpRangeScore float32
|
||||||
|
|
||||||
|
// CTIObjectReputation The reputation of the IP address
|
||||||
|
type CTIObjectReputation string
|
||||||
|
|
||||||
|
// ErrorResponse Error response return by the API
|
||||||
|
type ErrorResponse struct {
|
||||||
|
// Errors More details on individual errors
|
||||||
|
Errors *string `json:"errors,omitempty"`
|
||||||
|
|
||||||
|
// Message Error message
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FireCTIResponse defines model for FireCTIResponse.
|
||||||
|
type FireCTIResponse struct {
|
||||||
|
Links struct {
|
||||||
|
// First Url of the first page of result set
|
||||||
|
First struct {
|
||||||
|
Href *string `json:"href"`
|
||||||
|
} `json:"first"`
|
||||||
|
|
||||||
|
// Next Url of the next page of result set
|
||||||
|
Next struct {
|
||||||
|
Href string `json:"href"`
|
||||||
|
} `json:"next"`
|
||||||
|
|
||||||
|
// Prev Url of the previous page of result set
|
||||||
|
Prev *struct {
|
||||||
|
Href string `json:"href"`
|
||||||
|
} `json:"prev,omitempty"`
|
||||||
|
|
||||||
|
// Self Url of the current result set
|
||||||
|
Self struct {
|
||||||
|
Href string `json:"href"`
|
||||||
|
} `json:"self"`
|
||||||
|
} `json:"_links"`
|
||||||
|
Items []FireIPCTIResponse `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FireIPCTIResponse defines model for FireIPCTIResponse.
|
||||||
|
type FireIPCTIResponse struct {
|
||||||
|
// AsName The autonomous system name to which the IP belongs
|
||||||
|
AsName *string `json:"as_name"`
|
||||||
|
|
||||||
|
// AsNum The autonomous system number to which the IP belongs
|
||||||
|
AsNum *float32 `json:"as_num"`
|
||||||
|
|
||||||
|
// AttackDetails A more exhaustive list of the scenarios for which a given IP was reported
|
||||||
|
AttackDetails []struct {
|
||||||
|
// Description Human-friendly descriptions of scenarios
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Label Human-friendly descriptions of scenarios
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// Name Name of the scenario (see hub.crowdsec.net)
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
References *[]string `json:"references,omitempty"`
|
||||||
|
} `json:"attack_details"`
|
||||||
|
|
||||||
|
// BackgroundNoise The background noise level of the IP address
|
||||||
|
BackgroundNoise *FireIPCTIResponseBackgroundNoise `json:"background_noise"`
|
||||||
|
|
||||||
|
// BackgroundNoiseScore The background noise score of the IP ranging from 0 to 10 (highly noisy)
|
||||||
|
BackgroundNoiseScore *float32 `json:"background_noise_score"`
|
||||||
|
|
||||||
|
// Behaviors A list of the attack categories for which the IP was reported
|
||||||
|
Behaviors []struct {
|
||||||
|
// Description Human-friendly description of the category
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Label Human-friendly description of the category
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// Name The category of the attack, often in the form "protocol-or-scope:attack_type"
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
} `json:"behaviors"`
|
||||||
|
Classifications struct {
|
||||||
|
// Classifications A list of categories associated with the IP. Those data can be sourced from 3rd parties (i.e. tor exit nodes list)
|
||||||
|
Classifications *[]struct {
|
||||||
|
// Description Human-friendly description of the category
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Label Human-friendly name of the category
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// Name The name of the category, often in the form "protocol-or-scope:attack_type"
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
} `json:"classifications,omitempty"`
|
||||||
|
|
||||||
|
// FalsePositives A list of false positives tags associated with the IP. Any IP with `false_positives` tags shouldn't be considered as malicious
|
||||||
|
FalsePositives *[]struct {
|
||||||
|
// Description Human-friendly description of the category
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Label Human-friendly name of the category
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// Name The name of the false positive, often in the form "protocol-or-scope:attack_type"
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
} `json:"false_positives,omitempty"`
|
||||||
|
} `json:"classifications"`
|
||||||
|
|
||||||
|
// Cves A list of CVEs reported for this IP.
|
||||||
|
Cves []string `json:"cves"`
|
||||||
|
|
||||||
|
// Expiration Date at which the IP address expire from the community blocklist
|
||||||
|
Expiration *string `json:"expiration,omitempty"`
|
||||||
|
History struct {
|
||||||
|
// DaysAge Delta in days between first and last seen timestamps
|
||||||
|
DaysAge *float32 `json:"days_age,omitempty"`
|
||||||
|
|
||||||
|
// FirstSeen Date of the first time this IP was reported. Due to "progressive data degradation", this date might be later than the first time the IP was actually seen
|
||||||
|
FirstSeen *string `json:"first_seen,omitempty"`
|
||||||
|
|
||||||
|
// FullAge Delta in days between first seen and today
|
||||||
|
FullAge *float32 `json:"full_age,omitempty"`
|
||||||
|
|
||||||
|
// LastSeen Date of the last time this IP was reported
|
||||||
|
LastSeen *string `json:"last_seen,omitempty"`
|
||||||
|
} `json:"history"`
|
||||||
|
|
||||||
|
// Ip Requested IP
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
|
||||||
|
// IpRange The range to which the IP belongs
|
||||||
|
IpRange *string `json:"ip_range"`
|
||||||
|
|
||||||
|
// IpRange24 The /24 range to which the IP belongs
|
||||||
|
IpRange24 *string `json:"ip_range_24"`
|
||||||
|
|
||||||
|
// IpRange24Reputation The /24 range to which the IP belongs
|
||||||
|
IpRange24Reputation *FireIPCTIResponseIpRange24Reputation `json:"ip_range_24_reputation"`
|
||||||
|
|
||||||
|
// IpRange24Score The score of the /24 range (ip_range_24) the IP belongs to. 0 is good/unknown, 5 is worse
|
||||||
|
IpRange24Score *FireIPCTIResponseIpRange24Score `json:"ip_range_24_score"`
|
||||||
|
|
||||||
|
// IpRangeScore The score of the range (ip_range) the IP belongs to. 0 is good/unknown, 5 is worse
|
||||||
|
IpRangeScore FireIPCTIResponseIpRangeScore `json:"ip_range_score"`
|
||||||
|
|
||||||
|
// Location Location information about the IP address
|
||||||
|
Location struct {
|
||||||
|
// City The associated City of the IP
|
||||||
|
City *string `json:"city"`
|
||||||
|
|
||||||
|
// Country The two letters country code of the IP
|
||||||
|
Country *string `json:"country"`
|
||||||
|
|
||||||
|
// Latitude Coordinates of the IP
|
||||||
|
Latitude *float32 `json:"latitude"`
|
||||||
|
|
||||||
|
// Longitude Coordinates of the IP
|
||||||
|
Longitude *float32 `json:"longitude"`
|
||||||
|
} `json:"location"`
|
||||||
|
|
||||||
|
// MitreTechniques A list of Mitre Enterprise Techniques associated with the IP.
|
||||||
|
MitreTechniques []struct {
|
||||||
|
// Description Description of the Mitre technique
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Label The name of the Mitre technique
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// Name The ID of the Mitre technique"
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
} `json:"mitre_techniques"`
|
||||||
|
|
||||||
|
// References A list of the references for which the IP was see
|
||||||
|
References []struct {
|
||||||
|
// Description Human-friendly description of the reference
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
|
||||||
|
// Label Human-friendly description of the reference
|
||||||
|
Label *string `json:"label,omitempty"`
|
||||||
|
|
||||||
|
// Name The reference, often in the form "list:list_name"
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
} `json:"references"`
|
||||||
|
|
||||||
|
// Reputation The reputation of the IP address
|
||||||
|
Reputation FireIPCTIResponseReputation `json:"reputation"`
|
||||||
|
|
||||||
|
// ReverseDns Reverse dns lookup of the IP
|
||||||
|
ReverseDns *string `json:"reverse_dns"`
|
||||||
|
Scores struct {
|
||||||
|
LastDay *struct {
|
||||||
|
// Aggressiveness Last day aggressiveness score
|
||||||
|
Aggressiveness *float32 `json:"aggressiveness,omitempty"`
|
||||||
|
|
||||||
|
// Anomaly Last day anomaly score
|
||||||
|
Anomaly *float32 `json:"anomaly,omitempty"`
|
||||||
|
|
||||||
|
// Threat Last day threat score
|
||||||
|
Threat *float32 `json:"threat,omitempty"`
|
||||||
|
|
||||||
|
// Total Last day score
|
||||||
|
Total *float32 `json:"total,omitempty"`
|
||||||
|
|
||||||
|
// Trust Last day trust score
|
||||||
|
Trust *float32 `json:"trust,omitempty"`
|
||||||
|
} `json:"last_day,omitempty"`
|
||||||
|
LastMonth *struct {
|
||||||
|
// Aggressiveness Last month aggressiveness score
|
||||||
|
Aggressiveness *float32 `json:"aggressiveness,omitempty"`
|
||||||
|
|
||||||
|
// Anomaly Last month anomaly score
|
||||||
|
Anomaly *float32 `json:"anomaly,omitempty"`
|
||||||
|
|
||||||
|
// Threat Last month threat score
|
||||||
|
Threat *float32 `json:"threat,omitempty"`
|
||||||
|
|
||||||
|
// Total Last month score
|
||||||
|
Total *float32 `json:"total,omitempty"`
|
||||||
|
|
||||||
|
// Trust Last month trust score
|
||||||
|
Trust *float32 `json:"trust,omitempty"`
|
||||||
|
} `json:"last_month,omitempty"`
|
||||||
|
LastWeek *struct {
|
||||||
|
// Aggressiveness Last week aggressiveness score
|
||||||
|
Aggressiveness *float32 `json:"aggressiveness,omitempty"`
|
||||||
|
|
||||||
|
// Anomaly Last week anomaly score
|
||||||
|
Anomaly *float32 `json:"anomaly,omitempty"`
|
||||||
|
|
||||||
|
// Threat Last week threat score
|
||||||
|
Threat *float32 `json:"threat,omitempty"`
|
||||||
|
|
||||||
|
// Total Last week score
|
||||||
|
Total *float32 `json:"total,omitempty"`
|
||||||
|
|
||||||
|
// Trust Last week trust score
|
||||||
|
Trust *float32 `json:"trust,omitempty"`
|
||||||
|
} `json:"last_week,omitempty"`
|
||||||
|
Overall *struct {
|
||||||
|
// Aggressiveness Overall aggressiveness score
|
||||||
|
Aggressiveness *float32 `json:"aggressiveness,omitempty"`
|
||||||
|
|
||||||
|
// Anomaly Overall anomaly score
|
||||||
|
Anomaly *float32 `json:"anomaly,omitempty"`
|
||||||
|
|
||||||
|
// Threat Overall threat score
|
||||||
|
Threat *float32 `json:"threat,omitempty"`
|
||||||
|
|
||||||
|
// Total Overall score
|
||||||
|
Total *float32 `json:"total,omitempty"`
|
||||||
|
|
||||||
|
// Trust Overall trust score
|
||||||
|
Trust *float32 `json:"trust,omitempty"`
|
||||||
|
} `json:"overall,omitempty"`
|
||||||
|
} `json:"scores"`
|
||||||
|
|
||||||
|
// State state of the IP in the community blocklist: validated means IP is currently part of community blocklist, refused means it was part of the community blocklist, but was manually purged (ie. false positive)
|
||||||
|
State *FireIPCTIResponseState `json:"state,omitempty"`
|
||||||
|
|
||||||
|
// TargetCountries The top 10 reports repartition by country about the IP, as a percentage
|
||||||
|
TargetCountries map[string]interface{} `json:"target_countries"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FireIPCTIResponseBackgroundNoise The background noise level of the IP address
|
||||||
|
type FireIPCTIResponseBackgroundNoise string
|
||||||
|
|
||||||
|
// FireIPCTIResponseIpRange24Reputation The /24 range to which the IP belongs
|
||||||
|
type FireIPCTIResponseIpRange24Reputation string
|
||||||
|
|
||||||
|
// FireIPCTIResponseIpRange24Score The score of the /24 range (ip_range_24) the IP belongs to. 0 is good/unknown, 5 is worse
|
||||||
|
type FireIPCTIResponseIpRange24Score float32
|
||||||
|
|
||||||
|
// FireIPCTIResponseIpRangeScore The score of the range (ip_range) the IP belongs to. 0 is good/unknown, 5 is worse
|
||||||
|
type FireIPCTIResponseIpRangeScore float32
|
||||||
|
|
||||||
|
// FireIPCTIResponseReputation The reputation of the IP address
|
||||||
|
type FireIPCTIResponseReputation string
|
||||||
|
|
||||||
|
// FireIPCTIResponseState state of the IP in the community blocklist: validated means IP is currently part of community blocklist, refused means it was part of the community blocklist, but was manually purged (ie. false positive)
|
||||||
|
type FireIPCTIResponseState string
|
||||||
|
|
||||||
|
// QueryCTIResponse defines model for QueryCTIResponse.
|
||||||
|
type QueryCTIResponse = CTIObject
|
||||||
|
|
||||||
|
// SearchCTIResponse defines model for SearchCTIResponse.
|
||||||
|
type SearchCTIResponse struct {
|
||||||
|
Items []CTIObject `json:"items"`
|
||||||
|
NotFound float32 `json:"not_found"`
|
||||||
|
|
||||||
|
// Total IP of the request
|
||||||
|
Total float32 `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFireParams defines parameters for GetFire.
|
||||||
|
type GetFireParams struct {
|
||||||
|
// Page The page to fetch
|
||||||
|
Page *float32 `form:"page,omitempty" json:"page,omitempty"`
|
||||||
|
|
||||||
|
// Limit The number of items to fetch
|
||||||
|
Limit *float32 `form:"limit,omitempty" json:"limit,omitempty"`
|
||||||
|
|
||||||
|
// Since Filter records updated since - duration in h (hours), d(days), m(minutes) )
|
||||||
|
Since *string `form:"since,omitempty" json:"since,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSmokeParams defines parameters for GetSmoke.
|
||||||
|
type GetSmokeParams struct {
|
||||||
|
// Ips List of IPs to query, separated by comma
|
||||||
|
Ips string `form:"ips" json:"ips"`
|
||||||
|
}
|
|
@ -1,13 +1,14 @@
|
||||||
package exprhelpers
|
package exprhelpers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bluele/gcache"
|
"github.com/bluele/gcache"
|
||||||
"github.com/crowdsecurity/crowdsec/pkg/cticlient"
|
"github.com/crowdsecurity/crowdsec/pkg/cti"
|
||||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||||
"github.com/pkg/errors"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,12 +23,14 @@ var CTIApiEnabled = false
|
||||||
var CTIBackOffUntil time.Time
|
var CTIBackOffUntil time.Time
|
||||||
var CTIBackOffDuration time.Duration = 5 * time.Minute
|
var CTIBackOffDuration time.Duration = 5 * time.Minute
|
||||||
|
|
||||||
var ctiClient *cticlient.CrowdsecCTIClient
|
var ctiClient *cti.ClientWithResponses
|
||||||
|
var ctiLogger *log.Entry
|
||||||
|
|
||||||
func InitCrowdsecCTI(Key *string, TTL *time.Duration, Size *int, LogLevel *log.Level) error {
|
func InitCrowdsecCTI(Key *string, TTL *time.Duration, Size *int, LogLevel *log.Level) error {
|
||||||
|
var err error
|
||||||
if Key == nil || *Key == "" {
|
if Key == nil || *Key == "" {
|
||||||
log.Warningf("CTI API key not set or empty, CTI will not be available")
|
log.Warningf("CTI API key not set or empty, CTI will not be available")
|
||||||
return cticlient.ErrDisabled
|
return cti.ErrDisabled
|
||||||
}
|
}
|
||||||
CTIApiKey = *Key
|
CTIApiKey = *Key
|
||||||
if Size == nil {
|
if Size == nil {
|
||||||
|
@ -40,7 +43,7 @@ func InitCrowdsecCTI(Key *string, TTL *time.Duration, Size *int, LogLevel *log.L
|
||||||
}
|
}
|
||||||
clog := log.New()
|
clog := log.New()
|
||||||
if err := types.ConfigureLogger(clog); err != nil {
|
if err := types.ConfigureLogger(clog); err != nil {
|
||||||
return errors.Wrap(err, "while configuring datasource logger")
|
return fmt.Errorf("while configuring datasource logger: %w", err)
|
||||||
}
|
}
|
||||||
if LogLevel != nil {
|
if LogLevel != nil {
|
||||||
clog.SetLevel(*LogLevel)
|
clog.SetLevel(*LogLevel)
|
||||||
|
@ -49,8 +52,12 @@ func InitCrowdsecCTI(Key *string, TTL *time.Duration, Size *int, LogLevel *log.L
|
||||||
"type": "crowdsec-cti",
|
"type": "crowdsec-cti",
|
||||||
}
|
}
|
||||||
subLogger := clog.WithFields(customLog)
|
subLogger := clog.WithFields(customLog)
|
||||||
|
ctiLogger = subLogger
|
||||||
CrowdsecCTIInitCache(*Size, *TTL)
|
CrowdsecCTIInitCache(*Size, *TTL)
|
||||||
ctiClient = cticlient.NewCrowdsecCTIClient(cticlient.WithAPIKey(CTIApiKey), cticlient.WithLogger(subLogger))
|
ctiClient, err = cti.NewCTIClient(CTIApiKey)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("while creating CTI client: %w", err)
|
||||||
|
}
|
||||||
CTIApiEnabled = true
|
CTIApiEnabled = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -72,22 +79,22 @@ func CrowdsecCTIInitCache(size int, ttl time.Duration) {
|
||||||
CacheExpiration = ttl
|
CacheExpiration = ttl
|
||||||
}
|
}
|
||||||
|
|
||||||
// func CrowdsecCTI(ip string) (*cticlient.SmokeItem, error) {
|
// func CrowdsecCTI(ip string) (*cti.CTIObject, error) {
|
||||||
func CrowdsecCTI(params ...any) (any, error) {
|
func CrowdsecCTI(params ...any) (any, error) {
|
||||||
var ip string
|
var ip string
|
||||||
if !CTIApiEnabled {
|
if !CTIApiEnabled {
|
||||||
return &cticlient.SmokeItem{}, cticlient.ErrDisabled
|
return &cti.CTIObject{}, cti.ErrDisabled
|
||||||
}
|
}
|
||||||
var ok bool
|
var ok bool
|
||||||
if ip, ok = params[0].(string); !ok {
|
if ip, ok = params[0].(string); !ok {
|
||||||
return &cticlient.SmokeItem{}, fmt.Errorf("invalid type for ip : %T", params[0])
|
return &cti.CTIObject{}, fmt.Errorf("invalid type for ip : %T", params[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, err := CTICache.Get(ip); err == nil && val != nil {
|
if val, err := CTICache.Get(ip); err == nil && val != nil {
|
||||||
ctiClient.Logger.Debugf("cti cache fetch for %s", ip)
|
ctiLogger.Debugf("cti cache fetch for %s", ip)
|
||||||
ret, ok := val.(*cticlient.SmokeItem)
|
ret, ok := val.(*cti.CTIObject)
|
||||||
if !ok {
|
if !ok {
|
||||||
ctiClient.Logger.Warningf("CrowdsecCTI: invalid type in cache, removing")
|
ctiLogger.Warningf("CrowdsecCTI: invalid type in cache, removing")
|
||||||
CTICache.Remove(ip)
|
CTICache.Remove(ip)
|
||||||
} else {
|
} else {
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
@ -96,35 +103,46 @@ func CrowdsecCTI(params ...any) (any, error) {
|
||||||
|
|
||||||
if !CTIBackOffUntil.IsZero() && time.Now().Before(CTIBackOffUntil) {
|
if !CTIBackOffUntil.IsZero() && time.Now().Before(CTIBackOffUntil) {
|
||||||
//ctiClient.Logger.Warningf("Crowdsec CTI client is in backoff mode, ending in %s", time.Until(CTIBackOffUntil))
|
//ctiClient.Logger.Warningf("Crowdsec CTI client is in backoff mode, ending in %s", time.Until(CTIBackOffUntil))
|
||||||
return &cticlient.SmokeItem{}, cticlient.ErrLimit
|
return &cti.CTIObject{}, cti.ErrLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
ctiClient.Logger.Infof("cti call for %s", ip)
|
ctiLogger.Infof("cti call for %s", ip)
|
||||||
before := time.Now()
|
before := time.Now()
|
||||||
ctiResp, err := ctiClient.GetIPInfo(ip)
|
ctx := context.Background() // XXX: timeout?
|
||||||
ctiClient.Logger.Debugf("request for %s took %v", ip, time.Since(before))
|
ctiResp, err := ctiClient.GetSmokeIpWithResponse(ctx, ip)
|
||||||
|
ctiLogger.Debugf("request for %s took %v", ip, time.Since(before))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
ctiLogger.Warnf("CTI API error: %s", err)
|
||||||
case errors.Is(err, cticlient.ErrUnauthorized):
|
return &cti.CTIObject{}, fmt.Errorf("unexpected error: %w", err)
|
||||||
CTIApiEnabled = false
|
}
|
||||||
ctiClient.Logger.Errorf("Invalid API key provided, disabling CTI API")
|
|
||||||
return &cticlient.SmokeItem{}, cticlient.ErrUnauthorized
|
switch {
|
||||||
case errors.Is(err, cticlient.ErrLimit):
|
case ctiResp.HTTPResponse != nil && ctiResp.HTTPResponse.StatusCode == 403:
|
||||||
CTIBackOffUntil = time.Now().Add(CTIBackOffDuration)
|
fmt.Printf("403 error, disabling CTI API\n")
|
||||||
ctiClient.Logger.Errorf("CTI API is throttled, will try again in %s", CTIBackOffDuration)
|
CTIApiEnabled = false
|
||||||
return &cticlient.SmokeItem{}, cticlient.ErrLimit
|
ctiLogger.Errorf("Invalid API key provided, disabling CTI API")
|
||||||
default:
|
return &cti.CTIObject{}, cti.ErrUnauthorized
|
||||||
ctiClient.Logger.Warnf("CTI API error : %s", err)
|
case ctiResp.HTTPResponse != nil && ctiResp.HTTPResponse.StatusCode == 429:
|
||||||
return &cticlient.SmokeItem{}, fmt.Errorf("unexpected error : %v", err)
|
CTIBackOffUntil = time.Now().Add(CTIBackOffDuration)
|
||||||
}
|
ctiLogger.Errorf("CTI API is throttled, will try again in %s", CTIBackOffDuration)
|
||||||
|
return &cti.CTIObject{}, cti.ErrLimit
|
||||||
|
case ctiResp.HTTPResponse != nil && ctiResp.HTTPResponse.StatusCode != 200:
|
||||||
|
ctiLogger.Warnf("CTI API error: %s", ctiResp.HTTPResponse.Status)
|
||||||
|
return &cti.CTIObject{}, fmt.Errorf("unexpected error: %s", ctiResp.HTTPResponse.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := CTICache.SetWithExpire(ip, ctiResp, CacheExpiration); err != nil {
|
if err := CTICache.SetWithExpire(ip, ctiResp, CacheExpiration); err != nil {
|
||||||
ctiClient.Logger.Warningf("IpCTI : error while caching CTI : %s", err)
|
ctiLogger.Warningf("IpCTI : error while caching CTI : %s", err)
|
||||||
return &cticlient.SmokeItem{}, cticlient.ErrUnknown
|
return &cti.CTIObject{}, cti.ErrUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
ctiClient.Logger.Tracef("CTI response : %v", *ctiResp)
|
ctiLogger.Tracef("CTI response: %s", ctiResp.Body)
|
||||||
|
|
||||||
return ctiResp, nil
|
var ctiObject cti.CTIObject
|
||||||
|
if err := json.Unmarshal(ctiResp.Body, &ctiObject); err != nil {
|
||||||
|
return &cti.CTIObject{}, fmt.Errorf("while unmarshaling CTI response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ctiObject, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package exprhelpers
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -12,54 +13,13 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/crowdsecurity/go-cs-lib/ptr"
|
"github.com/crowdsecurity/go-cs-lib/ptr"
|
||||||
|
|
||||||
"github.com/crowdsecurity/crowdsec/pkg/cticlient"
|
"github.com/crowdsecurity/crowdsec/pkg/cti"
|
||||||
)
|
)
|
||||||
|
|
||||||
var sampledata = map[string]cticlient.SmokeItem{
|
|
||||||
//1.2.3.4 is a known false positive
|
|
||||||
"1.2.3.4": {
|
|
||||||
Ip: "1.2.3.4",
|
|
||||||
Classifications: cticlient.CTIClassifications{
|
|
||||||
FalsePositives: []cticlient.CTIClassification{
|
|
||||||
{
|
|
||||||
Name: "example_false_positive",
|
|
||||||
Label: "Example False Positive",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
//1.2.3.5 is a known bad-guy, and part of FIRE
|
|
||||||
"1.2.3.5": {
|
|
||||||
Ip: "1.2.3.5",
|
|
||||||
Classifications: cticlient.CTIClassifications{
|
|
||||||
Classifications: []cticlient.CTIClassification{
|
|
||||||
{
|
|
||||||
Name: "community-blocklist",
|
|
||||||
Label: "CrowdSec Community Blocklist",
|
|
||||||
Description: "IP belong to the CrowdSec Community Blocklist",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
//1.2.3.6 is a bad guy (high bg noise), but not in FIRE
|
|
||||||
"1.2.3.6": {
|
|
||||||
Ip: "1.2.3.6",
|
|
||||||
BackgroundNoiseScore: new(int),
|
|
||||||
Behaviors: []*cticlient.CTIBehavior{
|
|
||||||
{Name: "ssh:bruteforce", Label: "SSH Bruteforce", Description: "SSH Bruteforce"},
|
|
||||||
},
|
|
||||||
AttackDetails: []*cticlient.CTIAttackDetails{
|
|
||||||
{Name: "crowdsecurity/ssh-bf", Label: "Example Attack"},
|
|
||||||
{Name: "crowdsecurity/ssh-slow-bf", Label: "Example Attack"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
//1.2.3.7 is a ok guy, but part of a bad range
|
|
||||||
"1.2.3.7": {},
|
|
||||||
}
|
|
||||||
|
|
||||||
const validApiKey = "my-api-key"
|
const validApiKey = "my-api-key"
|
||||||
|
|
||||||
type RoundTripFunc func(req *http.Request) *http.Response
|
type RoundTripFunc func(req *http.Request) *http.Response
|
||||||
|
@ -80,6 +40,47 @@ func smokeHandler(req *http.Request) *http.Response {
|
||||||
|
|
||||||
requestedIP := strings.Split(req.URL.Path, "/")[3]
|
requestedIP := strings.Split(req.URL.Path, "/")[3]
|
||||||
|
|
||||||
|
//nolint: dupword
|
||||||
|
sampleString := `
|
||||||
|
# 1.2.3.4 is a known false positive
|
||||||
|
1.2.3.4:
|
||||||
|
ip: "1.2.3.4"
|
||||||
|
classifications:
|
||||||
|
false_positives:
|
||||||
|
-
|
||||||
|
name: "example_false_positive"
|
||||||
|
label: "Example False Positive"
|
||||||
|
# 1.2.3.5 is a known bad-guy, and part of FIRE
|
||||||
|
1.2.3.5:
|
||||||
|
ip: 1.2.3.5
|
||||||
|
classifications:
|
||||||
|
classifications:
|
||||||
|
-
|
||||||
|
name: "community-blocklist"
|
||||||
|
label: "CrowdSec Community Blocklist"
|
||||||
|
description: "IP belong to the CrowdSec Community Blocklist"
|
||||||
|
# 1.2.3.6 is a bad guy (high bg noise), but not in FIRE
|
||||||
|
1.2.3.6:
|
||||||
|
ip: 1.2.3.6
|
||||||
|
background_noise_score: 0
|
||||||
|
behaviors:
|
||||||
|
-
|
||||||
|
name: "ssh:bruteforce"
|
||||||
|
label: "SSH Bruteforce"
|
||||||
|
description: "SSH Bruteforce"
|
||||||
|
attack_details:
|
||||||
|
-
|
||||||
|
name: "crowdsecurity/ssh-bf"
|
||||||
|
label: "Example Attack"
|
||||||
|
-
|
||||||
|
name: "crowdsecurity/ssh-slow-bf"
|
||||||
|
label: "Example Attack"`
|
||||||
|
sampledata := make(map[string]cti.CTIObject)
|
||||||
|
err := yaml.Unmarshal([]byte(sampleString), &sampledata)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to unmarshal sample data: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
sample, ok := sampledata[requestedIP]
|
sample, ok := sampledata[requestedIP]
|
||||||
if !ok {
|
if !ok {
|
||||||
return &http.Response{
|
return &http.Response{
|
||||||
|
@ -112,79 +113,103 @@ func smokeHandler(req *http.Request) *http.Response {
|
||||||
func TestNillClient(t *testing.T) {
|
func TestNillClient(t *testing.T) {
|
||||||
defer ShutdownCrowdsecCTI()
|
defer ShutdownCrowdsecCTI()
|
||||||
|
|
||||||
if err := InitCrowdsecCTI(ptr.Of(""), nil, nil, nil); !errors.Is(err, cticlient.ErrDisabled) {
|
if err := InitCrowdsecCTI(ptr.Of(""), nil, nil, nil); !errors.Is(err, cti.ErrDisabled) {
|
||||||
t.Fatalf("failed to init CTI : %s", err)
|
t.Fatalf("failed to init CTI : %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
item, err := CrowdsecCTI("1.2.3.4")
|
item, err := CrowdsecCTI("1.2.3.4")
|
||||||
assert.Equal(t, err, cticlient.ErrDisabled)
|
assert.Equal(t, err, cti.ErrDisabled)
|
||||||
assert.Equal(t, item, &cticlient.SmokeItem{})
|
assert.Equal(t, &cti.CTIObject{}, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInvalidAuth(t *testing.T) {
|
func TestInvalidAuth(t *testing.T) {
|
||||||
defer ShutdownCrowdsecCTI()
|
defer ShutdownCrowdsecCTI()
|
||||||
|
badKey := "asdasd"
|
||||||
if err := InitCrowdsecCTI(ptr.Of("asdasd"), nil, nil, nil); err != nil {
|
if err := InitCrowdsecCTI(&badKey, nil, nil, nil); err != nil {
|
||||||
t.Fatalf("failed to init CTI : %s", err)
|
t.Fatalf("failed to init CTI : %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
badProvider, err := cti.NewAPIKeyProvider(badKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
//Replace the client created by InitCrowdsecCTI with one that uses a custom transport
|
//Replace the client created by InitCrowdsecCTI with one that uses a custom transport
|
||||||
ctiClient = cticlient.NewCrowdsecCTIClient(cticlient.WithAPIKey("asdasd"), cticlient.WithHTTPClient(&http.Client{
|
ctiClient, err = cti.NewClientWithResponses(CTIUrl+"/v2/", cti.WithRequestEditorFn(badProvider.Intercept), cti.WithHTTPClient(&http.Client{
|
||||||
Transport: RoundTripFunc(smokeHandler),
|
Transport: RoundTripFunc(smokeHandler),
|
||||||
}))
|
}))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.True(t, CTIApiEnabled)
|
||||||
item, err := CrowdsecCTI("1.2.3.4")
|
item, err := CrowdsecCTI("1.2.3.4")
|
||||||
assert.Equal(t, item, &cticlient.SmokeItem{})
|
require.False(t, CTIApiEnabled)
|
||||||
assert.False(t, CTIApiEnabled)
|
require.ErrorIs(t, err, cti.ErrUnauthorized)
|
||||||
assert.Equal(t, err, cticlient.ErrUnauthorized)
|
require.Equal(t, &cti.CTIObject{}, item)
|
||||||
|
|
||||||
|
provider, err := cti.NewAPIKeyProvider(validApiKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
//CTI is now disabled, all requests should return empty
|
//CTI is now disabled, all requests should return empty
|
||||||
ctiClient = cticlient.NewCrowdsecCTIClient(cticlient.WithAPIKey(validApiKey), cticlient.WithHTTPClient(&http.Client{
|
ctiClient, err = cti.NewClientWithResponses(CTIUrl+"/v2/", cti.WithRequestEditorFn(provider.Intercept), cti.WithHTTPClient(&http.Client{
|
||||||
Transport: RoundTripFunc(smokeHandler),
|
Transport: RoundTripFunc(smokeHandler),
|
||||||
}))
|
}))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
item, err = CrowdsecCTI("1.2.3.4")
|
item, err = CrowdsecCTI("1.2.3.4")
|
||||||
assert.Equal(t, item, &cticlient.SmokeItem{})
|
assert.Equal(t, &cti.CTIObject{}, item)
|
||||||
assert.False(t, CTIApiEnabled)
|
assert.False(t, CTIApiEnabled)
|
||||||
assert.Equal(t, err, cticlient.ErrDisabled)
|
assert.Equal(t, err, cti.ErrDisabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNoKey(t *testing.T) {
|
func TestNoKey(t *testing.T) {
|
||||||
defer ShutdownCrowdsecCTI()
|
defer ShutdownCrowdsecCTI()
|
||||||
|
|
||||||
err := InitCrowdsecCTI(nil, nil, nil, nil)
|
err := InitCrowdsecCTI(nil, nil, nil, nil)
|
||||||
require.ErrorIs(t, err, cticlient.ErrDisabled)
|
require.ErrorIs(t, err, cti.ErrDisabled)
|
||||||
|
|
||||||
|
|
||||||
|
provider, err := cti.NewAPIKeyProvider(validApiKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
//Replace the client created by InitCrowdsecCTI with one that uses a custom transport
|
//Replace the client created by InitCrowdsecCTI with one that uses a custom transport
|
||||||
ctiClient = cticlient.NewCrowdsecCTIClient(cticlient.WithAPIKey("asdasd"), cticlient.WithHTTPClient(&http.Client{
|
ctiClient, err = cti.NewClientWithResponses(CTIUrl+"/v2/", cti.WithRequestEditorFn(provider.Intercept), cti.WithHTTPClient(&http.Client{
|
||||||
Transport: RoundTripFunc(smokeHandler),
|
Transport: RoundTripFunc(smokeHandler),
|
||||||
}))
|
}))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
item, err := CrowdsecCTI("1.2.3.4")
|
item, err := CrowdsecCTI("1.2.3.4")
|
||||||
assert.Equal(t, item, &cticlient.SmokeItem{})
|
assert.Equal(t, &cti.CTIObject{}, item)
|
||||||
assert.False(t, CTIApiEnabled)
|
assert.False(t, CTIApiEnabled)
|
||||||
assert.Equal(t, err, cticlient.ErrDisabled)
|
assert.Equal(t, err, cti.ErrDisabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCache(t *testing.T) {
|
func TestCache(t *testing.T) {
|
||||||
defer ShutdownCrowdsecCTI()
|
defer ShutdownCrowdsecCTI()
|
||||||
|
var err error
|
||||||
|
|
||||||
cacheDuration := 1 * time.Second
|
cacheDuration := 1 * time.Second
|
||||||
if err := InitCrowdsecCTI(ptr.Of(validApiKey), &cacheDuration, nil, nil); err != nil {
|
if err := InitCrowdsecCTI(ptr.Of(validApiKey), &cacheDuration, nil, nil); err != nil {
|
||||||
t.Fatalf("failed to init CTI : %s", err)
|
t.Fatalf("failed to init CTI : %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
provider, err := cti.NewAPIKeyProvider(validApiKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
//Replace the client created by InitCrowdsecCTI with one that uses a custom transport
|
//Replace the client created by InitCrowdsecCTI with one that uses a custom transport
|
||||||
ctiClient = cticlient.NewCrowdsecCTIClient(cticlient.WithAPIKey(validApiKey), cticlient.WithHTTPClient(&http.Client{
|
ctiClient, err = cti.NewClientWithResponses(CTIUrl+"/v2/", cti.WithRequestEditorFn(provider.Intercept), cti.WithHTTPClient(&http.Client{
|
||||||
Transport: RoundTripFunc(smokeHandler),
|
Transport: RoundTripFunc(smokeHandler),
|
||||||
}))
|
}))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
item, err := CrowdsecCTI("1.2.3.4")
|
item, err := CrowdsecCTI("1.2.3.4")
|
||||||
ctiResp := item.(*cticlient.SmokeItem)
|
ctiResp := item.(*cti.CTIObject)
|
||||||
assert.Equal(t, "1.2.3.4", ctiResp.Ip)
|
assert.Equal(t, "1.2.3.4", ctiResp.Ip)
|
||||||
assert.True(t, CTIApiEnabled)
|
assert.True(t, CTIApiEnabled)
|
||||||
assert.Equal(t, 1, CTICache.Len(true))
|
assert.Equal(t, 1, CTICache.Len(true))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
item, err = CrowdsecCTI("1.2.3.4")
|
item, err = CrowdsecCTI("1.2.3.4")
|
||||||
ctiResp = item.(*cticlient.SmokeItem)
|
ctiResp = item.(*cti.CTIObject)
|
||||||
|
|
||||||
assert.Equal(t, "1.2.3.4", ctiResp.Ip)
|
assert.Equal(t, "1.2.3.4", ctiResp.Ip)
|
||||||
assert.True(t, CTIApiEnabled)
|
assert.True(t, CTIApiEnabled)
|
||||||
|
@ -196,7 +221,7 @@ func TestCache(t *testing.T) {
|
||||||
assert.Equal(t, 0, CTICache.Len(true))
|
assert.Equal(t, 0, CTICache.Len(true))
|
||||||
|
|
||||||
item, err = CrowdsecCTI("1.2.3.4")
|
item, err = CrowdsecCTI("1.2.3.4")
|
||||||
ctiResp = item.(*cticlient.SmokeItem)
|
ctiResp = item.(*cti.CTIObject)
|
||||||
|
|
||||||
assert.Equal(t, "1.2.3.4", ctiResp.Ip)
|
assert.Equal(t, "1.2.3.4", ctiResp.Ip)
|
||||||
assert.True(t, CTIApiEnabled)
|
assert.True(t, CTIApiEnabled)
|
||||||
|
|
|
@ -3,7 +3,7 @@ package exprhelpers
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/crowdsecurity/crowdsec/pkg/cticlient"
|
"github.com/crowdsecurity/crowdsec/pkg/cti"
|
||||||
)
|
)
|
||||||
|
|
||||||
type exprCustomFunc struct {
|
type exprCustomFunc struct {
|
||||||
|
@ -17,7 +17,7 @@ var exprFuncs = []exprCustomFunc{
|
||||||
name: "CrowdsecCTI",
|
name: "CrowdsecCTI",
|
||||||
function: CrowdsecCTI,
|
function: CrowdsecCTI,
|
||||||
signature: []interface{}{
|
signature: []interface{}{
|
||||||
new(func(string) (*cticlient.SmokeItem, error)),
|
new(func(string) (*cti.CTIObject, error)),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
//go:generate go run -mod=mod github.com/go-swagger/go-swagger/cmd/swagger@v0.30.5 generate model --spec=./localapi_swagger.yaml --target=../
|
//go:generate go run -mod=mod github.com/go-swagger/go-swagger/cmd/swagger@v0.30.5 generate model --spec=./localapi_swagger.yaml --quiet --target=../
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue