Merge branch 'crowdsecurity:master' into master
This commit is contained in:
commit
7b798c1f6d
6
.github/workflows/ci_go-test.yml
vendored
6
.github/workflows/ci_go-test.yml
vendored
|
@ -3,13 +3,14 @@ name: tests
|
|||
#those env variables are for localstack, so we can emulate aws services
|
||||
env:
|
||||
AWS_HOST: localstack
|
||||
SERVICES: cloudwatch,logs
|
||||
SERVICES: cloudwatch,logs,kinesis
|
||||
#those are to mimic aws config
|
||||
AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE
|
||||
AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
|
||||
AWS_REGION: us-east-1
|
||||
#and to override our endpoint in aws sdk
|
||||
AWS_ENDPOINT_FORCE: http://localhost:4566
|
||||
KINESIS_INITIALIZE_STREAMS: "stream-1-shard:1,stream-2-shards:2"
|
||||
|
||||
on:
|
||||
push:
|
||||
|
@ -32,7 +33,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
services:
|
||||
localstack:
|
||||
image: localstack/localstack:0.12.11
|
||||
image: localstack/localstack:0.13.3
|
||||
ports:
|
||||
- 4566:4566 # Localstack exposes all services on same port
|
||||
env:
|
||||
|
@ -43,6 +44,7 @@ jobs:
|
|||
KINESIS_ERROR_PROBABILITY: ""
|
||||
DOCKER_HOST: unix:///var/run/docker.sock
|
||||
HOST_TMP_FOLDER: "/tmp"
|
||||
KINESIS_INITIALIZE_STREAMS: ${{ env.KINESIS_INITIALIZE_STREAMS }}
|
||||
HOSTNAME_EXTERNAL: ${{ env.AWS_HOST }} # Required so that resource urls are provided properly
|
||||
# e.g sqs url will get localhost if we don't set this env to map our service
|
||||
options: >-
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -23,4 +23,4 @@ cmd/crowdsec/crowdsec
|
|||
plugins/notifications/http/notification-http
|
||||
plugins/notifications/slack/notification-slack
|
||||
plugins/notifications/splunk/notification-splunk
|
||||
|
||||
plugins/notifications/email/notification-email
|
||||
|
|
28
Makefile
28
Makefile
|
@ -15,15 +15,22 @@ DATA_PREFIX = $(PREFIX)"/var/run/crowdsec/"
|
|||
PID_DIR = $(PREFIX)"/var/run/"
|
||||
CROWDSEC_FOLDER = "./cmd/crowdsec"
|
||||
CSCLI_FOLDER = "./cmd/crowdsec-cli/"
|
||||
|
||||
HTTP_PLUGIN_FOLDER = "./plugins/notifications/http"
|
||||
SLACK_PLUGIN_FOLDER = "./plugins/notifications/slack"
|
||||
SPLUNK_PLUGIN_FOLDER = "./plugins/notifications/splunk"
|
||||
EMAIL_PLUGIN_FOLDER = "./plugins/notifications/email"
|
||||
|
||||
HTTP_PLUGIN_BIN = "notification-http"
|
||||
SLACK_PLUGIN_BIN = "notification-slack"
|
||||
SPLUNK_PLUGIN_BIN = "notification-splunk"
|
||||
EMAIL_PLUGIN_BIN = "notification-email"
|
||||
|
||||
HTTP_PLUGIN_CONFIG = "http.yaml"
|
||||
SLACK_PLUGIN_CONFIG = "slack.yaml"
|
||||
SPLUNK_PLUGIN_CONFIG = "splunk.yaml"
|
||||
EMAIL_PLUGIN_CONFIG = "email.yaml"
|
||||
|
||||
CROWDSEC_BIN = "crowdsec"
|
||||
CSCLI_BIN = "cscli"
|
||||
BUILD_CMD = "build"
|
||||
|
@ -66,9 +73,9 @@ build: goversion crowdsec cscli plugins
|
|||
|
||||
static: crowdsec_static cscli_static plugins_static
|
||||
|
||||
plugins: http-plugin slack-plugin splunk-plugin
|
||||
plugins: http-plugin slack-plugin splunk-plugin email-plugin
|
||||
|
||||
plugins_static: http-plugin_static slack-plugin_static splunk-plugin_static
|
||||
plugins_static: http-plugin_static slack-plugin_static splunk-plugin_static email-plugin_static
|
||||
|
||||
goversion:
|
||||
@if [ $(GO_MAJOR_VERSION) -gt $(MINIMUM_SUPPORTED_GO_MAJOR_VERSION) ]; then \
|
||||
|
@ -107,6 +114,8 @@ slack-plugin: goversion
|
|||
splunk-plugin: goversion
|
||||
@GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(SPLUNK_PLUGIN_FOLDER) build --no-print-directory
|
||||
|
||||
email-plugin: goversion
|
||||
@GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(EMAIL_PLUGIN_FOLDER) build --no-print-directory
|
||||
|
||||
cscli_static: goversion
|
||||
@GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(CSCLI_FOLDER) static --no-print-directory
|
||||
|
@ -123,6 +132,9 @@ slack-plugin_static: goversion
|
|||
splunk-plugin_static:goversion
|
||||
@GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(SPLUNK_PLUGIN_FOLDER) static --no-print-directory
|
||||
|
||||
email-plugin_static:goversion
|
||||
@GOARCH=$(GOARCH) GOOS=$(GOOS) $(MAKE) -C $(EMAIL_PLUGIN_FOLDER) static --no-print-directory
|
||||
|
||||
test: goversion
|
||||
@$(MAKE) -C $(CROWDSEC_FOLDER) test --no-print-directory
|
||||
|
||||
|
@ -133,15 +145,21 @@ package:
|
|||
@mkdir -p $(RELDIR)/$(subst ./,,$(HTTP_PLUGIN_FOLDER))
|
||||
@mkdir -p $(RELDIR)/$(subst ./,,$(SLACK_PLUGIN_FOLDER))
|
||||
@mkdir -p $(RELDIR)/$(subst ./,,$(SPLUNK_PLUGIN_FOLDER))
|
||||
@mkdir -p $(RELDIR)/$(subst ./,,$(EMAIL_PLUGIN_FOLDER))
|
||||
|
||||
@cp $(CROWDSEC_FOLDER)/$(CROWDSEC_BIN) $(RELDIR)/cmd/crowdsec
|
||||
@cp $(CSCLI_FOLDER)/$(CSCLI_BIN) $(RELDIR)/cmd/crowdsec-cli
|
||||
|
||||
@cp $(HTTP_PLUGIN_FOLDER)/$(HTTP_PLUGIN_BIN) $(RELDIR)/$(subst ./,,$(HTTP_PLUGIN_FOLDER))
|
||||
@cp $(SLACK_PLUGIN_FOLDER)/$(SLACK_PLUGIN_BIN) $(RELDIR)/$(subst ./,,$(SLACK_PLUGIN_FOLDER))
|
||||
@cp $(SPLUNK_PLUGIN_FOLDER)/$(SPLUNK_PLUGIN_BIN) $(RELDIR)/$(subst ./,,$(SPLUNK_PLUGIN_FOLDER))
|
||||
@cp $(EMAIL_PLUGIN_FOLDER)/$(EMAIL_PLUGIN_BIN) $(RELDIR)/$(subst ./,,$(EMAIL_PLUGIN_FOLDER))
|
||||
|
||||
@cp $(HTTP_PLUGIN_FOLDER)/$(HTTP_PLUGIN_CONFIG) $(RELDIR)/$(subst ./,,$(HTTP_PLUGIN_FOLDER))
|
||||
@cp $(SLACK_PLUGIN_FOLDER)/$(SLACK_PLUGIN_CONFIG) $(RELDIR)/$(subst ./,,$(SLACK_PLUGIN_FOLDER))
|
||||
@cp $(SPLUNK_PLUGIN_FOLDER)/$(SPLUNK_PLUGIN_CONFIG) $(RELDIR)/$(subst ./,,$(SPLUNK_PLUGIN_FOLDER))
|
||||
@cp $(EMAIL_PLUGIN_FOLDER)/$(EMAIL_PLUGIN_CONFIG) $(RELDIR)/$(subst ./,,$(EMAIL_PLUGIN_FOLDER))
|
||||
|
||||
@cp -R ./config/ $(RELDIR)
|
||||
@cp wizard.sh $(RELDIR)
|
||||
@cp scripts/test_env.sh $(RELDIR)
|
||||
|
@ -154,15 +172,21 @@ package_static:
|
|||
@mkdir -p $(RELDIR)/$(subst ./,,$(HTTP_PLUGIN_FOLDER))
|
||||
@mkdir -p $(RELDIR)/$(subst ./,,$(SLACK_PLUGIN_FOLDER))
|
||||
@mkdir -p $(RELDIR)/$(subst ./,,$(SPLUNK_PLUGIN_FOLDER))
|
||||
@mkdir -p $(RELDIR)/$(subst ./,,$(EMAIL_PLUGIN_FOLDER))
|
||||
|
||||
@cp $(CROWDSEC_FOLDER)/$(CROWDSEC_BIN) $(RELDIR)/cmd/crowdsec
|
||||
@cp $(CSCLI_FOLDER)/$(CSCLI_BIN) $(RELDIR)/cmd/crowdsec-cli
|
||||
|
||||
@cp $(HTTP_PLUGIN_FOLDER)/$(HTTP_PLUGIN_BIN) $(RELDIR)/$(subst ./,,$(HTTP_PLUGIN_FOLDER))
|
||||
@cp $(SLACK_PLUGIN_FOLDER)/$(SLACK_PLUGIN_BIN) $(RELDIR)/$(subst ./,,$(SLACK_PLUGIN_FOLDER))
|
||||
@cp $(SPLUNK_PLUGIN_FOLDER)/$(SPLUNK_PLUGIN_BIN) $(RELDIR)/$(subst ./,,$(SPLUNK_PLUGIN_FOLDER))
|
||||
@cp $(EMAIL_PLUGIN_FOLDER)/$(EMAIL_PLUGIN_BIN) $(RELDIR)/$(subst ./,,$(EMAIL_PLUGIN_FOLDER))
|
||||
|
||||
@cp $(HTTP_PLUGIN_FOLDER)/$(HTTP_PLUGIN_CONFIG) $(RELDIR)/$(subst ./,,$(HTTP_PLUGIN_FOLDER))
|
||||
@cp $(SLACK_PLUGIN_FOLDER)/$(SLACK_PLUGIN_CONFIG) $(RELDIR)/$(subst ./,,$(SLACK_PLUGIN_FOLDER))
|
||||
@cp $(SPLUNK_PLUGIN_FOLDER)/$(SPLUNK_PLUGIN_CONFIG) $(RELDIR)/$(subst ./,,$(SPLUNK_PLUGIN_FOLDER))
|
||||
@cp $(EMAIL_PLUGIN_FOLDER)/$(EMAIL_PLUGIN_CONFIG) $(RELDIR)/$(subst ./,,$(EMAIL_PLUGIN_FOLDER))
|
||||
|
||||
@cp -R ./config/ $(RELDIR)
|
||||
@cp wizard.sh $(RELDIR)
|
||||
@cp scripts/test_env.sh $(RELDIR)
|
||||
|
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
@ -48,15 +49,21 @@ func DecisionsFromAlert(alert *models.Alert) string {
|
|||
func AlertsToTable(alerts *models.GetAlertsResponse, printMachine bool) error {
|
||||
|
||||
if csConfig.Cscli.Output == "raw" {
|
||||
csvwriter := csv.NewWriter(os.Stdout)
|
||||
if printMachine {
|
||||
fmt.Printf("id,scope,value,reason,country,as,decisions,created_at,machine\n")
|
||||
err := csvwriter.Write([]string{"id", "scope", "value", "reason", "country", "as", "decisions", "created_at", "machine"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("id,scope,value,reason,country,as,decisions,created_at\n")
|
||||
err := csvwriter.Write([]string{"id", "scope", "value", "reason", "country", "as", "decisions", "created_at"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, alertItem := range *alerts {
|
||||
if printMachine {
|
||||
fmt.Printf("%v,%v,%v,%v,%v,%v,%v,%v,%v\n",
|
||||
alertItem.ID,
|
||||
row := []string{
|
||||
fmt.Sprintf("%d", alertItem.ID),
|
||||
*alertItem.Source.Scope,
|
||||
*alertItem.Source.Value,
|
||||
*alertItem.Scenario,
|
||||
|
@ -64,20 +71,16 @@ func AlertsToTable(alerts *models.GetAlertsResponse, printMachine bool) error {
|
|||
alertItem.Source.AsNumber + " " + alertItem.Source.AsName,
|
||||
DecisionsFromAlert(alertItem),
|
||||
*alertItem.StartAt,
|
||||
alertItem.MachineID)
|
||||
} else {
|
||||
fmt.Printf("%v,%v,%v,%v,%v,%v,%v,%v\n",
|
||||
alertItem.ID,
|
||||
*alertItem.Source.Scope,
|
||||
*alertItem.Source.Value,
|
||||
*alertItem.Scenario,
|
||||
alertItem.Source.Cn,
|
||||
alertItem.Source.AsNumber+" "+alertItem.Source.AsName,
|
||||
DecisionsFromAlert(alertItem),
|
||||
*alertItem.StartAt)
|
||||
}
|
||||
|
||||
if printMachine {
|
||||
row = append(row, alertItem.MachineID)
|
||||
}
|
||||
err := csvwriter.Write(row)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
csvwriter.Flush()
|
||||
} else if csConfig.Cscli.Output == "json" {
|
||||
x, _ := json.MarshalIndent(alerts, "", " ")
|
||||
fmt.Printf("%s", string(x))
|
||||
|
@ -143,7 +146,9 @@ func DisplayOneAlert(alert *models.Alert, withDetail bool) error {
|
|||
fmt.Printf(" - Events Count : %d\n", *alert.EventsCount)
|
||||
fmt.Printf(" - Scope:Value: %s\n", scopeAndValue)
|
||||
fmt.Printf(" - Country : %s\n", alert.Source.Cn)
|
||||
fmt.Printf(" - AS : %s\n\n", alert.Source.AsName)
|
||||
fmt.Printf(" - AS : %s\n", alert.Source.AsName)
|
||||
fmt.Printf(" - Begin : %s\n", *alert.StartAt)
|
||||
fmt.Printf(" - End : %s\n\n", *alert.StopAt)
|
||||
foundActive := false
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"ID", "scope:value", "action", "expiration", "created_at"})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
@ -82,6 +83,11 @@ Note: This command requires database direct access, so is intended to be run on
|
|||
}
|
||||
fmt.Printf("%s", string(x))
|
||||
} else if csConfig.Cscli.Output == "raw" {
|
||||
csvwriter := csv.NewWriter(os.Stdout)
|
||||
err := csvwriter.Write([]string{"name", "ip", "revoked", "last_pull", "type", "version"})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to write raw header: %s", err)
|
||||
}
|
||||
for _, b := range blockers {
|
||||
var revoked string
|
||||
if !b.Revoked {
|
||||
|
@ -89,9 +95,13 @@ Note: This command requires database direct access, so is intended to be run on
|
|||
} else {
|
||||
revoked = "pending"
|
||||
}
|
||||
fmt.Printf("%s,%s,%s,%s,%s\n", b.Name, b.IPAddress, revoked, b.LastPull.Format(time.RFC3339), b.Version)
|
||||
err := csvwriter.Write([]string{b.Name, b.IPAddress, revoked, b.LastPull.Format(time.RFC3339), b.Type, b.Version})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to write raw: %s", err)
|
||||
}
|
||||
}
|
||||
csvwriter.Flush()
|
||||
}
|
||||
},
|
||||
}
|
||||
cmdBouncers.AddCommand(cmdBouncersList)
|
||||
|
|
|
@ -76,6 +76,9 @@ func NewCollectionsCmd() *cobra.Command {
|
|||
for _, name := range args {
|
||||
if !forceAction {
|
||||
item := cwhub.GetItem(cwhub.COLLECTIONS, name)
|
||||
if item == nil {
|
||||
log.Fatalf("unable to retrieve: %s\n", name)
|
||||
}
|
||||
if len(item.BelongsToCollections) > 0 {
|
||||
log.Warningf("%s belongs to other collections :\n%s\n", name, item.BelongsToCollections)
|
||||
log.Printf("Run 'sudo cscli collections remove %s --force' if you want to force remove this sub collection\n", name)
|
||||
|
@ -133,16 +136,16 @@ func NewCollectionsCmd() *cobra.Command {
|
|||
|
||||
var cmdCollectionsList = &cobra.Command{
|
||||
Use: "list collection [-a]",
|
||||
Short: "List all collections or given one",
|
||||
Long: `List all collections or given one`,
|
||||
Short: "List all collections",
|
||||
Long: `List all collections`,
|
||||
Example: `cscli collections list`,
|
||||
Args: cobra.ExactArgs(0),
|
||||
DisableAutoGenTag: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ListItem(cwhub.COLLECTIONS, args)
|
||||
ListItems([]string{cwhub.COLLECTIONS}, args, false, true)
|
||||
},
|
||||
}
|
||||
cmdCollectionsList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List as well disabled items")
|
||||
cmdCollectionsList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well")
|
||||
cmdCollections.AddCommand(cmdCollectionsList)
|
||||
|
||||
return cmdCollections
|
||||
|
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
@ -52,23 +53,32 @@ func DecisionsToTable(alerts *models.GetAlertsResponse) error {
|
|||
alertItem.Decisions = newDecisions
|
||||
}
|
||||
if csConfig.Cscli.Output == "raw" {
|
||||
fmt.Printf("id,source,ip,reason,action,country,as,events_count,expiration,simulated,alert_id\n")
|
||||
csvwriter := csv.NewWriter(os.Stdout)
|
||||
err := csvwriter.Write([]string{"id", "source", "ip", "reason", "action", "country", "as", "events_count", "expiration", "simulated", "alert_id"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, alertItem := range *alerts {
|
||||
for _, decisionItem := range alertItem.Decisions {
|
||||
fmt.Printf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v\n",
|
||||
decisionItem.ID,
|
||||
err := csvwriter.Write([]string{
|
||||
fmt.Sprintf("%d", decisionItem.ID),
|
||||
*decisionItem.Origin,
|
||||
*decisionItem.Scope + ":" + *decisionItem.Value,
|
||||
*decisionItem.Scenario,
|
||||
*decisionItem.Type,
|
||||
alertItem.Source.Cn,
|
||||
alertItem.Source.AsNumber + " " + alertItem.Source.AsName,
|
||||
*alertItem.EventsCount,
|
||||
fmt.Sprintf("%d", *alertItem.EventsCount),
|
||||
*decisionItem.Duration,
|
||||
*decisionItem.Simulated,
|
||||
alertItem.ID)
|
||||
fmt.Sprintf("%t", *decisionItem.Simulated),
|
||||
fmt.Sprintf("%d", alertItem.ID),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
csvwriter.Flush()
|
||||
} else if csConfig.Cscli.Output == "json" {
|
||||
x, _ := json.MarshalIndent(alerts, "", " ")
|
||||
fmt.Printf("%s", string(x))
|
||||
|
@ -151,6 +161,7 @@ func NewDecisionsCmd() *cobra.Command {
|
|||
ValueEquals: new(string),
|
||||
ScopeEquals: new(string),
|
||||
ScenarioEquals: new(string),
|
||||
OriginEquals: new(string),
|
||||
IPEquals: new(string),
|
||||
RangeEquals: new(string),
|
||||
Since: new(string),
|
||||
|
@ -233,6 +244,10 @@ cscli decisions list -t ban
|
|||
filter.RangeEquals = nil
|
||||
}
|
||||
|
||||
if *filter.OriginEquals == "" {
|
||||
filter.OriginEquals = nil
|
||||
}
|
||||
|
||||
if contained != nil && *contained {
|
||||
filter.Contains = new(bool)
|
||||
}
|
||||
|
@ -254,6 +269,7 @@ cscli decisions list -t ban
|
|||
cmdDecisionsList.Flags().StringVar(filter.Until, "until", "", "restrict to alerts older than until (ie. 4h, 30d)")
|
||||
cmdDecisionsList.Flags().StringVarP(filter.TypeEquals, "type", "t", "", "restrict to this decision type (ie. ban,captcha)")
|
||||
cmdDecisionsList.Flags().StringVar(filter.ScopeEquals, "scope", "", "restrict to this scope (ie. ip,range,session)")
|
||||
cmdDecisionsList.Flags().StringVar(filter.OriginEquals, "origin", "", "restrict to this origin (ie. lists,CAPI,cscli)")
|
||||
cmdDecisionsList.Flags().StringVarP(filter.ValueEquals, "value", "v", "", "restrict to this value (ie. 1.2.3.4,userName)")
|
||||
cmdDecisionsList.Flags().StringVarP(filter.ScenarioEquals, "scenario", "s", "", "restrict to this scenario (ie. crowdsecurity/ssh-bf)")
|
||||
cmdDecisionsList.Flags().StringVarP(filter.IPEquals, "ip", "i", "", "restrict to alerts from this source ip (shorthand for --scope ip --value <IP>)")
|
||||
|
|
|
@ -56,17 +56,10 @@ cscli hub update # Download list of available configurations from the hub
|
|||
log.Info(v)
|
||||
}
|
||||
cwhub.DisplaySummary()
|
||||
log.Printf("PARSERS:")
|
||||
ListItem(cwhub.PARSERS, args)
|
||||
log.Printf("SCENARIOS:")
|
||||
ListItem(cwhub.SCENARIOS, args)
|
||||
log.Printf("COLLECTIONS:")
|
||||
ListItem(cwhub.COLLECTIONS, args)
|
||||
log.Printf("POSTOVERFLOWS:")
|
||||
ListItem(cwhub.PARSERS_OVFLW, args)
|
||||
ListItems([]string{cwhub.PARSERS, cwhub.COLLECTIONS, cwhub.SCENARIOS, cwhub.PARSERS_OVFLW}, args, true, false)
|
||||
},
|
||||
}
|
||||
cmdHubList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List as well disabled items")
|
||||
cmdHubList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well")
|
||||
cmdHub.AddCommand(cmdHubList)
|
||||
|
||||
var cmdHubUpdate = &cobra.Command{
|
||||
|
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
saferand "crypto/rand"
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
@ -144,7 +145,11 @@ Note: This command requires database direct access, so is intended to be run on
|
|||
}
|
||||
fmt.Printf("%s", string(x))
|
||||
} else if csConfig.Cscli.Output == "raw" {
|
||||
fmt.Printf("machine_id,ip_address,updated_at,validated,version\n")
|
||||
csvwriter := csv.NewWriter(os.Stdout)
|
||||
err := csvwriter.Write([]string{"machine_id", "ip_address", "updated_at", "validated", "version"})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to write header: %s", err)
|
||||
}
|
||||
for _, w := range machines {
|
||||
var validated string
|
||||
if w.IsValidated {
|
||||
|
@ -152,8 +157,12 @@ Note: This command requires database direct access, so is intended to be run on
|
|||
} else {
|
||||
validated = "false"
|
||||
}
|
||||
fmt.Printf("%s,%s,%s,%s,%s\n", w.MachineId, w.IpAddress, w.UpdatedAt.Format(time.RFC3339), validated, w.Version)
|
||||
err := csvwriter.Write([]string{w.MachineId, w.IpAddress, w.UpdatedAt.Format(time.RFC3339), validated, w.Version})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to write raw output : %s", err)
|
||||
}
|
||||
}
|
||||
csvwriter.Flush()
|
||||
} else {
|
||||
log.Errorf("unknown output '%s'", csConfig.Cscli.Output)
|
||||
}
|
||||
|
@ -247,7 +256,7 @@ cscli machines add MyTestMachine --password MyPassword
|
|||
if err != nil {
|
||||
log.Fatalf("unable to marshal api credentials: %s", err)
|
||||
}
|
||||
if dumpFile != "" {
|
||||
if dumpFile != "" && dumpFile != "-" {
|
||||
err = ioutil.WriteFile(dumpFile, apiConfigDump, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("write api credentials in '%s' failed: %s", dumpFile, err)
|
||||
|
|
|
@ -132,10 +132,10 @@ cscli parsers remove crowdsecurity/sshd-logs
|
|||
cscli parser list crowdsecurity/xxx`,
|
||||
DisableAutoGenTag: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ListItem(cwhub.PARSERS, args)
|
||||
ListItems([]string{cwhub.PARSERS}, args, false, true)
|
||||
},
|
||||
}
|
||||
cmdParsersList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List as well disabled items")
|
||||
cmdParsersList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well")
|
||||
cmdParsers.AddCommand(cmdParsersList)
|
||||
|
||||
return cmdParsers
|
||||
|
|
|
@ -130,10 +130,10 @@ func NewPostOverflowsCmd() *cobra.Command {
|
|||
cscli postoverflows list crowdsecurity/xxx`,
|
||||
DisableAutoGenTag: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ListItem(cwhub.PARSERS_OVFLW, args)
|
||||
ListItems([]string{cwhub.PARSERS_OVFLW}, args, false, true)
|
||||
},
|
||||
}
|
||||
cmdPostOverflowsList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List as well disabled items")
|
||||
cmdPostOverflowsList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well")
|
||||
cmdPostOverflows.AddCommand(cmdPostOverflowsList)
|
||||
|
||||
return cmdPostOverflows
|
||||
|
|
|
@ -132,10 +132,10 @@ cscli scenarios remove crowdsecurity/ssh-bf
|
|||
cscli scenarios list crowdsecurity/xxx`,
|
||||
DisableAutoGenTag: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ListItem(cwhub.SCENARIOS, args)
|
||||
ListItems([]string{cwhub.SCENARIOS}, args, false, true)
|
||||
},
|
||||
}
|
||||
cmdScenariosList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List as well disabled items")
|
||||
cmdScenariosList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well")
|
||||
cmdScenarios.AddCommand(cmdScenariosList)
|
||||
|
||||
return cmdScenarios
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
@ -67,7 +68,6 @@ func manageCliDecisionAlerts(ip *string, ipRange *string, scope *string, value *
|
|||
*scope = types.Country
|
||||
case "as":
|
||||
*scope = types.AS
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -101,44 +101,77 @@ func setHubBranch() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func ListItem(itemType string, args []string) {
|
||||
func ListItems(itemTypes []string, args []string, showType bool, showHeader bool) {
|
||||
|
||||
var hubStatus []map[string]string
|
||||
var hubStatusByItemType = make(map[string][]cwhub.ItemHubStatus)
|
||||
|
||||
for _, itemType := range itemTypes {
|
||||
if len(args) == 1 {
|
||||
hubStatus = cwhub.HubStatus(itemType, args[0], all)
|
||||
// This means that user requested a specific item by name
|
||||
hubStatusByItemType[itemType] = cwhub.GetHubStatusForItemType(itemType, args[0], all)
|
||||
} else {
|
||||
hubStatus = cwhub.HubStatus(itemType, "", all)
|
||||
hubStatusByItemType[itemType] = cwhub.GetHubStatusForItemType(itemType, "", all)
|
||||
}
|
||||
}
|
||||
|
||||
if csConfig.Cscli.Output == "human" {
|
||||
|
||||
for itemType, statuses := range hubStatusByItemType {
|
||||
fmt.Println(strings.ToUpper(itemType))
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetCenterSeparator("")
|
||||
table.SetColumnSeparator("")
|
||||
|
||||
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetHeader([]string{"Name", fmt.Sprintf("%v Status", emoji.Package), "Version", "Local Path"})
|
||||
for _, v := range hubStatus {
|
||||
table.Append([]string{v["name"], v["utf8_status"], v["local_version"], v["local_path"]})
|
||||
for _, status := range statuses {
|
||||
table.Append([]string{status.Name, status.UTF8_Status, status.LocalVersion, status.LocalPath})
|
||||
}
|
||||
table.Render()
|
||||
}
|
||||
} else if csConfig.Cscli.Output == "json" {
|
||||
x, err := json.MarshalIndent(hubStatus, "", " ")
|
||||
x, err := json.MarshalIndent(hubStatusByItemType, "", " ")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to unmarshal")
|
||||
}
|
||||
fmt.Printf("%s", string(x))
|
||||
} else if csConfig.Cscli.Output == "raw" {
|
||||
fmt.Printf("name,status,version,description\n")
|
||||
for _, v := range hubStatus {
|
||||
if v["local_version"] == "" {
|
||||
v["local_version"] = "n/a"
|
||||
csvwriter := csv.NewWriter(os.Stdout)
|
||||
if showHeader {
|
||||
if showType {
|
||||
err := csvwriter.Write([]string{"name", "status", "version", "description", "type"})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to write header: %s", err)
|
||||
}
|
||||
fmt.Printf("%s,%s,%s,%s\n", v["name"], v["status"], v["local_version"], v["description"])
|
||||
} else {
|
||||
err := csvwriter.Write([]string{"name", "status", "version", "description"})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to write header: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
for itemType, statuses := range hubStatusByItemType {
|
||||
for _, status := range statuses {
|
||||
if status.LocalVersion == "" {
|
||||
status.LocalVersion = "n/a"
|
||||
}
|
||||
row := []string{
|
||||
status.Name,
|
||||
status.Status,
|
||||
status.LocalVersion,
|
||||
status.Description,
|
||||
}
|
||||
if showType {
|
||||
row = append(row, itemType)
|
||||
}
|
||||
err := csvwriter.Write(row)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to write raw output : %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
csvwriter.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
func InstallItem(name string, obtype string, force bool) {
|
||||
|
@ -272,11 +305,25 @@ func InspectItem(name string, objecitemType string) {
|
|||
if hubItem == nil {
|
||||
log.Fatalf("unable to retrieve item.")
|
||||
}
|
||||
buff, err := yaml.Marshal(*hubItem)
|
||||
var b []byte
|
||||
var err error
|
||||
switch csConfig.Cscli.Output {
|
||||
case "human", "raw":
|
||||
b, err = yaml.Marshal(*hubItem)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to marshal item : %s", err)
|
||||
}
|
||||
fmt.Printf("%s", string(buff))
|
||||
case "json":
|
||||
b, err = json.MarshalIndent(*hubItem, "", " ")
|
||||
if err != nil {
|
||||
log.Fatalf("unable to marshal item : %s", err)
|
||||
}
|
||||
}
|
||||
fmt.Printf("%s", string(b))
|
||||
if csConfig.Cscli.Output == "json" || csConfig.Cscli.Output == "raw" {
|
||||
return
|
||||
}
|
||||
|
||||
if csConfig.Prometheus.Enabled {
|
||||
if csConfig.Prometheus.ListenAddr == "" || csConfig.Prometheus.ListenPort == 0 {
|
||||
log.Warningf("No prometheus address or port specified in '%s', can't show metrics", *csConfig.FilePath)
|
||||
|
|
|
@ -9,4 +9,5 @@ decisions:
|
|||
# - slack_default # Set the webhook in /etc/crowdsec/notifications/slack.yaml before enabling this.
|
||||
# - splunk_default # Set the splunk url and token in /etc/crowdsec/notifications/splunk.yaml before enabling this.
|
||||
# - http_default # Set the required http parameters in /etc/crowdsec/notifications/http.yaml before enabling this.
|
||||
# - email_default # Set the required http parameters in /etc/crowdsec/notifications/email.yaml before enabling this.
|
||||
on_success: break
|
||||
|
|
8
go.mod
8
go.mod
|
@ -10,7 +10,7 @@ require (
|
|||
github.com/alexliesenfeld/health v0.5.1
|
||||
github.com/antonmedv/expr v1.8.9
|
||||
github.com/appleboy/gin-jwt/v2 v2.6.4
|
||||
github.com/aws/aws-sdk-go v1.38.34
|
||||
github.com/aws/aws-sdk-go v1.42.25
|
||||
github.com/buger/jsonparser v1.1.1
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||
github.com/crowdsecurity/grokky v0.0.0-20210908095311-0b3373925934
|
||||
|
@ -24,7 +24,7 @@ require (
|
|||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/go-co-op/gocron v1.9.0
|
||||
github.com/go-openapi/errors v0.19.9
|
||||
github.com/go-openapi/errors v0.20.1
|
||||
github.com/go-openapi/strfmt v0.19.11
|
||||
github.com/go-openapi/swag v0.19.12
|
||||
github.com/go-openapi/validate v0.20.0
|
||||
|
@ -129,10 +129,10 @@ require (
|
|||
github.com/vjeantet/grok v1.0.1 // indirect
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||
go.mongodb.org/mongo-driver v1.4.4 // indirect
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
|
||||
golang.org/x/text v0.3.5 // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
google.golang.org/appengine v1.6.6 // indirect
|
||||
google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
|
|
9
go.sum
9
go.sum
|
@ -80,6 +80,8 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN
|
|||
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
|
||||
github.com/aws/aws-sdk-go v1.38.34 h1:JSAyS6hSDLbRmCAz9VAkwDf5oh/olt9mBTrVBWGJcU8=
|
||||
github.com/aws/aws-sdk-go v1.38.34/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.42.25 h1:BbdvHAi+t9LRiaYUyd53noq9jcaAcfzOhSVbKfr6Avs=
|
||||
github.com/aws/aws-sdk-go v1.42.25/go.mod h1:gyRszuZ/icHmHAVE4gc/r+cfCmhA1AD+vqfWbgI+eHs=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
|
@ -200,6 +202,8 @@ github.com/go-openapi/errors v0.19.7/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpX
|
|||
github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.19.9 h1:9SnKdGhiPZHF3ttwFMiCBEb8jQ4IDdrK+5+a0oTygA4=
|
||||
github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.20.1 h1:j23mMDtRxMwIobkpId7sWh7Ddcx4ivaoqUbfXx5P+a8=
|
||||
github.com/go-openapi/errors v0.20.1/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
|
@ -816,6 +820,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -876,6 +882,7 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210921065528-437939a70204 h1:JJhkWtBuTQKyz2bd5WG9H8iUsJRU3En/KRfN8B2RnDs=
|
||||
|
@ -891,6 +898,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
dockeracquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/docker"
|
||||
fileacquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/file"
|
||||
journalctlacquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/journalctl"
|
||||
kinesisacquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/kinesis"
|
||||
syslogacquisition "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/syslog"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
|
@ -60,6 +61,10 @@ var AcquisitionSources = []struct {
|
|||
name: "docker",
|
||||
iface: func() DataSource { return &dockeracquisition.DockerSource{} },
|
||||
},
|
||||
{
|
||||
name: "kinesis",
|
||||
iface: func() DataSource { return &kinesisacquisition.KinesisSource{} },
|
||||
},
|
||||
}
|
||||
|
||||
func GetDataSourceIface(dataSourceType string) DataSource {
|
||||
|
|
|
@ -109,7 +109,7 @@ func (d *DockerSource) Configure(Config []byte, logger *log.Entry) error {
|
|||
d.compiledContainerID = append(d.compiledContainerID, regexp.MustCompile(cont))
|
||||
}
|
||||
|
||||
dockerClient, err := client.NewClientWithOpts(client.FromEnv)
|
||||
dockerClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -136,6 +136,12 @@ func (d *DockerSource) Configure(Config []byte, logger *log.Entry) error {
|
|||
}
|
||||
d.Client = dockerClient
|
||||
|
||||
_, err = d.Client.Info(context.Background())
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to configure docker datasource %s", d.Config.DockerHost)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -158,7 +164,7 @@ func (d *DockerSource) ConfigureByDSN(dsn string, labels map[string]string, logg
|
|||
d.logger = logger
|
||||
d.Config.Labels = labels
|
||||
|
||||
dockerClient, err := client.NewClientWithOpts(client.FromEnv)
|
||||
dockerClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -389,7 +395,7 @@ func (d *DockerSource) WatchContainer(monitChan chan *ContainerConfig, deleteCha
|
|||
delete(d.runningContainerState, idx)
|
||||
}
|
||||
} else {
|
||||
log.Debugf("container list err: %s", err.Error())
|
||||
log.Errorf("container list err: %s", err.Error())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
|
510
pkg/acquisition/modules/kinesis/kinesis.go
Normal file
510
pkg/acquisition/modules/kinesis/kinesis.go
Normal file
|
@ -0,0 +1,510 @@
|
|||
package kinesisacquisition
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/arn"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/kinesis"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/acquisition/configuration"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/leakybucket"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/tomb.v2"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type KinesisConfiguration struct {
|
||||
configuration.DataSourceCommonCfg `yaml:",inline"`
|
||||
StreamName string `yaml:"stream_name"`
|
||||
StreamARN string `yaml:"stream_arn"`
|
||||
UseEnhancedFanOut bool `yaml:"use_enhanced_fanout"` //Use RegisterStreamConsumer and SubscribeToShard instead of GetRecords
|
||||
AwsProfile *string `yaml:"aws_profile"`
|
||||
AwsRegion string `yaml:"aws_region"`
|
||||
AwsEndpoint string `yaml:"aws_endpoint"`
|
||||
ConsumerName string `yaml:"consumer_name"`
|
||||
FromSubscription bool `yaml:"from_subscription"`
|
||||
MaxRetries int `yaml:"max_retries"`
|
||||
}
|
||||
|
||||
type KinesisSource struct {
|
||||
Config KinesisConfiguration
|
||||
logger *log.Entry
|
||||
kClient *kinesis.Kinesis
|
||||
shardReaderTomb *tomb.Tomb
|
||||
}
|
||||
|
||||
type CloudWatchSubscriptionRecord struct {
|
||||
MessageType string `json:"messageType"`
|
||||
Owner string `json:"owner"`
|
||||
LogGroup string `json:"logGroup"`
|
||||
LogStream string `json:"logStream"`
|
||||
SubscriptionFilters []string `json:"subscriptionFilters"`
|
||||
LogEvents []CloudwatchSubscriptionLogEvent `json:"logEvents"`
|
||||
}
|
||||
|
||||
type CloudwatchSubscriptionLogEvent struct {
|
||||
ID string `json:"id"`
|
||||
Message string `json:"message"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
var linesRead = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "cs_kinesis_stream_hits_total",
|
||||
Help: "Number of event read per stream.",
|
||||
},
|
||||
[]string{"stream"},
|
||||
)
|
||||
|
||||
var linesReadShards = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "cs_kinesis_shards_hits_total",
|
||||
Help: "Number of event read per shards.",
|
||||
},
|
||||
[]string{"stream", "shard"},
|
||||
)
|
||||
|
||||
func (k *KinesisSource) newClient() error {
|
||||
var sess *session.Session
|
||||
|
||||
if k.Config.AwsProfile != nil {
|
||||
sess = session.Must(session.NewSessionWithOptions(session.Options{
|
||||
SharedConfigState: session.SharedConfigEnable,
|
||||
Profile: *k.Config.AwsProfile,
|
||||
}))
|
||||
} else {
|
||||
sess = session.Must(session.NewSessionWithOptions(session.Options{
|
||||
SharedConfigState: session.SharedConfigEnable,
|
||||
}))
|
||||
}
|
||||
|
||||
if sess == nil {
|
||||
return fmt.Errorf("failed to create aws session")
|
||||
}
|
||||
config := aws.NewConfig()
|
||||
if k.Config.AwsRegion != "" {
|
||||
config = config.WithRegion(k.Config.AwsRegion)
|
||||
}
|
||||
if k.Config.AwsEndpoint != "" {
|
||||
config = config.WithEndpoint(k.Config.AwsEndpoint)
|
||||
}
|
||||
k.kClient = kinesis.New(sess, config)
|
||||
if k.kClient == nil {
|
||||
return fmt.Errorf("failed to create kinesis client")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KinesisSource) GetMetrics() []prometheus.Collector {
|
||||
return []prometheus.Collector{linesRead, linesReadShards}
|
||||
|
||||
}
|
||||
func (k *KinesisSource) GetAggregMetrics() []prometheus.Collector {
|
||||
return []prometheus.Collector{linesRead, linesReadShards}
|
||||
}
|
||||
|
||||
func (k *KinesisSource) Configure(yamlConfig []byte, logger *log.Entry) error {
|
||||
config := KinesisConfiguration{}
|
||||
k.logger = logger
|
||||
err := yaml.UnmarshalStrict(yamlConfig, &config)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot parse kinesis datasource configuration")
|
||||
}
|
||||
if config.Mode == "" {
|
||||
config.Mode = configuration.TAIL_MODE
|
||||
}
|
||||
k.Config = config
|
||||
if k.Config.StreamName == "" && !k.Config.UseEnhancedFanOut {
|
||||
return fmt.Errorf("stream_name is mandatory when use_enhanced_fanout is false")
|
||||
}
|
||||
if k.Config.StreamARN == "" && k.Config.UseEnhancedFanOut {
|
||||
return fmt.Errorf("stream_arn is mandatory when use_enhanced_fanout is true")
|
||||
}
|
||||
if k.Config.ConsumerName == "" && k.Config.UseEnhancedFanOut {
|
||||
return fmt.Errorf("consumer_name is mandatory when use_enhanced_fanout is true")
|
||||
}
|
||||
if k.Config.StreamARN != "" && k.Config.StreamName != "" {
|
||||
return fmt.Errorf("stream_arn and stream_name are mutually exclusive")
|
||||
}
|
||||
if k.Config.MaxRetries <= 0 {
|
||||
k.Config.MaxRetries = 10
|
||||
}
|
||||
err = k.newClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot create kinesis client")
|
||||
}
|
||||
k.shardReaderTomb = &tomb.Tomb{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KinesisSource) ConfigureByDSN(string, map[string]string, *log.Entry) error {
|
||||
return fmt.Errorf("kinesis datasource does not support command-line acquisition")
|
||||
}
|
||||
|
||||
func (k *KinesisSource) GetMode() string {
|
||||
return k.Config.Mode
|
||||
}
|
||||
|
||||
func (k *KinesisSource) GetName() string {
|
||||
return "kinesis"
|
||||
}
|
||||
|
||||
func (k *KinesisSource) OneShotAcquisition(out chan types.Event, t *tomb.Tomb) error {
|
||||
return fmt.Errorf("kinesis datasource does not support one-shot acquisition")
|
||||
}
|
||||
|
||||
func (k *KinesisSource) decodeFromSubscription(record []byte) ([]CloudwatchSubscriptionLogEvent, error) {
|
||||
b := bytes.NewBuffer(record)
|
||||
r, err := gzip.NewReader(b)
|
||||
|
||||
if err != nil {
|
||||
k.logger.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
decompressed, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
k.logger.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
var subscriptionRecord CloudWatchSubscriptionRecord
|
||||
err = json.Unmarshal(decompressed, &subscriptionRecord)
|
||||
if err != nil {
|
||||
k.logger.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return subscriptionRecord.LogEvents, nil
|
||||
}
|
||||
|
||||
func (k *KinesisSource) WaitForConsumerDeregistration(consumerName string, streamARN string) error {
|
||||
maxTries := k.Config.MaxRetries
|
||||
for i := 0; i < maxTries; i++ {
|
||||
_, err := k.kClient.DescribeStreamConsumer(&kinesis.DescribeStreamConsumerInput{
|
||||
ConsumerName: aws.String(consumerName),
|
||||
StreamARN: aws.String(streamARN),
|
||||
})
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case *kinesis.ResourceNotFoundException:
|
||||
return nil
|
||||
default:
|
||||
k.logger.Errorf("Error while waiting for consumer deregistration: %s", err)
|
||||
return errors.Wrap(err, "Cannot describe stream consumer")
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Millisecond * 200 * time.Duration(i+1))
|
||||
}
|
||||
return fmt.Errorf("consumer %s is not deregistered after %d tries", consumerName, maxTries)
|
||||
}
|
||||
|
||||
func (k *KinesisSource) DeregisterConsumer() error {
|
||||
k.logger.Debugf("Deregistering consumer %s if it exists", k.Config.ConsumerName)
|
||||
_, err := k.kClient.DeregisterStreamConsumer(&kinesis.DeregisterStreamConsumerInput{
|
||||
ConsumerName: aws.String(k.Config.ConsumerName),
|
||||
StreamARN: aws.String(k.Config.StreamARN),
|
||||
})
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case *kinesis.ResourceNotFoundException:
|
||||
default:
|
||||
return errors.Wrap(err, "Cannot deregister stream consumer")
|
||||
}
|
||||
}
|
||||
err = k.WaitForConsumerDeregistration(k.Config.ConsumerName, k.Config.StreamARN)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot wait for consumer deregistration")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KinesisSource) WaitForConsumerRegistration(consumerARN string) error {
|
||||
maxTries := k.Config.MaxRetries
|
||||
for i := 0; i < maxTries; i++ {
|
||||
describeOutput, err := k.kClient.DescribeStreamConsumer(&kinesis.DescribeStreamConsumerInput{
|
||||
ConsumerARN: aws.String(consumerARN),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot describe stream consumer")
|
||||
}
|
||||
if *describeOutput.ConsumerDescription.ConsumerStatus == "ACTIVE" {
|
||||
k.logger.Debugf("Consumer %s is active", consumerARN)
|
||||
return nil
|
||||
}
|
||||
time.Sleep(time.Millisecond * 200 * time.Duration(i+1))
|
||||
k.logger.Debugf("Waiting for consumer registration %d", i)
|
||||
}
|
||||
return fmt.Errorf("consumer %s is not active after %d tries", consumerARN, maxTries)
|
||||
}
|
||||
|
||||
func (k *KinesisSource) RegisterConsumer() (*kinesis.RegisterStreamConsumerOutput, error) {
|
||||
k.logger.Debugf("Registering consumer %s", k.Config.ConsumerName)
|
||||
streamConsumer, err := k.kClient.RegisterStreamConsumer(&kinesis.RegisterStreamConsumerInput{
|
||||
ConsumerName: aws.String(k.Config.ConsumerName),
|
||||
StreamARN: aws.String(k.Config.StreamARN),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Cannot register stream consumer")
|
||||
}
|
||||
err = k.WaitForConsumerRegistration(*streamConsumer.Consumer.ConsumerARN)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Timeout while waiting for consumer to be active")
|
||||
}
|
||||
return streamConsumer, nil
|
||||
}
|
||||
|
||||
func (k *KinesisSource) ParseAndPushRecords(records []*kinesis.Record, out chan types.Event, logger *log.Entry, shardId string) {
|
||||
for _, record := range records {
|
||||
if k.Config.StreamARN != "" {
|
||||
linesReadShards.With(prometheus.Labels{"stream": k.Config.StreamARN, "shard": shardId}).Inc()
|
||||
linesRead.With(prometheus.Labels{"stream": k.Config.StreamARN}).Inc()
|
||||
} else {
|
||||
linesReadShards.With(prometheus.Labels{"stream": k.Config.StreamName, "shard": shardId}).Inc()
|
||||
linesRead.With(prometheus.Labels{"stream": k.Config.StreamName}).Inc()
|
||||
}
|
||||
var data []CloudwatchSubscriptionLogEvent
|
||||
var err error
|
||||
if k.Config.FromSubscription {
|
||||
//The AWS docs says that the data is base64 encoded
|
||||
//but apparently GetRecords decodes it for us ?
|
||||
data, err = k.decodeFromSubscription(record.Data)
|
||||
if err != nil {
|
||||
logger.Errorf("Cannot decode data: %s", err)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
data = []CloudwatchSubscriptionLogEvent{{Message: string(record.Data)}}
|
||||
}
|
||||
for _, event := range data {
|
||||
logger.Tracef("got record %s", event.Message)
|
||||
l := types.Line{}
|
||||
l.Raw = event.Message
|
||||
l.Labels = k.Config.Labels
|
||||
l.Time = time.Now()
|
||||
l.Process = true
|
||||
l.Module = k.GetName()
|
||||
if k.Config.StreamARN != "" {
|
||||
l.Src = k.Config.StreamARN
|
||||
} else {
|
||||
l.Src = k.Config.StreamName
|
||||
}
|
||||
evt := types.Event{Line: l, Process: true, Type: types.LOG, ExpectMode: leakybucket.LIVE}
|
||||
out <- evt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KinesisSource) ReadFromSubscription(reader kinesis.SubscribeToShardEventStreamReader, out chan types.Event, shardId string, streamName string) error {
|
||||
logger := k.logger.WithFields(log.Fields{"shard_id": shardId})
|
||||
//ghetto sync, kinesis allows to subscribe to a closed shard, which will make the goroutine exit immediately
|
||||
//and we won't be able to start a new one if this is the first one started by the tomb
|
||||
//TODO: look into parent shards to see if a shard is closed before starting to read it ?
|
||||
time.Sleep(time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-k.shardReaderTomb.Dying():
|
||||
logger.Infof("Subscribed shard reader is dying")
|
||||
err := reader.Close()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot close kinesis subscribed shard reader")
|
||||
}
|
||||
return nil
|
||||
case event, ok := <-reader.Events():
|
||||
if !ok {
|
||||
logger.Infof("Event chan has been closed")
|
||||
return nil
|
||||
}
|
||||
switch event := event.(type) {
|
||||
case *kinesis.SubscribeToShardEvent:
|
||||
k.ParseAndPushRecords(event.Records, out, logger, shardId)
|
||||
case *kinesis.SubscribeToShardEventStreamUnknownEvent:
|
||||
logger.Infof("got an unknown event, what to do ?")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KinesisSource) SubscribeToShards(arn arn.ARN, streamConsumer *kinesis.RegisterStreamConsumerOutput, out chan types.Event) error {
|
||||
shards, err := k.kClient.ListShards(&kinesis.ListShardsInput{
|
||||
StreamName: aws.String(arn.Resource[7:]),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot list shards for enhanced_read")
|
||||
}
|
||||
|
||||
for _, shard := range shards.Shards {
|
||||
shardId := *shard.ShardId
|
||||
r, err := k.kClient.SubscribeToShard(&kinesis.SubscribeToShardInput{
|
||||
ShardId: aws.String(shardId),
|
||||
StartingPosition: &kinesis.StartingPosition{Type: aws.String(kinesis.ShardIteratorTypeLatest)},
|
||||
ConsumerARN: streamConsumer.Consumer.ConsumerARN,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot subscribe to shard")
|
||||
}
|
||||
k.shardReaderTomb.Go(func() error {
|
||||
return k.ReadFromSubscription(r.GetEventStream().Reader, out, shardId, arn.Resource[7:])
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KinesisSource) EnhancedRead(out chan types.Event, t *tomb.Tomb) error {
|
||||
parsedARN, err := arn.Parse(k.Config.StreamARN)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot parse stream ARN")
|
||||
}
|
||||
if !strings.HasPrefix(parsedARN.Resource, "stream/") {
|
||||
return fmt.Errorf("resource part of stream ARN %s does not start with stream/", k.Config.StreamARN)
|
||||
}
|
||||
|
||||
k.logger = k.logger.WithFields(log.Fields{"stream": parsedARN.Resource[7:]})
|
||||
k.logger.Info("starting kinesis acquisition with enhanced fan-out")
|
||||
err = k.DeregisterConsumer()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot deregister consumer")
|
||||
}
|
||||
|
||||
streamConsumer, err := k.RegisterConsumer()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot register consumer")
|
||||
}
|
||||
|
||||
for {
|
||||
k.shardReaderTomb = &tomb.Tomb{}
|
||||
|
||||
err = k.SubscribeToShards(parsedARN, streamConsumer, out)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot subscribe to shards")
|
||||
}
|
||||
select {
|
||||
case <-t.Dying():
|
||||
k.logger.Infof("Kinesis source is dying")
|
||||
k.shardReaderTomb.Kill(nil)
|
||||
_ = k.shardReaderTomb.Wait() //we don't care about the error as we kill the tomb ourselves
|
||||
err = k.DeregisterConsumer()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot deregister consumer")
|
||||
}
|
||||
return nil
|
||||
case <-k.shardReaderTomb.Dying():
|
||||
k.logger.Debugf("Kinesis subscribed shard reader is dying")
|
||||
if k.shardReaderTomb.Err() != nil {
|
||||
return k.shardReaderTomb.Err()
|
||||
}
|
||||
//All goroutines have exited without error, so a resharding event, start again
|
||||
k.logger.Debugf("All reader goroutines have exited, resharding event or periodic resubscribe")
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KinesisSource) ReadFromShard(out chan types.Event, shardId string) error {
|
||||
logger := k.logger.WithFields(log.Fields{"shard": shardId})
|
||||
logger.Debugf("Starting to read shard")
|
||||
sharIt, err := k.kClient.GetShardIterator(&kinesis.GetShardIteratorInput{ShardId: aws.String(shardId),
|
||||
StreamName: &k.Config.StreamName,
|
||||
ShardIteratorType: aws.String(kinesis.ShardIteratorTypeLatest)})
|
||||
if err != nil {
|
||||
logger.Errorf("Cannot get shard iterator: %s", err)
|
||||
return errors.Wrap(err, "Cannot get shard iterator")
|
||||
}
|
||||
it := sharIt.ShardIterator
|
||||
//AWS recommends to wait for a second between calls to GetRecords for a given shard
|
||||
ticker := time.NewTicker(time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
records, err := k.kClient.GetRecords(&kinesis.GetRecordsInput{ShardIterator: it})
|
||||
it = records.NextShardIterator
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case *kinesis.ProvisionedThroughputExceededException:
|
||||
logger.Warn("Provisioned throughput exceeded")
|
||||
//TODO: implement exponential backoff
|
||||
continue
|
||||
case *kinesis.ExpiredIteratorException:
|
||||
logger.Warn("Expired iterator")
|
||||
continue
|
||||
default:
|
||||
logger.Error("Cannot get records")
|
||||
return errors.Wrap(err, "Cannot get records")
|
||||
}
|
||||
}
|
||||
k.ParseAndPushRecords(records.Records, out, logger, shardId)
|
||||
|
||||
if it == nil {
|
||||
logger.Warnf("Shard has been closed")
|
||||
return nil
|
||||
}
|
||||
case <-k.shardReaderTomb.Dying():
|
||||
logger.Infof("shardReaderTomb is dying, exiting ReadFromShard")
|
||||
ticker.Stop()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KinesisSource) ReadFromStream(out chan types.Event, t *tomb.Tomb) error {
|
||||
k.logger = k.logger.WithFields(log.Fields{"stream": k.Config.StreamName})
|
||||
k.logger.Info("starting kinesis acquisition from shards")
|
||||
for {
|
||||
shards, err := k.kClient.ListShards(&kinesis.ListShardsInput{
|
||||
StreamName: aws.String(k.Config.StreamName),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot list shards")
|
||||
}
|
||||
k.shardReaderTomb = &tomb.Tomb{}
|
||||
for _, shard := range shards.Shards {
|
||||
shardId := *shard.ShardId
|
||||
k.shardReaderTomb.Go(func() error {
|
||||
defer types.CatchPanic("crowdsec/acquis/kinesis/streaming/shard")
|
||||
return k.ReadFromShard(out, shardId)
|
||||
})
|
||||
}
|
||||
select {
|
||||
case <-t.Dying():
|
||||
k.logger.Info("kinesis source is dying")
|
||||
k.shardReaderTomb.Kill(nil)
|
||||
_ = k.shardReaderTomb.Wait() //we don't care about the error as we kill the tomb ourselves
|
||||
return nil
|
||||
case <-k.shardReaderTomb.Dying():
|
||||
reason := k.shardReaderTomb.Err()
|
||||
if reason != nil {
|
||||
k.logger.Errorf("Unexpected error from shard reader : %s", reason)
|
||||
return reason
|
||||
}
|
||||
k.logger.Infof("All shards have been closed, probably a resharding event, restarting acquisition")
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (k *KinesisSource) StreamingAcquisition(out chan types.Event, t *tomb.Tomb) error {
|
||||
t.Go(func() error {
|
||||
defer types.CatchPanic("crowdsec/acquis/kinesis/streaming")
|
||||
if k.Config.UseEnhancedFanOut {
|
||||
return k.EnhancedRead(out, t)
|
||||
} else {
|
||||
return k.ReadFromStream(out, t)
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KinesisSource) CanRun() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KinesisSource) Dump() interface{} {
|
||||
return k
|
||||
}
|
325
pkg/acquisition/modules/kinesis/kinesis_test.go
Normal file
325
pkg/acquisition/modules/kinesis/kinesis_test.go
Normal file
|
@ -0,0 +1,325 @@
|
|||
package kinesisacquisition
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/kinesis"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/tomb.v2"
|
||||
)
|
||||
|
||||
func getLocalStackEndpoint() (string, error) {
|
||||
endpoint := "http://localhost:4566"
|
||||
if v := os.Getenv("AWS_ENDPOINT_FORCE"); v != "" {
|
||||
v = strings.TrimPrefix(v, "http://")
|
||||
_, err := net.Dial("tcp", v)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("while dialing %s : %s : aws endpoint isn't available", v, err)
|
||||
}
|
||||
}
|
||||
return endpoint, nil
|
||||
}
|
||||
|
||||
func GenSubObject(i int) []byte {
|
||||
r := CloudWatchSubscriptionRecord{
|
||||
MessageType: "subscription",
|
||||
Owner: "test",
|
||||
LogGroup: "test",
|
||||
LogStream: "test",
|
||||
SubscriptionFilters: []string{"filter1"},
|
||||
LogEvents: []CloudwatchSubscriptionLogEvent{
|
||||
{
|
||||
ID: "testid",
|
||||
Message: fmt.Sprintf("%d", i),
|
||||
Timestamp: time.Now().Unix(),
|
||||
},
|
||||
},
|
||||
}
|
||||
body, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
var b bytes.Buffer
|
||||
gz := gzip.NewWriter(&b)
|
||||
gz.Write(body)
|
||||
gz.Close()
|
||||
//AWS actually base64 encodes the data, but it looks like kinesis automatically decodes it at some point
|
||||
//localstack does not do it, so let's just write a raw gzipped stream
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func WriteToStream(streamName string, count int, shards int, sub bool) {
|
||||
endpoint, err := getLocalStackEndpoint()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
sess := session.Must(session.NewSession())
|
||||
kinesisClient := kinesis.New(sess, aws.NewConfig().WithEndpoint(endpoint).WithRegion("us-east-1"))
|
||||
for i := 0; i < count; i++ {
|
||||
partition := "partition"
|
||||
if shards != 1 {
|
||||
partition = fmt.Sprintf("partition-%d", i%shards)
|
||||
}
|
||||
var data []byte
|
||||
if sub {
|
||||
data = GenSubObject(i)
|
||||
} else {
|
||||
data = []byte(fmt.Sprintf("%d", i))
|
||||
}
|
||||
_, err = kinesisClient.PutRecord(&kinesis.PutRecordInput{
|
||||
Data: data,
|
||||
PartitionKey: aws.String(partition),
|
||||
StreamName: aws.String(streamName),
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("Error writing to stream: %s\n", err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", "foobar")
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", "foobar")
|
||||
|
||||
//delete_streams()
|
||||
//create_streams()
|
||||
code := m.Run()
|
||||
//delete_streams()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func TestBadConfiguration(t *testing.T) {
|
||||
tests := []struct {
|
||||
config string
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
config: `source: kinesis`,
|
||||
expectedErr: "stream_name is mandatory when use_enhanced_fanout is false",
|
||||
},
|
||||
{
|
||||
config: `
|
||||
source: kinesis
|
||||
use_enhanced_fanout: true`,
|
||||
expectedErr: "stream_arn is mandatory when use_enhanced_fanout is true",
|
||||
},
|
||||
{
|
||||
config: `
|
||||
source: kinesis
|
||||
use_enhanced_fanout: true
|
||||
stream_arn: arn:aws:kinesis:eu-west-1:123456789012:stream/my-stream`,
|
||||
expectedErr: "consumer_name is mandatory when use_enhanced_fanout is true",
|
||||
},
|
||||
{
|
||||
config: `
|
||||
source: kinesis
|
||||
stream_name: foobar
|
||||
stream_arn: arn:aws:kinesis:eu-west-1:123456789012:stream/my-stream`,
|
||||
expectedErr: "stream_arn and stream_name are mutually exclusive",
|
||||
},
|
||||
}
|
||||
|
||||
subLogger := log.WithFields(log.Fields{
|
||||
"type": "kinesis",
|
||||
})
|
||||
for _, test := range tests {
|
||||
f := KinesisSource{}
|
||||
err := f.Configure([]byte(test.config), subLogger)
|
||||
if test.expectedErr != "" && err == nil {
|
||||
t.Fatalf("Expected err %s but got nil !", test.expectedErr)
|
||||
}
|
||||
if test.expectedErr != "" {
|
||||
assert.Contains(t, err.Error(), test.expectedErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadFromStream(t *testing.T) {
|
||||
tests := []struct {
|
||||
config string
|
||||
count int
|
||||
shards int
|
||||
}{
|
||||
{
|
||||
config: `source: kinesis
|
||||
aws_endpoint: %s
|
||||
aws_region: us-east-1
|
||||
stream_name: stream-1-shard`,
|
||||
count: 10,
|
||||
shards: 1,
|
||||
},
|
||||
}
|
||||
endpoint, _ := getLocalStackEndpoint()
|
||||
for _, test := range tests {
|
||||
f := KinesisSource{}
|
||||
config := fmt.Sprintf(test.config, endpoint)
|
||||
err := f.Configure([]byte(config), log.WithFields(log.Fields{
|
||||
"type": "kinesis",
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatalf("Error configuring source: %s", err)
|
||||
}
|
||||
tomb := &tomb.Tomb{}
|
||||
out := make(chan types.Event)
|
||||
err = f.StreamingAcquisition(out, tomb)
|
||||
if err != nil {
|
||||
t.Fatalf("Error starting source: %s", err)
|
||||
}
|
||||
//Allow the datasource to start listening to the stream
|
||||
time.Sleep(4 * time.Second)
|
||||
WriteToStream(f.Config.StreamName, test.count, test.shards, false)
|
||||
for i := 0; i < test.count; i++ {
|
||||
e := <-out
|
||||
assert.Equal(t, fmt.Sprintf("%d", i), e.Line.Raw)
|
||||
}
|
||||
tomb.Kill(nil)
|
||||
tomb.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadFromMultipleShards(t *testing.T) {
|
||||
tests := []struct {
|
||||
config string
|
||||
count int
|
||||
shards int
|
||||
}{
|
||||
{
|
||||
config: `source: kinesis
|
||||
aws_endpoint: %s
|
||||
aws_region: us-east-1
|
||||
stream_name: stream-2-shards`,
|
||||
count: 10,
|
||||
shards: 2,
|
||||
},
|
||||
}
|
||||
endpoint, _ := getLocalStackEndpoint()
|
||||
for _, test := range tests {
|
||||
f := KinesisSource{}
|
||||
config := fmt.Sprintf(test.config, endpoint)
|
||||
err := f.Configure([]byte(config), log.WithFields(log.Fields{
|
||||
"type": "kinesis",
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatalf("Error configuring source: %s", err)
|
||||
}
|
||||
tomb := &tomb.Tomb{}
|
||||
out := make(chan types.Event)
|
||||
err = f.StreamingAcquisition(out, tomb)
|
||||
if err != nil {
|
||||
t.Fatalf("Error starting source: %s", err)
|
||||
}
|
||||
//Allow the datasource to start listening to the stream
|
||||
time.Sleep(4 * time.Second)
|
||||
WriteToStream(f.Config.StreamName, test.count, test.shards, false)
|
||||
c := 0
|
||||
for i := 0; i < test.count; i++ {
|
||||
<-out
|
||||
c += 1
|
||||
}
|
||||
assert.Equal(t, test.count, c)
|
||||
tomb.Kill(nil)
|
||||
tomb.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromSubscription(t *testing.T) {
|
||||
tests := []struct {
|
||||
config string
|
||||
count int
|
||||
shards int
|
||||
}{
|
||||
{
|
||||
config: `source: kinesis
|
||||
aws_endpoint: %s
|
||||
aws_region: us-east-1
|
||||
stream_name: stream-1-shard
|
||||
from_subscription: true`,
|
||||
count: 10,
|
||||
shards: 1,
|
||||
},
|
||||
}
|
||||
endpoint, _ := getLocalStackEndpoint()
|
||||
for _, test := range tests {
|
||||
f := KinesisSource{}
|
||||
config := fmt.Sprintf(test.config, endpoint)
|
||||
err := f.Configure([]byte(config), log.WithFields(log.Fields{
|
||||
"type": "kinesis",
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatalf("Error configuring source: %s", err)
|
||||
}
|
||||
tomb := &tomb.Tomb{}
|
||||
out := make(chan types.Event)
|
||||
err = f.StreamingAcquisition(out, tomb)
|
||||
if err != nil {
|
||||
t.Fatalf("Error starting source: %s", err)
|
||||
}
|
||||
//Allow the datasource to start listening to the stream
|
||||
time.Sleep(4 * time.Second)
|
||||
WriteToStream(f.Config.StreamName, test.count, test.shards, true)
|
||||
for i := 0; i < test.count; i++ {
|
||||
e := <-out
|
||||
assert.Equal(t, fmt.Sprintf("%d", i), e.Line.Raw)
|
||||
}
|
||||
tomb.Kill(nil)
|
||||
tomb.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestSubscribeToStream(t *testing.T) {
|
||||
tests := []struct {
|
||||
config string
|
||||
count int
|
||||
shards int
|
||||
}{
|
||||
{
|
||||
config: `source: kinesis
|
||||
aws_endpoint: %s
|
||||
aws_region: us-east-1
|
||||
stream_arn: arn:aws:kinesis:us-east-1:000000000000:stream/stream-1-shard
|
||||
consumer_name: consumer-1
|
||||
use_enhanced_fanout: true`,
|
||||
count: 10,
|
||||
shards: 1,
|
||||
},
|
||||
}
|
||||
endpoint, _ := getLocalStackEndpoint()
|
||||
for _, test := range tests {
|
||||
f := KinesisSource{}
|
||||
config := fmt.Sprintf(test.config, endpoint)
|
||||
err := f.Configure([]byte(config), log.WithFields(log.Fields{
|
||||
"type": "kinesis",
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatalf("Error configuring source: %s", err)
|
||||
}
|
||||
tomb := &tomb.Tomb{}
|
||||
out := make(chan types.Event)
|
||||
err = f.StreamingAcquisition(out, tomb)
|
||||
if err != nil {
|
||||
t.Fatalf("Error starting source: %s", err)
|
||||
}
|
||||
//Allow the datasource to start listening to the stream
|
||||
time.Sleep(10 * time.Second)
|
||||
WriteToStream("stream-1-shard", test.count, test.shards)
|
||||
for i := 0; i < test.count; i++ {
|
||||
e := <-out
|
||||
assert.Equal(t, fmt.Sprintf("%d", i), e.Line.Raw)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -19,6 +19,7 @@ type AlertsListOpts struct {
|
|||
ScenarioEquals *string `url:"scenario,omitempty"`
|
||||
IPEquals *string `url:"ip,omitempty"`
|
||||
RangeEquals *string `url:"range,omitempty"`
|
||||
OriginEquals *string `url:"origin,omitempty"`
|
||||
Since *string `url:"since,omitempty"`
|
||||
TypeEquals *string `url:"decision_type,omitempty"`
|
||||
Until *string `url:"until,omitempty"`
|
||||
|
@ -38,6 +39,7 @@ type AlertsDeleteOpts struct {
|
|||
RangeEquals *string `url:"range,omitempty"`
|
||||
Since *string `url:"since,omitempty"`
|
||||
Until *string `url:"until,omitempty"`
|
||||
OriginEquals *string `url:"origin,omitempty"`
|
||||
ActiveDecisionEquals *bool `url:"has_active_decision,omitempty"`
|
||||
SourceEquals *string `url:"alert_source,omitempty"`
|
||||
Contains *bool `url:"contains,omitempty"`
|
||||
|
|
|
@ -123,7 +123,7 @@ func TestCreateAlert(t *testing.T) {
|
|||
router.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, 500, w.Code)
|
||||
assert.Equal(t, "{\"message\":\"validation failure list:\\nscenario in body is required\\nscenario_hash in body is required\\nscenario_version in body is required\\nsimulated in body is required\\nsource in body is required\"}", w.Body.String())
|
||||
assert.Equal(t, "{\"message\":\"validation failure list:\\n0.scenario in body is required\\n0.scenario_hash in body is required\\n0.scenario_version in body is required\\n0.simulated in body is required\\n0.source in body is required\"}", w.Body.String())
|
||||
|
||||
// Create Valid Alert
|
||||
alertContentBytes, err = ioutil.ReadFile("./tests/alert_sample.json")
|
||||
|
|
|
@ -234,6 +234,10 @@ func (a *apic) Send(cacheOrig *models.AddSignalsRequest) {
|
|||
}
|
||||
}
|
||||
|
||||
var SCOPE_CAPI string = "CAPI"
|
||||
var SCOPE_CAPI_ALIAS string = "crowdsecurity/community-blocklist" //we don't use "CAPI" directly, to make it less confusing for the user
|
||||
var SCOPE_LISTS string = "lists"
|
||||
|
||||
func (a *apic) PullTop() error {
|
||||
var err error
|
||||
|
||||
|
@ -256,10 +260,28 @@ func (a *apic) PullTop() error {
|
|||
if a.startup {
|
||||
a.startup = false
|
||||
}
|
||||
// process deleted decisions
|
||||
/*to count additions/deletions accross lists*/
|
||||
var add_counters map[string]map[string]int
|
||||
var delete_counters map[string]map[string]int
|
||||
|
||||
add_counters = make(map[string]map[string]int)
|
||||
add_counters[SCOPE_CAPI] = make(map[string]int)
|
||||
add_counters[SCOPE_LISTS] = make(map[string]int)
|
||||
delete_counters = make(map[string]map[string]int)
|
||||
delete_counters[SCOPE_CAPI] = make(map[string]int)
|
||||
delete_counters[SCOPE_LISTS] = make(map[string]int)
|
||||
var filter map[string][]string
|
||||
var nbDeleted int
|
||||
// process deleted decisions
|
||||
for _, decision := range data.Deleted {
|
||||
//count individual deletions
|
||||
if *decision.Origin == SCOPE_CAPI {
|
||||
delete_counters[SCOPE_CAPI][*decision.Scenario]++
|
||||
} else if *decision.Origin == SCOPE_LISTS {
|
||||
delete_counters[SCOPE_LISTS][*decision.Scenario]++
|
||||
} else {
|
||||
log.Warningf("Unknown origin %s", *decision.Origin)
|
||||
}
|
||||
if strings.ToLower(*decision.Scope) == "ip" {
|
||||
filter = make(map[string][]string, 1)
|
||||
filter["value"] = []string{*decision.Value}
|
||||
|
@ -287,23 +309,77 @@ func (a *apic) PullTop() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
capiPullTopX := models.Alert{}
|
||||
capiPullTopX.Scenario = types.StrPtr(fmt.Sprintf("update : +%d/-%d IPs", len(data.New), len(data.Deleted)))
|
||||
capiPullTopX.Message = types.StrPtr("")
|
||||
capiPullTopX.Source = &models.Source{}
|
||||
capiPullTopX.Source.Scope = types.StrPtr("crowdsec/community-blocklist")
|
||||
capiPullTopX.Source.Value = types.StrPtr("")
|
||||
capiPullTopX.StartAt = types.StrPtr(time.Now().Format(time.RFC3339))
|
||||
capiPullTopX.StopAt = types.StrPtr(time.Now().Format(time.RFC3339))
|
||||
capiPullTopX.Capacity = types.Int32Ptr(0)
|
||||
capiPullTopX.Simulated = types.BoolPtr(false)
|
||||
capiPullTopX.EventsCount = types.Int32Ptr(int32(len(data.New)))
|
||||
capiPullTopX.Leakspeed = types.StrPtr("")
|
||||
capiPullTopX.ScenarioHash = types.StrPtr("")
|
||||
capiPullTopX.ScenarioVersion = types.StrPtr("")
|
||||
capiPullTopX.MachineID = database.CapiMachineID
|
||||
// process new decisions
|
||||
//we receive only one list of decisions, that we need to break-up :
|
||||
// one alert for "community blocklist"
|
||||
// one alert per list we're subscribed to
|
||||
var alertsFromCapi []*models.Alert
|
||||
alertsFromCapi = make([]*models.Alert, 0)
|
||||
|
||||
//iterate over all new decisions, and simply create corresponding alerts
|
||||
for _, decision := range data.New {
|
||||
found := false
|
||||
for _, sub := range alertsFromCapi {
|
||||
if sub.Source.Scope == nil {
|
||||
log.Warningf("nil scope in %+v", sub)
|
||||
continue
|
||||
}
|
||||
if *decision.Origin == SCOPE_CAPI {
|
||||
if *sub.Source.Scope == SCOPE_CAPI {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
} else if *decision.Origin == SCOPE_LISTS {
|
||||
if *sub.Source.Scope == *decision.Origin {
|
||||
if sub.Scenario == nil {
|
||||
log.Warningf("nil scenario in %+v", sub)
|
||||
}
|
||||
if *sub.Scenario == *decision.Scenario {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Warningf("unknown origin %s : %+v", *decision.Origin, decision)
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
log.Debugf("Create entry for origin:%s scenario:%s", *decision.Origin, *decision.Scenario)
|
||||
newAlert := models.Alert{}
|
||||
newAlert.Message = types.StrPtr("")
|
||||
newAlert.Source = &models.Source{}
|
||||
if *decision.Origin == SCOPE_CAPI { //to make things more user friendly, we replace CAPI with community-blocklist
|
||||
newAlert.Source.Scope = types.StrPtr(SCOPE_CAPI)
|
||||
newAlert.Scenario = types.StrPtr(SCOPE_CAPI)
|
||||
} else if *decision.Origin == SCOPE_LISTS {
|
||||
newAlert.Source.Scope = types.StrPtr(SCOPE_LISTS)
|
||||
newAlert.Scenario = types.StrPtr(*decision.Scenario)
|
||||
} else {
|
||||
log.Warningf("unknown origin %s", *decision.Origin)
|
||||
}
|
||||
newAlert.Source.Value = types.StrPtr("")
|
||||
newAlert.StartAt = types.StrPtr(time.Now().Format(time.RFC3339))
|
||||
newAlert.StopAt = types.StrPtr(time.Now().Format(time.RFC3339))
|
||||
newAlert.Capacity = types.Int32Ptr(0)
|
||||
newAlert.Simulated = types.BoolPtr(false)
|
||||
newAlert.EventsCount = types.Int32Ptr(int32(len(data.New)))
|
||||
newAlert.Leakspeed = types.StrPtr("")
|
||||
newAlert.ScenarioHash = types.StrPtr("")
|
||||
newAlert.ScenarioVersion = types.StrPtr("")
|
||||
newAlert.MachineID = database.CapiMachineID
|
||||
alertsFromCapi = append(alertsFromCapi, &newAlert)
|
||||
}
|
||||
}
|
||||
|
||||
//iterate a second time and fill the alerts with the new decisions
|
||||
for _, decision := range data.New {
|
||||
//count and create separate alerts for each list
|
||||
if *decision.Origin == SCOPE_CAPI {
|
||||
add_counters[SCOPE_CAPI]["all"]++
|
||||
} else if *decision.Origin == SCOPE_LISTS {
|
||||
add_counters[SCOPE_LISTS][*decision.Scenario]++
|
||||
} else {
|
||||
log.Warningf("Unknown origin %s", *decision.Origin)
|
||||
}
|
||||
|
||||
/*CAPI might send lower case scopes, unify it.*/
|
||||
switch strings.ToLower(*decision.Scope) {
|
||||
|
@ -312,17 +388,48 @@ func (a *apic) PullTop() error {
|
|||
case "range":
|
||||
*decision.Scope = types.Range
|
||||
}
|
||||
|
||||
capiPullTopX.Decisions = append(capiPullTopX.Decisions, decision)
|
||||
found := false
|
||||
//add the individual decisions to the right list
|
||||
for idx, alert := range alertsFromCapi {
|
||||
if *decision.Origin == SCOPE_CAPI {
|
||||
if *alert.Source.Scope == SCOPE_CAPI {
|
||||
alertsFromCapi[idx].Decisions = append(alertsFromCapi[idx].Decisions, decision)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
} else if *decision.Origin == SCOPE_LISTS {
|
||||
if *alert.Source.Scope == SCOPE_LISTS && *alert.Scenario == *decision.Scenario {
|
||||
alertsFromCapi[idx].Decisions = append(alertsFromCapi[idx].Decisions, decision)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
} else {
|
||||
log.Warningf("unknown origin %s", *decision.Origin)
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
log.Warningf("Orphaned decision for %s - %s", *decision.Origin, *decision.Scenario)
|
||||
}
|
||||
}
|
||||
|
||||
alertID, inserted, deleted, err := a.dbClient.UpdateCommunityBlocklist(&capiPullTopX)
|
||||
for idx, alert := range alertsFromCapi {
|
||||
formatted_update := ""
|
||||
|
||||
if *alertsFromCapi[idx].Source.Scope == SCOPE_CAPI {
|
||||
*alertsFromCapi[idx].Source.Scope = SCOPE_CAPI_ALIAS
|
||||
formatted_update = fmt.Sprintf("update : +%d/-%d IPs", add_counters[SCOPE_CAPI]["all"], delete_counters[SCOPE_CAPI]["all"])
|
||||
} else if *alertsFromCapi[idx].Source.Scope == SCOPE_LISTS {
|
||||
*alertsFromCapi[idx].Source.Scope = fmt.Sprintf("%s:%s", SCOPE_LISTS, *alertsFromCapi[idx].Scenario)
|
||||
formatted_update = fmt.Sprintf("update : +%d/-%d IPs", add_counters[SCOPE_LISTS][*alert.Scenario], delete_counters[SCOPE_LISTS][*alert.Scenario])
|
||||
}
|
||||
alertsFromCapi[idx].Scenario = types.StrPtr(formatted_update)
|
||||
log.Debugf("%s has %d decisions", *alertsFromCapi[idx].Source.Scope, len(alertsFromCapi[idx].Decisions))
|
||||
alertID, inserted, deleted, err := a.dbClient.UpdateCommunityBlocklist(alertsFromCapi[idx])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "while saving alert from capi/community-blocklist")
|
||||
return errors.Wrapf(err, "while saving alert from %s", *alertsFromCapi[idx].Source.Scope)
|
||||
}
|
||||
log.Printf("%s : added %d entries, deleted %d entries (alert:%d)", *alertsFromCapi[idx].Source.Scope, inserted, deleted, alertID)
|
||||
}
|
||||
|
||||
log.Printf("capi/community-blocklist : added %d entries, deleted %d entries (alert:%d)", inserted, deleted, alertID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -31,45 +31,75 @@ var HubBranch = "master"
|
|||
var HubIndexFile = ".index.json"
|
||||
|
||||
type ItemVersion struct {
|
||||
Digest string
|
||||
Deprecated bool
|
||||
Digest string `json:"digest,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
}
|
||||
|
||||
type ItemHubStatus struct {
|
||||
Name string `json:"name"`
|
||||
LocalVersion string `json:"local_version"`
|
||||
LocalPath string `json:"local_path"`
|
||||
Description string `json:"description"`
|
||||
UTF8_Status string `json:"utf8_status"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
//Item can be : parsed, scenario, collection
|
||||
type Item struct {
|
||||
/*descriptive info*/
|
||||
Type string `yaml:"type,omitempty"` //parser|postoverflows|scenario|collection(|enrich)
|
||||
Stage string `json:"stage" yaml:"stage,omitempty,omitempty"` //Stage for parser|postoverflow : s00-raw/s01-...
|
||||
Name string //as seen in .config.json, usually "author/name"
|
||||
FileName string //the filename, ie. apache2-logs.yaml
|
||||
Description string `yaml:"description,omitempty"` //as seen in .config.json
|
||||
Author string `json:"author"` //as seen in .config.json
|
||||
References []string `yaml:"references,omitempty"` //as seen in .config.json
|
||||
BelongsToCollections []string `yaml:"belongs_to_collections,omitempty"` /*if it's part of collections, track name here*/
|
||||
Type string `yaml:"type,omitempty" json:"type,omitempty"` //parser|postoverflows|scenario|collection(|enrich)
|
||||
Stage string `json:"stage,omitempty" yaml:"stage,omitempty,omitempty"` //Stage for parser|postoverflow : s00-raw/s01-...
|
||||
Name string `json:"name,omitempty"` //as seen in .config.json, usually "author/name"
|
||||
FileName string `json:"file_name,omitempty"` //the filename, ie. apache2-logs.yaml
|
||||
Description string `yaml:"description,omitempty" json:"description,omitempty"` //as seen in .config.json
|
||||
Author string `json:"author,omitempty"` //as seen in .config.json
|
||||
References []string `yaml:"references,omitempty" json:"references,omitempty"` //as seen in .config.json
|
||||
BelongsToCollections []string `yaml:"belongs_to_collections,omitempty" json:"belongs_to_collections,omitempty"` /*if it's part of collections, track name here*/
|
||||
|
||||
/*remote (hub) infos*/
|
||||
RemoteURL string `yaml:"remoteURL,omitempty"` //the full remote uri of file in http
|
||||
RemotePath string `json:"path" yaml:"remote_path,omitempty"` //the path relative to git ie. /parsers/stage/author/file.yaml
|
||||
RemoteHash string `yaml:"hash,omitempty"` //the meow
|
||||
Version string `json:"version"` //the last version
|
||||
Versions map[string]ItemVersion `json:"versions" yaml:"-"` //the list of existing versions
|
||||
RemoteURL string `yaml:"remoteURL,omitempty" json:"remoteURL,omitempty"` //the full remote uri of file in http
|
||||
RemotePath string `json:"path,omitempty" yaml:"remote_path,omitempty"` //the path relative to git ie. /parsers/stage/author/file.yaml
|
||||
RemoteHash string `yaml:"hash,omitempty" json:"hash,omitempty"` //the meow
|
||||
Version string `json:"version,omitempty"` //the last version
|
||||
Versions map[string]ItemVersion `json:"versions,omitempty" yaml:"-"` //the list of existing versions
|
||||
|
||||
/*local (deployed) infos*/
|
||||
LocalPath string `yaml:"local_path,omitempty"` //the local path relative to ${CFG_DIR}
|
||||
LocalPath string `yaml:"local_path,omitempty" json:"local_path,omitempty"` //the local path relative to ${CFG_DIR}
|
||||
//LocalHubPath string
|
||||
LocalVersion string
|
||||
LocalHash string //the local meow
|
||||
Installed bool
|
||||
Downloaded bool
|
||||
UpToDate bool
|
||||
Tainted bool //has it been locally modified
|
||||
Local bool //if it's a non versioned control one
|
||||
LocalVersion string `json:"local_version,omitempty"`
|
||||
LocalHash string `json:"local_hash,omitempty"` //the local meow
|
||||
Installed bool `json:"installed,omitempty"`
|
||||
Downloaded bool `json:"downloaded,omitempty"`
|
||||
UpToDate bool `json:"up_to_date,omitempty"`
|
||||
Tainted bool `json:"tainted,omitempty"` //has it been locally modified
|
||||
Local bool `json:"local,omitempty"` //if it's a non versioned control one
|
||||
|
||||
/*if it's a collection, it not a single file*/
|
||||
Parsers []string `yaml:"parsers,omitempty"`
|
||||
PostOverflows []string `yaml:"postoverflows,omitempty"`
|
||||
Scenarios []string `yaml:"scenarios,omitempty"`
|
||||
Collections []string `yaml:"collections,omitempty"`
|
||||
Parsers []string `yaml:"parsers,omitempty" json:"parsers,omitempty"`
|
||||
PostOverflows []string `yaml:"postoverflows,omitempty" json:"postoverflows,omitempty"`
|
||||
Scenarios []string `yaml:"scenarios,omitempty" json:"scenarios,omitempty"`
|
||||
Collections []string `yaml:"collections,omitempty" json:"collections,omitempty"`
|
||||
}
|
||||
|
||||
func (i *Item) toHubStatus() ItemHubStatus {
|
||||
hubStatus := ItemHubStatus{}
|
||||
hubStatus.Name = i.Name
|
||||
hubStatus.LocalVersion = i.LocalVersion
|
||||
hubStatus.LocalPath = i.LocalPath
|
||||
hubStatus.Description = i.Description
|
||||
|
||||
status, ok, warning, managed := ItemStatus(*i)
|
||||
hubStatus.Status = status
|
||||
if !managed {
|
||||
hubStatus.UTF8_Status = fmt.Sprintf("%v %s", emoji.House, status)
|
||||
} else if !i.Installed {
|
||||
hubStatus.UTF8_Status = fmt.Sprintf("%v %s", emoji.Prohibited, status)
|
||||
} else if warning {
|
||||
hubStatus.UTF8_Status = fmt.Sprintf("%v %s", emoji.Warning, status)
|
||||
} else if ok {
|
||||
hubStatus.UTF8_Status = fmt.Sprintf("%v %s", emoji.CheckMark, status)
|
||||
}
|
||||
return hubStatus
|
||||
}
|
||||
|
||||
var skippedLocal = 0
|
||||
|
@ -240,18 +270,18 @@ func GetUpstreamInstalledScenarios() ([]Item, error) {
|
|||
}
|
||||
|
||||
//Returns a list of entries for packages : name, status, local_path, local_version, utf8_status (fancy)
|
||||
func HubStatus(itemType string, name string, all bool) []map[string]string {
|
||||
func GetHubStatusForItemType(itemType string, name string, all bool) []ItemHubStatus {
|
||||
if _, ok := hubIdx[itemType]; !ok {
|
||||
log.Errorf("type %s doesn't exist", itemType)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var ret []map[string]string
|
||||
var ret = make([]ItemHubStatus, 0)
|
||||
/*remember, you do it for the user :)*/
|
||||
for _, item := range hubIdx[itemType] {
|
||||
if name != "" && name != item.Name {
|
||||
//user has required a specific name
|
||||
//user has requested a specific name
|
||||
continue
|
||||
}
|
||||
//Only enabled items ?
|
||||
|
@ -259,23 +289,7 @@ func HubStatus(itemType string, name string, all bool) []map[string]string {
|
|||
continue
|
||||
}
|
||||
//Check the item status
|
||||
status, ok, warning, managed := ItemStatus(item)
|
||||
tmp := make(map[string]string)
|
||||
tmp["name"] = item.Name
|
||||
tmp["status"] = status
|
||||
tmp["local_version"] = item.LocalVersion
|
||||
tmp["local_path"] = item.LocalPath
|
||||
tmp["description"] = item.Description
|
||||
if !managed {
|
||||
tmp["utf8_status"] = fmt.Sprintf("%v %s", emoji.House, status)
|
||||
} else if !item.Installed {
|
||||
tmp["utf8_status"] = fmt.Sprintf("%v %s", emoji.Prohibited, status)
|
||||
} else if warning {
|
||||
tmp["utf8_status"] = fmt.Sprintf("%v %s", emoji.Warning, status)
|
||||
} else if ok {
|
||||
tmp["utf8_status"] = fmt.Sprintf("%v %s", emoji.CheckMark, status)
|
||||
}
|
||||
ret = append(ret, tmp)
|
||||
ret = append(ret, item.toHubStatus())
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
|
@ -321,10 +321,10 @@ func TestInstallParser(t *testing.T) {
|
|||
for _, it := range hubIdx[PARSERS] {
|
||||
testInstallItem(cfg.Hub, t, it)
|
||||
it = hubIdx[PARSERS][it.Name]
|
||||
_ = HubStatus(PARSERS, it.Name, false)
|
||||
_ = GetHubStatusForItemType(PARSERS, it.Name, false)
|
||||
testTaintItem(cfg.Hub, t, it)
|
||||
it = hubIdx[PARSERS][it.Name]
|
||||
_ = HubStatus(PARSERS, it.Name, false)
|
||||
_ = GetHubStatusForItemType(PARSERS, it.Name, false)
|
||||
testUpdateItem(cfg.Hub, t, it)
|
||||
it = hubIdx[PARSERS][it.Name]
|
||||
testDisableItem(cfg.Hub, t, it)
|
||||
|
@ -361,7 +361,7 @@ func TestInstallCollection(t *testing.T) {
|
|||
testDisableItem(cfg.Hub, t, it)
|
||||
|
||||
it = hubIdx[COLLECTIONS][it.Name]
|
||||
x := HubStatus(COLLECTIONS, it.Name, false)
|
||||
x := GetHubStatusForItemType(COLLECTIONS, it.Name, false)
|
||||
log.Printf("%+v", x)
|
||||
break
|
||||
}
|
||||
|
|
|
@ -561,6 +561,10 @@ func BuildAlertRequestFromFilter(alerts *ent.AlertQuery, filter map[string][]str
|
|||
delete(filter, "simulated")
|
||||
}
|
||||
|
||||
if _, ok := filter["origin"]; ok {
|
||||
filter["include_capi"] = []string{"true"}
|
||||
}
|
||||
|
||||
for param, value := range filter {
|
||||
switch param {
|
||||
case "contains":
|
||||
|
@ -579,7 +583,7 @@ func BuildAlertRequestFromFilter(alerts *ent.AlertQuery, filter map[string][]str
|
|||
case "value":
|
||||
alerts = alerts.Where(alert.SourceValueEQ(value[0]))
|
||||
case "scenario":
|
||||
alerts = alerts.Where(alert.ScenarioEQ(value[0]))
|
||||
alerts = alerts.Where(alert.HasDecisionsWith(decision.ScenarioEQ(value[0])))
|
||||
case "ip", "range":
|
||||
ip_sz, start_ip, start_sfx, end_ip, end_sfx, err = types.Addr2Ints(value[0])
|
||||
if err != nil {
|
||||
|
@ -617,9 +621,11 @@ func BuildAlertRequestFromFilter(alerts *ent.AlertQuery, filter map[string][]str
|
|||
alerts = alerts.Where(alert.StartedAtLTE(until))
|
||||
case "decision_type":
|
||||
alerts = alerts.Where(alert.HasDecisionsWith(decision.TypeEQ(value[0])))
|
||||
case "origin":
|
||||
alerts = alerts.Where(alert.HasDecisionsWith(decision.OriginEQ(value[0])))
|
||||
case "include_capi": //allows to exclude one or more specific origins
|
||||
if value[0] == "false" {
|
||||
alerts = alerts.Where(alert.HasDecisionsWith(decision.OriginNEQ(CapiMachineID)))
|
||||
alerts = alerts.Where(alert.HasDecisionsWith(decision.Or(decision.OriginEQ("crowdsec"), decision.OriginEQ("cscli"))))
|
||||
} else if value[0] != "true" {
|
||||
log.Errorf("Invalid bool '%s' for include_capi", value[0])
|
||||
}
|
||||
|
|
|
@ -77,10 +77,13 @@ func (c *Client) ListMachines() ([]*ent.Machine, error) {
|
|||
}
|
||||
|
||||
func (c *Client) ValidateMachine(machineID string) error {
|
||||
_, err := c.Ent.Machine.Update().Where(machine.MachineIdEQ(machineID)).SetIsValidated(true).Save(c.CTX)
|
||||
rets, err := c.Ent.Machine.Update().Where(machine.MachineIdEQ(machineID)).SetIsValidated(true).Save(c.CTX)
|
||||
if err != nil {
|
||||
return errors.Wrapf(UpdateFail, "validating machine: %s", err)
|
||||
}
|
||||
if rets == 0 {
|
||||
return fmt.Errorf("machine not found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,14 @@ package leakybucket
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/mohae/deepcopy"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
|
@ -154,14 +155,137 @@ func ShutdownAllBuckets(buckets *Buckets) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func PourItemToBucket(bucket *Leaky, holder BucketFactory, buckets *Buckets, parsed types.Event) (bool, error) {
|
||||
var sent bool
|
||||
var buckey = bucket.Mapkey
|
||||
var err error
|
||||
|
||||
sigclosed := 0
|
||||
failed_sent := 0
|
||||
attempts := 0
|
||||
start := time.Now()
|
||||
|
||||
for !sent {
|
||||
attempts += 1
|
||||
/* Warn the user if we used more than a 100 ms to pour an event, it's at least an half lock*/
|
||||
if attempts%100000 == 0 && start.Add(100*time.Millisecond).Before(time.Now()) {
|
||||
holder.logger.Warningf("stuck for %s sending event to %s (sigclosed:%d failed_sent:%d attempts:%d)", time.Since(start),
|
||||
buckey, sigclosed, failed_sent, attempts)
|
||||
}
|
||||
|
||||
/* check if leak routine is up */
|
||||
select {
|
||||
case _, ok := <-bucket.Signal:
|
||||
if !ok {
|
||||
//the bucket was found and dead, get a new one and continue
|
||||
bucket.logger.Tracef("Bucket %s found dead, cleanup the body", buckey)
|
||||
buckets.Bucket_map.Delete(buckey)
|
||||
sigclosed += 1
|
||||
bucket, err = LoadOrStoreBucketFromHolder(buckey, buckets, holder, parsed.ExpectMode)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
holder.logger.Tracef("Signal exists, try to pour :)")
|
||||
default:
|
||||
/*nothing to read, but not closed, try to pour */
|
||||
holder.logger.Tracef("Signal exists but empty, try to pour :)")
|
||||
}
|
||||
|
||||
/*let's see if this time-bucket should have expired */
|
||||
if bucket.Mode == TIMEMACHINE {
|
||||
bucket.mutex.Lock()
|
||||
firstTs := bucket.First_ts
|
||||
lastTs := bucket.Last_ts
|
||||
bucket.mutex.Unlock()
|
||||
|
||||
if !firstTs.IsZero() {
|
||||
var d time.Time
|
||||
err = d.UnmarshalText([]byte(parsed.MarshaledTime))
|
||||
if err != nil {
|
||||
holder.logger.Warningf("Failed unmarshaling event time (%s) : %v", parsed.MarshaledTime, err)
|
||||
}
|
||||
if d.After(lastTs.Add(bucket.Duration)) {
|
||||
bucket.logger.Tracef("bucket is expired (curr event: %s, bucket deadline: %s), kill", d, lastTs.Add(bucket.Duration))
|
||||
buckets.Bucket_map.Delete(buckey)
|
||||
//not sure about this, should we create a new one ?
|
||||
sigclosed += 1
|
||||
bucket, err = LoadOrStoreBucketFromHolder(buckey, buckets, holder, parsed.ExpectMode)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
/*the bucket seems to be up & running*/
|
||||
select {
|
||||
case bucket.In <- parsed:
|
||||
holder.logger.Tracef("Successfully sent !")
|
||||
if BucketPourTrack {
|
||||
if _, ok := BucketPourCache[bucket.Name]; !ok {
|
||||
BucketPourCache[bucket.Name] = make([]types.Event, 0)
|
||||
}
|
||||
evt := deepcopy.Copy(parsed)
|
||||
BucketPourCache[bucket.Name] = append(BucketPourCache[bucket.Name], evt.(types.Event))
|
||||
}
|
||||
sent = true
|
||||
continue
|
||||
default:
|
||||
failed_sent += 1
|
||||
holder.logger.Tracef("Failed to send, try again")
|
||||
continue
|
||||
|
||||
}
|
||||
}
|
||||
holder.logger.Debugf("bucket '%s' is poured", holder.Name)
|
||||
return sent, nil
|
||||
}
|
||||
|
||||
func LoadOrStoreBucketFromHolder(partitionKey string, buckets *Buckets, holder BucketFactory, expectMode int) (*Leaky, error) {
|
||||
|
||||
biface, ok := buckets.Bucket_map.Load(partitionKey)
|
||||
|
||||
/* the bucket doesn't exist, create it !*/
|
||||
if !ok {
|
||||
var fresh_bucket *Leaky
|
||||
|
||||
switch expectMode {
|
||||
case TIMEMACHINE:
|
||||
fresh_bucket = NewTimeMachine(holder)
|
||||
holder.logger.Debugf("Creating TimeMachine bucket")
|
||||
case LIVE:
|
||||
fresh_bucket = NewLeaky(holder)
|
||||
holder.logger.Debugf("Creating Live bucket")
|
||||
default:
|
||||
return nil, fmt.Errorf("input event has no expected mode : %+v", expectMode)
|
||||
}
|
||||
fresh_bucket.In = make(chan types.Event)
|
||||
fresh_bucket.Mapkey = partitionKey
|
||||
fresh_bucket.Signal = make(chan bool, 1)
|
||||
actual, stored := buckets.Bucket_map.LoadOrStore(partitionKey, fresh_bucket)
|
||||
if !stored {
|
||||
holder.tomb.Go(func() error {
|
||||
return LeakRoutine(fresh_bucket)
|
||||
})
|
||||
biface = fresh_bucket
|
||||
//once the created goroutine is ready to process event, we can return it
|
||||
<-fresh_bucket.Signal
|
||||
} else {
|
||||
holder.logger.Debugf("Unexpectedly found exisint bucket for %s", partitionKey)
|
||||
biface = actual
|
||||
}
|
||||
holder.logger.Debugf("Created new bucket %s", partitionKey)
|
||||
}
|
||||
return biface.(*Leaky), nil
|
||||
}
|
||||
|
||||
func PourItemToHolders(parsed types.Event, holders []BucketFactory, buckets *Buckets) (bool, error) {
|
||||
var (
|
||||
ok, condition, sent bool
|
||||
err error
|
||||
ok, condition, poured bool
|
||||
)
|
||||
//synchronize with DumpBucketsStateAt
|
||||
|
||||
//to track bucket pour : track items that enter the pour routine
|
||||
if BucketPourTrack {
|
||||
if BucketPourCache == nil {
|
||||
BucketPourCache = make(map[string][]types.Event)
|
||||
|
@ -173,8 +297,10 @@ func PourItemToHolders(parsed types.Event, holders []BucketFactory, buckets *Buc
|
|||
BucketPourCache["OK"] = append(BucketPourCache["OK"], evt.(types.Event))
|
||||
}
|
||||
|
||||
//find the relevant holders (scenarios)
|
||||
for idx, holder := range holders {
|
||||
|
||||
//evaluate bucket's condition
|
||||
if holder.RunTimeFilter != nil {
|
||||
holder.logger.Tracef("event against holder %d/%d", idx, len(holders))
|
||||
output, err := expr.Run(holder.RunTimeFilter, exprhelpers.GetExprEnv(map[string]interface{}{"evt": &parsed}))
|
||||
|
@ -197,7 +323,7 @@ func PourItemToHolders(parsed types.Event, holders []BucketFactory, buckets *Buc
|
|||
}
|
||||
}
|
||||
|
||||
sent = false
|
||||
//groupby determines the partition key for the specific bucket
|
||||
var groupby string
|
||||
if holder.RunTimeGroupBy != nil {
|
||||
tmpGroupBy, err := expr.Run(holder.RunTimeGroupBy, exprhelpers.GetExprEnv(map[string]interface{}{"evt": &parsed}))
|
||||
|
@ -213,119 +339,19 @@ func PourItemToHolders(parsed types.Event, holders []BucketFactory, buckets *Buc
|
|||
}
|
||||
buckey := GetKey(holder, groupby)
|
||||
|
||||
sigclosed := 0
|
||||
keymiss := 0
|
||||
failed_sent := 0
|
||||
attempts := 0
|
||||
start := time.Now()
|
||||
for !sent {
|
||||
attempts += 1
|
||||
/* Warn the user if we used more than a 100 ms to pour an event, it's at least an half lock*/
|
||||
if attempts%100000 == 0 && start.Add(100*time.Millisecond).Before(time.Now()) {
|
||||
holder.logger.Warningf("stuck for %s sending event to %s (sigclosed:%d keymiss:%d failed_sent:%d attempts:%d)", time.Since(start),
|
||||
buckey, sigclosed, keymiss, failed_sent, attempts)
|
||||
}
|
||||
biface, ok := buckets.Bucket_map.Load(buckey)
|
||||
//biface, bigout
|
||||
/* the bucket doesn't exist, create it !*/
|
||||
if !ok {
|
||||
/*
|
||||
not found in map
|
||||
*/
|
||||
|
||||
holder.logger.Debugf("Creating bucket %s", buckey)
|
||||
keymiss += 1
|
||||
var fresh_bucket *Leaky
|
||||
|
||||
switch parsed.ExpectMode {
|
||||
case TIMEMACHINE:
|
||||
fresh_bucket = NewTimeMachine(holder)
|
||||
holder.logger.Debugf("Creating TimeMachine bucket")
|
||||
case LIVE:
|
||||
fresh_bucket = NewLeaky(holder)
|
||||
holder.logger.Debugf("Creating Live bucket")
|
||||
default:
|
||||
holder.logger.Fatalf("input event has no expected mode, malformed : %+v", parsed)
|
||||
}
|
||||
fresh_bucket.In = make(chan types.Event)
|
||||
fresh_bucket.Mapkey = buckey
|
||||
fresh_bucket.Signal = make(chan bool, 1)
|
||||
buckets.Bucket_map.Store(buckey, fresh_bucket)
|
||||
holder.tomb.Go(func() error {
|
||||
return LeakRoutine(fresh_bucket)
|
||||
})
|
||||
|
||||
holder.logger.Debugf("Created new bucket %s", buckey)
|
||||
|
||||
//wait for signal to be opened
|
||||
<-fresh_bucket.Signal
|
||||
continue
|
||||
}
|
||||
|
||||
bucket := biface.(*Leaky)
|
||||
/* check if leak routine is up */
|
||||
select {
|
||||
case _, ok := <-bucket.Signal:
|
||||
if !ok {
|
||||
//it's closed, delete it
|
||||
bucket.logger.Debugf("Bucket %s found dead, cleanup the body", buckey)
|
||||
buckets.Bucket_map.Delete(buckey)
|
||||
sigclosed += 1
|
||||
continue
|
||||
}
|
||||
holder.logger.Tracef("Signal exists, try to pour :)")
|
||||
|
||||
default:
|
||||
/*nothing to read, but not closed, try to pour */
|
||||
holder.logger.Tracef("Signal exists but empty, try to pour :)")
|
||||
|
||||
}
|
||||
/*let's see if this time-bucket should have expired */
|
||||
if bucket.Mode == TIMEMACHINE {
|
||||
bucket.mutex.Lock()
|
||||
firstTs := bucket.First_ts
|
||||
lastTs := bucket.Last_ts
|
||||
bucket.mutex.Unlock()
|
||||
|
||||
if !firstTs.IsZero() {
|
||||
var d time.Time
|
||||
err = d.UnmarshalText([]byte(parsed.MarshaledTime))
|
||||
//we need to either find the existing bucket, or create a new one (if it's the first event to hit it for this partition key)
|
||||
bucket, err := LoadOrStoreBucketFromHolder(buckey, buckets, holder, parsed.ExpectMode)
|
||||
if err != nil {
|
||||
holder.logger.Warningf("Failed unmarshaling event time (%s) : %v", parsed.MarshaledTime, err)
|
||||
return false, errors.Wrap(err, "failed to load or store bucket")
|
||||
}
|
||||
if d.After(lastTs.Add(bucket.Duration)) {
|
||||
bucket.logger.Tracef("bucket is expired (curr event: %s, bucket deadline: %s), kill", d, lastTs.Add(bucket.Duration))
|
||||
buckets.Bucket_map.Delete(buckey)
|
||||
continue
|
||||
//finally, pour the even into the bucket
|
||||
ok, err := PourItemToBucket(bucket, holder, buckets, parsed)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to pour bucket")
|
||||
}
|
||||
if ok {
|
||||
poured = true
|
||||
}
|
||||
}
|
||||
}
|
||||
/*if we're here, let's try to pour */
|
||||
|
||||
select {
|
||||
case bucket.In <- parsed:
|
||||
holder.logger.Tracef("Successfully sent !")
|
||||
//and track item poured to each bucket
|
||||
if BucketPourTrack {
|
||||
if _, ok := BucketPourCache[bucket.Name]; !ok {
|
||||
BucketPourCache[bucket.Name] = make([]types.Event, 0)
|
||||
}
|
||||
evt := deepcopy.Copy(parsed)
|
||||
BucketPourCache[bucket.Name] = append(BucketPourCache[bucket.Name], evt.(types.Event))
|
||||
}
|
||||
|
||||
//sent was successful !
|
||||
sent = true
|
||||
continue
|
||||
default:
|
||||
failed_sent += 1
|
||||
holder.logger.Tracef("Failed to send, try again")
|
||||
continue
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
holder.logger.Debugf("bucket '%s' is poured", holder.Name)
|
||||
}
|
||||
return sent, nil
|
||||
return poured, nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
|
@ -31,6 +32,33 @@ func (m AddAlertsRequest) Validate(formats strfmt.Registry) error {
|
|||
if err := m[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this add alerts request based on the context it is used
|
||||
func (m AddAlertsRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
for i := 0; i < len(m); i++ {
|
||||
|
||||
if m[i] != nil {
|
||||
if err := m[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
|
@ -18,3 +20,8 @@ type AddAlertsResponse []string
|
|||
func (m AddAlertsResponse) Validate(formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this add alerts response based on context it is used
|
||||
func (m AddAlertsResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
|
@ -33,6 +34,33 @@ func (m AddSignalsRequest) Validate(formats strfmt.Registry) error {
|
|||
if err := m[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this add signals request based on the context it is used
|
||||
func (m AddSignalsRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
for i := 0; i < len(m); i++ {
|
||||
|
||||
if m[i] != nil {
|
||||
if err := m[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
@ -136,6 +138,8 @@ func (m *AddSignalsRequestItem) validateSource(formats strfmt.Registry) error {
|
|||
if err := m.Source.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("source")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("source")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -162,6 +166,36 @@ func (m *AddSignalsRequestItem) validateStopAt(formats strfmt.Registry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this add signals request item based on the context it is used
|
||||
func (m *AddSignalsRequestItem) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateSource(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddSignalsRequestItem) contextValidateSource(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Source != nil {
|
||||
if err := m.Source.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("source")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("source")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *AddSignalsRequestItem) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
|
@ -6,6 +6,7 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
|
@ -168,7 +169,6 @@ func (m *Alert) validateCapacity(formats strfmt.Registry) error {
|
|||
}
|
||||
|
||||
func (m *Alert) validateDecisions(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.Decisions) { // not required
|
||||
return nil
|
||||
}
|
||||
|
@ -182,6 +182,8 @@ func (m *Alert) validateDecisions(formats strfmt.Registry) error {
|
|||
if err := m.Decisions[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("decisions" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("decisions" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -207,6 +209,8 @@ func (m *Alert) validateEvents(formats strfmt.Registry) error {
|
|||
if err := m.Events[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("events" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("events" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -245,7 +249,6 @@ func (m *Alert) validateMessage(formats strfmt.Registry) error {
|
|||
}
|
||||
|
||||
func (m *Alert) validateMeta(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.Meta) { // not required
|
||||
return nil
|
||||
}
|
||||
|
@ -253,6 +256,8 @@ func (m *Alert) validateMeta(formats strfmt.Registry) error {
|
|||
if err := m.Meta.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("meta")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("meta")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -306,6 +311,8 @@ func (m *Alert) validateSource(formats strfmt.Registry) error {
|
|||
if err := m.Source.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("source")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("source")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -332,6 +339,141 @@ func (m *Alert) validateStopAt(formats strfmt.Registry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this alert based on the context it is used
|
||||
func (m *Alert) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateCreatedAt(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateDecisions(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateEvents(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateID(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateMachineID(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateMeta(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateSource(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Alert) contextValidateCreatedAt(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.ReadOnly(ctx, "created_at", "body", string(m.CreatedAt)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Alert) contextValidateDecisions(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
for i := 0; i < len(m.Decisions); i++ {
|
||||
|
||||
if m.Decisions[i] != nil {
|
||||
if err := m.Decisions[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("decisions" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("decisions" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Alert) contextValidateEvents(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
for i := 0; i < len(m.Events); i++ {
|
||||
|
||||
if m.Events[i] != nil {
|
||||
if err := m.Events[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("events" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("events" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Alert) contextValidateID(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.ReadOnly(ctx, "id", "body", int64(m.ID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Alert) contextValidateMachineID(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.ReadOnly(ctx, "machine_id", "body", string(m.MachineID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Alert) contextValidateMeta(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := m.Meta.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("meta")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("meta")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Alert) contextValidateSource(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if m.Source != nil {
|
||||
if err := m.Source.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("source")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("source")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *Alert) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
@ -138,6 +140,42 @@ func (m *Decision) validateValue(formats strfmt.Registry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this decision based on the context it is used
|
||||
func (m *Decision) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateID(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateSimulated(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Decision) contextValidateID(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.ReadOnly(ctx, "id", "body", int64(m.ID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Decision) contextValidateSimulated(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := validate.ReadOnly(ctx, "simulated", "body", m.Simulated); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *Decision) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
@ -42,7 +44,6 @@ func (m *DecisionsStreamResponse) Validate(formats strfmt.Registry) error {
|
|||
}
|
||||
|
||||
func (m *DecisionsStreamResponse) validateDeleted(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.Deleted) { // not required
|
||||
return nil
|
||||
}
|
||||
|
@ -50,6 +51,8 @@ func (m *DecisionsStreamResponse) validateDeleted(formats strfmt.Registry) error
|
|||
if err := m.Deleted.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("deleted")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("deleted")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -58,7 +61,6 @@ func (m *DecisionsStreamResponse) validateDeleted(formats strfmt.Registry) error
|
|||
}
|
||||
|
||||
func (m *DecisionsStreamResponse) validateNew(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.New) { // not required
|
||||
return nil
|
||||
}
|
||||
|
@ -66,6 +68,54 @@ func (m *DecisionsStreamResponse) validateNew(formats strfmt.Registry) error {
|
|||
if err := m.New.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("new")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("new")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this decisions stream response based on the context it is used
|
||||
func (m *DecisionsStreamResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateDeleted(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateNew(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *DecisionsStreamResponse) contextValidateDeleted(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := m.Deleted.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("deleted")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("deleted")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *DecisionsStreamResponse) contextValidateNew(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := m.New.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("new")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("new")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
@ -24,6 +26,11 @@ func (m *DeleteAlertsResponse) Validate(formats strfmt.Registry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this delete alerts response based on context it is used
|
||||
func (m *DeleteAlertsResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *DeleteAlertsResponse) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
@ -24,6 +26,11 @@ func (m *DeleteDecisionResponse) Validate(formats strfmt.Registry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this delete decision response based on context it is used
|
||||
func (m *DeleteDecisionResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *DeleteDecisionResponse) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
@ -50,6 +52,11 @@ func (m *ErrorResponse) validateMessage(formats strfmt.Registry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this error response based on context it is used
|
||||
func (m *ErrorResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *ErrorResponse) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
@ -53,6 +55,8 @@ func (m *Event) validateMeta(formats strfmt.Registry) error {
|
|||
if err := m.Meta.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("meta")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("meta")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -69,6 +73,34 @@ func (m *Event) validateTimestamp(formats strfmt.Registry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this event based on the context it is used
|
||||
func (m *Event) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateMeta(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event) contextValidateMeta(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
if err := m.Meta.ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("meta")
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("meta")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *Event) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
|
@ -6,6 +6,7 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
|
@ -31,6 +32,33 @@ func (m GetAlertsResponse) Validate(formats strfmt.Registry) error {
|
|||
if err := m[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this get alerts response based on the context it is used
|
||||
func (m GetAlertsResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
for i := 0; i < len(m); i++ {
|
||||
|
||||
if m[i] != nil {
|
||||
if err := m[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
|
@ -31,6 +32,33 @@ func (m GetDecisionsResponse) Validate(formats strfmt.Registry) error {
|
|||
if err := m[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this get decisions response based on the context it is used
|
||||
func (m GetDecisionsResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
for i := 0; i < len(m); i++ {
|
||||
|
||||
if m[i] != nil {
|
||||
if err := m[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ paths:
|
|||
required: false
|
||||
type: string
|
||||
description: 'Comma separated scopes of decisions to fetch'
|
||||
example: ip,range,country
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
|
@ -406,6 +405,11 @@ paths:
|
|||
required: false
|
||||
type: number
|
||||
description: 'number of alerts to return'
|
||||
- name: origin
|
||||
in: query
|
||||
required: false
|
||||
type: string
|
||||
description: 'restrict results to this origin (ie. lists,CAPI,cscli)'
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
|
@ -485,6 +489,11 @@ paths:
|
|||
required: false
|
||||
type: number
|
||||
description: 'number of alerts to return'
|
||||
- name: origin
|
||||
in: query
|
||||
required: false
|
||||
type: string
|
||||
description: 'restrict results to this origin (ie. lists,CAPI,cscli)'
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
|
|
|
@ -6,6 +6,7 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
|
@ -33,6 +34,33 @@ func (m Meta) Validate(formats strfmt.Registry) error {
|
|||
if err := m[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this meta based on the context it is used
|
||||
func (m Meta) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
for i := 0; i < len(m); i++ {
|
||||
|
||||
if m[i] != nil {
|
||||
if err := m[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName(strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName(strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -63,6 +91,11 @@ func (m *MetaItems0) Validate(formats strfmt.Registry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this meta items0 based on context it is used
|
||||
func (m *MetaItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *MetaItems0) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
|
@ -6,6 +6,7 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
|
@ -78,6 +79,8 @@ func (m *Metrics) validateBouncers(formats strfmt.Registry) error {
|
|||
if err := m.Bouncers[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("bouncers" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("bouncers" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -103,6 +106,66 @@ func (m *Metrics) validateMachines(formats strfmt.Registry) error {
|
|||
if err := m.Machines[i].Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("machines" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("machines" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validate this metrics based on the context it is used
|
||||
func (m *Metrics) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.contextValidateBouncers(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.contextValidateMachines(ctx, formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Metrics) contextValidateBouncers(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
for i := 0; i < len(m.Bouncers); i++ {
|
||||
|
||||
if m.Bouncers[i] != nil {
|
||||
if err := m.Bouncers[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("bouncers" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("bouncers" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Metrics) contextValidateMachines(ctx context.Context, formats strfmt.Registry) error {
|
||||
|
||||
for i := 0; i < len(m.Machines); i++ {
|
||||
|
||||
if m.Machines[i] != nil {
|
||||
if err := m.Machines[i].ContextValidate(ctx, formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("machines" + "." + strconv.Itoa(i))
|
||||
} else if ce, ok := err.(*errors.CompositeError); ok {
|
||||
return ce.ValidateName("machines" + "." + strconv.Itoa(i))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
@ -29,6 +31,11 @@ func (m *MetricsSoftInfo) Validate(formats strfmt.Registry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this metrics soft info based on context it is used
|
||||
func (m *MetricsSoftInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *MetricsSoftInfo) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
@ -83,6 +85,11 @@ func (m *Source) validateValue(formats strfmt.Registry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this source based on context it is used
|
||||
func (m *Source) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *Source) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
@ -70,6 +72,11 @@ func (m *WatcherAuthRequest) validatePassword(formats strfmt.Registry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this watcher auth request based on context it is used
|
||||
func (m *WatcherAuthRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *WatcherAuthRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
@ -32,6 +34,11 @@ func (m *WatcherAuthResponse) Validate(formats strfmt.Registry) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this watcher auth response based on context it is used
|
||||
func (m *WatcherAuthResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *WatcherAuthResponse) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
|
@ -6,6 +6,8 @@ package models
|
|||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
|
@ -67,6 +69,11 @@ func (m *WatcherRegistrationRequest) validatePassword(formats strfmt.Registry) e
|
|||
return nil
|
||||
}
|
||||
|
||||
// ContextValidate validates this watcher registration request based on context it is used
|
||||
func (m *WatcherRegistrationRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *WatcherRegistrationRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
|
|
21
plugins/notifications/email/LICENSE
Normal file
21
plugins/notifications/email/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Crowdsec
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
16
plugins/notifications/email/Makefile
Normal file
16
plugins/notifications/email/Makefile
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Go parameters
|
||||
GOCMD=go
|
||||
GOBUILD=$(GOCMD) build
|
||||
GOCLEAN=$(GOCMD) clean
|
||||
GOTEST=$(GOCMD) test
|
||||
GOGET=$(GOCMD) get
|
||||
BINARY_NAME=notification-email
|
||||
|
||||
clean:
|
||||
@rm -f $(BINARY_NAME)
|
||||
|
||||
build: clean
|
||||
@$(GOBUILD) $(LD_OPTS) -o $(BINARY_NAME) -v
|
||||
|
||||
static: clean
|
||||
$(GOBUILD) $(LD_OPTS_STATIC) -o $(BINARY_NAME) -v -a -tags netgo
|
35
plugins/notifications/email/email.yaml
Normal file
35
plugins/notifications/email/email.yaml
Normal file
|
@ -0,0 +1,35 @@
|
|||
# Don't change this
|
||||
type: email
|
||||
|
||||
name: email_default # this must match with the registered plugin in the profile
|
||||
log_level: info # Options include: trace, debug, info, warn, error, off
|
||||
|
||||
format: | # This template receives list of models.Alert objects
|
||||
{{range . -}}
|
||||
{{$alert := . -}}
|
||||
{{range .Decisions -}}
|
||||
<a href=https://www.whois.com/whois/{{.Value}}>{{.Value}}</a> will get <b>{{.Type}}</b> for next <b>{{.Duration}}</b> for triggering <b>{{.Scenario}}</b>. <a href=https://www.shodan.io/host/{{.Value}}>Shodan</a>
|
||||
{{end -}}
|
||||
{{end -}}
|
||||
|
||||
smtp_host: # eg value smtp.gmail.com
|
||||
smtp_username: #Replace this with your actual username
|
||||
smtp_password: #Replace this with your actual password
|
||||
smtp_port: # Common values are any of [25, 465, 587, 2525]
|
||||
auth_type: # Valid choices are either of "none", "crammd5", "login", "plain"
|
||||
sender_email: # eg: foo@gmail.com
|
||||
email_subject: CrowdSec Notification
|
||||
receiver_emails:
|
||||
# - email1@gmail.com
|
||||
# - email2@gmail.com
|
||||
encryption_type: ssltls # eg valid choices are either "ssltls" or "none"
|
||||
|
||||
|
||||
|
||||
# group_wait: # duration to wait collecting alerts before sending to this plugin, eg "30s"
|
||||
|
||||
# group_threshold: # if alerts exceed this, then the plugin will be sent the message. eg "10"
|
||||
|
||||
# max_retry: # number of tries to attempt to send message to plugins in case of error.
|
||||
|
||||
timeout: 20s # duration to wait for response from plugin before considering this attempt a failure. eg "10s"
|
11
plugins/notifications/email/go.mod
Normal file
11
plugins/notifications/email/go.mod
Normal file
|
@ -0,0 +1,11 @@
|
|||
module github.com/crowdsecurity/email-plugin
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/crowdsecurity/crowdsec v1.2.0
|
||||
github.com/hashicorp/go-hclog v1.0.0
|
||||
github.com/hashicorp/go-plugin v1.4.3
|
||||
github.com/xhit/go-simple-mail/v2 v2.10.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
893
plugins/notifications/email/go.sum
Normal file
893
plugins/notifications/email/go.sum
Normal file
|
@ -0,0 +1,893 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
entgo.io/ent v0.7.0/go.mod h1:HZZJxglL8ro4OVDmM06lijj4bOTGcaDdrZttDZ8fVJs=
|
||||
github.com/AlecAivazis/survey/v2 v2.2.7/go.mod h1:9DYvHgXtiXm6nCn+jXnOXLKbH+Yo9u8fAS/SduGdoPk=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
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/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/alexliesenfeld/health v0.5.1/go.mod h1:N4NDIeQtlWumG+6z1ne1v62eQxktz5ylEgGgH9emdMw=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/antonmedv/expr v1.8.9/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/appleboy/gin-jwt/v2 v2.6.4/go.mod h1:CZpq1cRw+kqi0+yD2CwVw7VGXrrx4AqBdeZnwxVmoAs=
|
||||
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
|
||||
github.com/aws/aws-sdk-go v1.38.34/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/crowdsecurity/crowdsec v1.2.0 h1:tVyE2YczFVqHI+2k8qgnRleVVwIIlwdIo1HsCM5eIi4=
|
||||
github.com/crowdsecurity/crowdsec v1.2.0/go.mod h1:qPjm7NpE8oE0o1o+trVprKye4U5TapNchlzfGoqw/Ec=
|
||||
github.com/crowdsecurity/grokky v0.0.0-20210908095311-0b3373925934/go.mod h1:fx5UYUYAFIrOUNAkFCUOM2wJcsp9EWSQE9R0/9kaFJg=
|
||||
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
|
||||
github.com/dghubble/sling v1.3.0/go.mod h1:XXShWaBWKzNLhu2OxikSNFrlsvowtz4kyRuXUG7oQKY=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v20.10.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/enescakir/emoji v1.0.0/go.mod h1:Bt1EKuLnKDTYpLALApstIkAjdDrS/8IAgTkKp+WKFD0=
|
||||
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-bindata/go-bindata v1.0.1-0.20190711162640-ee3c2418e368/go.mod h1:7xCgX1lzlrXPHkfvn3EhumqHkmSlzt8at9q7v0ax19c=
|
||||
github.com/go-co-op/gocron v0.5.1/go.mod h1:6Btk4lVj3bnFAgbVfr76W8impTyhYrEi1pV5Pt4Tp/M=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
||||
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
|
||||
github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
|
||||
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
|
||||
github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ=
|
||||
github.com/go-openapi/analysis v0.19.16/go.mod h1:GLInF007N83Ad3m8a/CbQ5TPzdnGT7workfHwuVjNVk=
|
||||
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
||||
github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
||||
github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.19.7/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
|
||||
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
|
||||
github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI=
|
||||
github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY=
|
||||
github.com/go-openapi/loads v0.19.6/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc=
|
||||
github.com/go-openapi/loads v0.19.7/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc=
|
||||
github.com/go-openapi/loads v0.20.0/go.mod h1:2LhKquiE513rN5xC6Aan6lYOSddlL8Mp20AW9kpviM4=
|
||||
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
|
||||
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
|
||||
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
|
||||
github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo=
|
||||
github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98=
|
||||
github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk=
|
||||
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
|
||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
|
||||
github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
|
||||
github.com/go-openapi/spec v0.19.15/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU=
|
||||
github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU=
|
||||
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
|
||||
github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
|
||||
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
|
||||
github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=
|
||||
github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=
|
||||
github.com/go-openapi/strfmt v0.19.11/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
|
||||
github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
|
||||
github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M=
|
||||
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
|
||||
github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo=
|
||||
github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8=
|
||||
github.com/go-openapi/validate v0.19.12/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4=
|
||||
github.com/go-openapi/validate v0.19.15/go.mod h1:tbn/fdOwYHgrhPBzidZfJC2MIVvs9GA7monOmWBbeCI=
|
||||
github.com/go-openapi/validate v0.20.0/go.mod h1:b60iJT+xNNLfaQJUqLI7946tYiFEOuE9E4k54HpKcJ0=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.5.1-0.20200311113236-681ffa848bae/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
|
||||
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
|
||||
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
|
||||
github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
||||
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
||||
github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
|
||||
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
|
||||
github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
|
||||
github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
|
||||
github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
|
||||
github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
|
||||
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
|
||||
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
|
||||
github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
|
||||
github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
|
||||
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
|
||||
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
|
||||
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
|
||||
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
|
||||
github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
|
||||
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
|
||||
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
|
||||
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
|
||||
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
|
||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
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.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e/go.mod h1:AFIo+02s+12CEg8Gzz9kzhCbmbq6JcKNrhHffCGA9z4=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-hclog v1.0.0 h1:bkKf0BeBXcSYa7f5Fyi9gMuQ8gNsxeiNpZjR6VxNZeo=
|
||||
github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-plugin v1.4.2/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
|
||||
github.com/hashicorp/go-plugin v1.4.3 h1:DXmvivbWD5qdiBts9TpBC7BYL1Aia5sxbRgQB+v6UZM=
|
||||
github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/go-syslog/v3 v3.0.0/go.mod h1:tulsOp+CecTAYC27u9miMgq21GqXRW6VdKbOG+QSP4Q=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
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/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
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.3/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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/leodido/ragel-machinery v0.0.0-20181214104525-299bdde78165/go.mod h1:WZxr2/6a/Ar9bMDc2rN/LJrE/hF6bXE4LPyDSIxwAfg=
|
||||
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
|
||||
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.6/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
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/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/oschwald/geoip2-golang v1.4.0/go.mod h1:8QwxJvRImBH+Zl6Aa6MaIcs5YdlZSTKtzmPGzQqi9ng=
|
||||
github.com/oschwald/maxminddb-golang v1.6.0/go.mod h1:DUJFucBg2cvqx42YmDa/+xHvb0elJtOm3o4aFQ/nb/w=
|
||||
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
|
||||
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
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/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/prom2json v1.3.0/go.mod h1:rMN7m0ApCowcoDlypBHlkNbp5eJQf/+1isKykIP5ZnM=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/sanity-io/litter v1.2.0/go.mod h1:JF6pZUFgu2Q0sBZ+HSV35P8TVPI1TTzEwyu9FXAw2W4=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||
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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
|
||||
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.2.3/go.mod h1:5l8GZ8hZvmL4uMdy+mhCO1LjswGRYco9Q3HfuisB21A=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.2.3/go.mod h1:5FxzDJIgeiWJZslYHPj+LS1dq1ZBQVelZFnjsFGI/Uc=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
||||
github.com/vjeantet/grok v1.0.1/go.mod h1:ax1aAchzC6/QMXMcyzHQGZWaW1l195+uMYIkCWPCNIo=
|
||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
github.com/xhit/go-simple-mail/v2 v2.10.0 h1:nib6RaJ4qVh5HD9UE9QJqnUZyWp3upv+Z6CFxaMj0V8=
|
||||
github.com/xhit/go-simple-mail/v2 v2.10.0/go.mod h1:kA1XbQfCI4JxQ9ccSN6VFyIEkkugOm7YiPkA5hKiQn4=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
|
||||
go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
|
||||
go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
||||
go.mongodb.org/mongo-driver v1.4.4/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
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.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/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-20181023162649-9b4f9f5ad519/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-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/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-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c=
|
||||
golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/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-20190114222345-bf090417da8b/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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f h1:izedQ6yVIc5mZsRuXzmSreCOlzI0lCU1HpG8yEdMiKw=
|
||||
google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
122
plugins/notifications/email/main.go
Normal file
122
plugins/notifications/email/main.go
Normal file
|
@ -0,0 +1,122 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/crowdsecurity/crowdsec/pkg/protobufs"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
plugin "github.com/hashicorp/go-plugin"
|
||||
mail "github.com/xhit/go-simple-mail/v2"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var logger hclog.Logger = hclog.New(&hclog.LoggerOptions{
|
||||
Name: "email-plugin",
|
||||
Level: hclog.LevelFromString("DEBUG"),
|
||||
Output: os.Stderr,
|
||||
JSONFormat: true,
|
||||
})
|
||||
|
||||
var AuthStringToType map[string]mail.AuthType = map[string]mail.AuthType{
|
||||
"none": mail.AuthNone,
|
||||
"crammd5": mail.AuthCRAMMD5,
|
||||
"login": mail.AuthLogin,
|
||||
"plain": mail.AuthPlain,
|
||||
}
|
||||
|
||||
var EncryptionStringToType map[string]mail.Encryption = map[string]mail.Encryption{
|
||||
"ssltls": mail.EncryptionSTARTTLS,
|
||||
"none": mail.EncryptionNone,
|
||||
}
|
||||
|
||||
type PluginConfig struct {
|
||||
Name string `yaml:"name"`
|
||||
LogLevel *string `yaml:"log_level"`
|
||||
|
||||
SMTPHost string `yaml:"smtp_host"`
|
||||
SMTPPort int `yaml:"smtp_port"`
|
||||
SMTPUsername string `yaml:"smtp_username"`
|
||||
SMTPPassword string `yaml:"smtp_password"`
|
||||
SenderEmail string `yaml:"sender_email"`
|
||||
ReceiverEmails []string `yaml:"receiver_emails"`
|
||||
EmailSubject string `yaml:"email_subject"`
|
||||
EncryptionType string `yaml:"encryption_type"`
|
||||
AuthType string `yaml:"auth_type"`
|
||||
}
|
||||
|
||||
type EmailPlugin struct {
|
||||
ConfigByName map[string]PluginConfig
|
||||
}
|
||||
|
||||
func (n *EmailPlugin) Configure(ctx context.Context, config *protobufs.Config) (*protobufs.Empty, error) {
|
||||
d := PluginConfig{}
|
||||
if err := yaml.Unmarshal(config.Config, &d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n.ConfigByName[d.Name] = d
|
||||
return &protobufs.Empty{}, nil
|
||||
}
|
||||
|
||||
func (n *EmailPlugin) Notify(ctx context.Context, notification *protobufs.Notification) (*protobufs.Empty, error) {
|
||||
if _, ok := n.ConfigByName[notification.Name]; !ok {
|
||||
return nil, fmt.Errorf("invalid plugin config name %s", notification.Name)
|
||||
}
|
||||
cfg := n.ConfigByName[notification.Name]
|
||||
if cfg.LogLevel != nil && *cfg.LogLevel != "" {
|
||||
logger.SetLevel(hclog.LevelFromString(*cfg.LogLevel))
|
||||
} else {
|
||||
logger.SetLevel(hclog.Info)
|
||||
}
|
||||
logger = logger.Named(cfg.Name)
|
||||
logger.Debug("got notification")
|
||||
|
||||
server := mail.NewSMTPClient()
|
||||
server.Host = cfg.SMTPHost
|
||||
server.Port = cfg.SMTPPort
|
||||
server.Username = cfg.SMTPUsername
|
||||
server.Password = cfg.SMTPPassword
|
||||
server.Encryption = EncryptionStringToType[cfg.EncryptionType]
|
||||
server.Authentication = AuthStringToType[cfg.AuthType]
|
||||
|
||||
logger.Debug("making smtp connection")
|
||||
smtpClient, err := server.Connect()
|
||||
if err != nil {
|
||||
return &protobufs.Empty{}, err
|
||||
}
|
||||
logger.Debug("smtp connection done")
|
||||
|
||||
email := mail.NewMSG()
|
||||
email.SetFrom(fmt.Sprintf("From <%s>", cfg.SenderEmail)).
|
||||
AddTo(cfg.ReceiverEmails...).
|
||||
SetSubject(cfg.EmailSubject)
|
||||
email.SetBody(mail.TextHTML, notification.Text)
|
||||
|
||||
err = email.Send(smtpClient)
|
||||
if err != nil {
|
||||
return &protobufs.Empty{}, err
|
||||
} else {
|
||||
logger.Info(fmt.Sprintf("sent email to %v", cfg.ReceiverEmails))
|
||||
}
|
||||
return &protobufs.Empty{}, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
var handshake = plugin.HandshakeConfig{
|
||||
ProtocolVersion: 1,
|
||||
MagicCookieKey: "CROWDSEC_PLUGIN_KEY",
|
||||
MagicCookieValue: os.Getenv("CROWDSEC_PLUGIN_KEY"),
|
||||
}
|
||||
|
||||
plugin.Serve(&plugin.ServeConfig{
|
||||
HandshakeConfig: handshake,
|
||||
Plugins: map[string]plugin.Plugin{
|
||||
"email": &protobufs.NotifierPlugin{
|
||||
Impl: &EmailPlugin{ConfigByName: make(map[string]PluginConfig)},
|
||||
},
|
||||
},
|
||||
GRPCServer: plugin.DefaultGRPCServer,
|
||||
Logger: logger,
|
||||
})
|
||||
}
|
|
@ -10,7 +10,7 @@ ${CSCLI_BIN} collections list || fail "failed to list collections"
|
|||
BASE_COLLECTION_COUNT=2
|
||||
|
||||
# we expect 1 collections : linux
|
||||
${CSCLI_BIN} collections list -ojson | ${JQ} ". | length == ${BASE_COLLECTION_COUNT}" || fail "(first) expected exactly ${BASE_COLLECTION_COUNT} collection"
|
||||
${CSCLI_BIN} collections list -ojson | ${JQ} ".collections | length == ${BASE_COLLECTION_COUNT}" || fail "(first) expected exactly ${BASE_COLLECTION_COUNT} collection"
|
||||
|
||||
# install an extra collection
|
||||
${CSCLI} collections install crowdsecurity/mysql || fail "failed to install collection"
|
||||
|
@ -18,7 +18,7 @@ ${CSCLI} collections install crowdsecurity/mysql || fail "failed to install coll
|
|||
BASE_COLLECTION_COUNT=$(($BASE_COLLECTION_COUNT+1))
|
||||
|
||||
# we should now have 2 collections :)
|
||||
${CSCLI_BIN} collections list -ojson | ${JQ} ". | length == ${BASE_COLLECTION_COUNT}" || fail "(post install) expected exactly ${BASE_COLLECTION_COUNT} collection"
|
||||
${CSCLI_BIN} collections list -ojson | ${JQ} ".collections | length == ${BASE_COLLECTION_COUNT}" || fail "(post install) expected exactly ${BASE_COLLECTION_COUNT} collection"
|
||||
|
||||
# remove the collection
|
||||
${CSCLI} collections remove crowdsecurity/mysql || fail "failed to remove collection"
|
||||
|
@ -26,5 +26,5 @@ ${CSCLI} collections remove crowdsecurity/mysql || fail "failed to remove collec
|
|||
BASE_COLLECTION_COUNT=$(($BASE_COLLECTION_COUNT-1))
|
||||
|
||||
# we expect 1 collections : linux
|
||||
${CSCLI_BIN} collections list -ojson | ${JQ} ". | length == ${BASE_COLLECTION_COUNT}" || fail "(post remove) expected exactly ${BASE_COLLECTION_COUNT} collection"
|
||||
${CSCLI_BIN} collections list -ojson | ${JQ} ".collections | length == ${BASE_COLLECTION_COUNT}" || fail "(post remove) expected exactly ${BASE_COLLECTION_COUNT} collection"
|
||||
|
||||
|
|
|
@ -68,10 +68,12 @@ smb
|
|||
HTTP_PLUGIN_BINARY="./plugins/notifications/http/notification-http"
|
||||
SLACK_PLUGIN_BINARY="./plugins/notifications/slack/notification-slack"
|
||||
SPLUNK_PLUGIN_BINARY="./plugins/notifications/splunk/notification-splunk"
|
||||
EMAIL_PLUGIN_BINARY="./plugins/notifications/email/notification-email"
|
||||
|
||||
HTTP_PLUGIN_CONFIG="./plugins/notifications/http/http.yaml"
|
||||
SLACK_PLUGIN_CONFIG="./plugins/notifications/slack/slack.yaml"
|
||||
SPLUNK_PLUGIN_CONFIG="./plugins/notifications/splunk/splunk.yaml"
|
||||
EMAIL_PLUGIN_CONFIG="./plugins/notifications/email/email.yaml"
|
||||
|
||||
BACKUP_DIR=$(mktemp -d)
|
||||
rm -rf $BACKUP_DIR
|
||||
|
@ -493,11 +495,13 @@ install_plugins(){
|
|||
cp ${SLACK_PLUGIN_BINARY} ${CROWDSEC_PLUGIN_DIR}
|
||||
cp ${SPLUNK_PLUGIN_BINARY} ${CROWDSEC_PLUGIN_DIR}
|
||||
cp ${HTTP_PLUGIN_BINARY} ${CROWDSEC_PLUGIN_DIR}
|
||||
cp ${EMAIL_PLUGIN_BINARY} ${CROWDSEC_PLUGIN_DIR}
|
||||
|
||||
if [[ ${DOCKER_MODE} == "false" ]]; then
|
||||
cp -n ${SLACK_PLUGIN_CONFIG} /etc/crowdsec/notifications/
|
||||
cp -n ${SPLUNK_PLUGIN_CONFIG} /etc/crowdsec/notifications/
|
||||
cp -n ${HTTP_PLUGIN_CONFIG} /etc/crowdsec/notifications/
|
||||
cp -n ${EMAIL_PLUGIN_CONFIG} /etc/crowdsec/notifications
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue