bitbucket.org/Aishee/synsec@v0.0.0-20210414005726-236fc01a153d/cmd/synsec/output.go (about) 1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "net/url" 7 "sync" 8 "time" 9 10 "bitbucket.org/Aishee/synsec/pkg/apiclient" 11 "bitbucket.org/Aishee/synsec/pkg/csconfig" 12 "bitbucket.org/Aishee/synsec/pkg/cwhub" 13 "bitbucket.org/Aishee/synsec/pkg/cwversion" 14 leaky "bitbucket.org/Aishee/synsec/pkg/leakybucket" 15 "bitbucket.org/Aishee/synsec/pkg/models" 16 "bitbucket.org/Aishee/synsec/pkg/parser" 17 "bitbucket.org/Aishee/synsec/pkg/types" 18 "github.com/go-openapi/strfmt" 19 "github.com/pkg/errors" 20 log "github.com/sirupsen/logrus" 21 ) 22 23 func dedupAlerts(alerts []types.RuntimeAlert) ([]*models.Alert, error) { 24 25 var dedupCache []*models.Alert 26 27 for idx, alert := range alerts { 28 log.Tracef("alert %d/%d", idx, len(alerts)) 29 /*if we have more than one source, we need to dedup */ 30 if len(alert.Sources) == 0 || len(alert.Sources) == 1 { 31 dedupCache = append(dedupCache, alert.Alert) 32 continue 33 } 34 for k, src := range alert.Sources { 35 refsrc := *alert.Alert //copy 36 log.Tracef("source[%s]", k) 37 refsrc.Source = &src 38 dedupCache = append(dedupCache, &refsrc) 39 } 40 } 41 if len(dedupCache) != len(alerts) { 42 log.Tracef("went from %d to %d alerts", len(alerts), len(dedupCache)) 43 } 44 return dedupCache, nil 45 } 46 47 func PushAlerts(alerts []types.RuntimeAlert, client *apiclient.ApiClient) error { 48 ctx := context.Background() 49 alertsToPush, err := dedupAlerts(alerts) 50 51 if err != nil { 52 return errors.Wrap(err, "failed to transform alerts for api") 53 } 54 _, _, err = client.Alerts.Add(ctx, alertsToPush) 55 if err != nil { 56 return errors.Wrap(err, "failed sending alert to LAPI") 57 } 58 return nil 59 } 60 61 func runOutput(input chan types.Event, overflow chan types.Event, buckets *leaky.Buckets, 62 postOverflowCTX parser.UnixParserCtx, postOverflowNodes []parser.Node, apiConfig csconfig.ApiCredentialsCfg) error { 63 64 var err error 65 ticker := time.NewTicker(1 * time.Second) 66 67 var cache []types.RuntimeAlert 68 var cacheMutex sync.Mutex 69 70 scenarios, err := cwhub.GetUpstreamInstalledScenariosAsString() 71 if err != nil { 72 return errors.Wrapf(err, "loading list of installed hub scenarios: %s", err) 73 } 74 75 apiURL, err := url.Parse(apiConfig.URL) 76 if err != nil { 77 return errors.Wrapf(err, "parsing api url ('%s'): %s", apiConfig.URL, err) 78 } 79 80 password := strfmt.Password(apiConfig.Password) 81 82 Client, err := apiclient.NewClient(&apiclient.Config{ 83 MachineID: apiConfig.Login, 84 Password: password, 85 Scenarios: scenarios, 86 UserAgent: fmt.Sprintf("synsec/%s", cwversion.VersionStr()), 87 URL: apiURL, 88 VersionPrefix: "v1", 89 UpdateScenario: cwhub.GetUpstreamInstalledScenariosAsString, 90 }) 91 if err != nil { 92 return errors.Wrapf(err, "new client api: %s", err) 93 } 94 if _, err = Client.Auth.AuthenticateWatcher(context.Background(), models.WatcherAuthRequest{ 95 MachineID: &apiConfig.Login, 96 Password: &password, 97 Scenarios: scenarios, 98 }); err != nil { 99 return errors.Wrapf(err, "authenticate watcher (%s)", apiConfig.Login) 100 } 101 LOOP: 102 for { 103 select { 104 case <-ticker.C: 105 if len(cache) > 0 { 106 cacheMutex.Lock() 107 cachecopy := cache 108 newcache := make([]types.RuntimeAlert, 0) 109 cache = newcache 110 cacheMutex.Unlock() 111 if err := PushAlerts(cachecopy, Client); err != nil { 112 log.Errorf("while pushing to api : %s", err) 113 //just push back the events to the queue 114 cacheMutex.Lock() 115 cache = append(cache, cachecopy...) 116 cacheMutex.Unlock() 117 } 118 } 119 case <-outputsTomb.Dying(): 120 if len(cache) > 0 { 121 cacheMutex.Lock() 122 cachecopy := cache 123 newcache := make([]types.RuntimeAlert, 0) 124 cache = newcache 125 cacheMutex.Unlock() 126 if err := PushAlerts(cachecopy, Client); err != nil { 127 log.Errorf("while pushing leftovers to api : %s", err) 128 } 129 } 130 break LOOP 131 case event := <-overflow: 132 133 /*if alert is empty and mapKey is present, the overflow is just to cleanup bucket*/ 134 if event.Overflow.Alert == nil && event.Overflow.Mapkey != "" { 135 buckets.Bucket_map.Delete(event.Overflow.Mapkey) 136 break 137 } 138 if event.Overflow.Reprocess { 139 log.Debugf("Overflow being reprocessed.") 140 input <- event 141 } 142 /* process post overflow parser nodes */ 143 event, err := parser.Parse(postOverflowCTX, event, postOverflowNodes) 144 if err != nil { 145 return fmt.Errorf("postoverflow failed : %s", err) 146 } 147 log.Printf("%s", *event.Overflow.Alert.Message) 148 if event.Overflow.Whitelisted { 149 log.Printf("[%s] is whitelisted, skip.", *event.Overflow.Alert.Message) 150 continue 151 } 152 cacheMutex.Lock() 153 cache = append(cache, event.Overflow) 154 cacheMutex.Unlock() 155 156 } 157 } 158 159 ticker.Stop() 160 return nil 161 162 }