bitbucket.org/Aishee/synsec@v0.0.0-20210414005726-236fc01a153d/pkg/apiserver/controllers/v1/alerts.go (about) 1 package v1 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strconv" 8 "time" 9 10 jwt "github.com/appleboy/gin-jwt/v2" 11 12 "bitbucket.org/Aishee/synsec/pkg/csprofiles" 13 "bitbucket.org/Aishee/synsec/pkg/database/ent" 14 "bitbucket.org/Aishee/synsec/pkg/models" 15 "bitbucket.org/Aishee/synsec/pkg/types" 16 "github.com/gin-gonic/gin" 17 "github.com/go-openapi/strfmt" 18 log "github.com/sirupsen/logrus" 19 ) 20 21 func FormatOneAlert(alert *ent.Alert) *models.Alert { 22 var outputAlert models.Alert 23 var machineID string 24 startAt := alert.StartedAt.String() 25 StopAt := alert.StoppedAt.String() 26 if alert.Edges.Owner == nil { 27 machineID = "N/A" 28 } else { 29 machineID = alert.Edges.Owner.MachineId 30 } 31 32 outputAlert = models.Alert{ 33 ID: int64(alert.ID), 34 MachineID: machineID, 35 CreatedAt: alert.CreatedAt.Format(time.RFC3339), 36 Scenario: &alert.Scenario, 37 ScenarioVersion: &alert.ScenarioVersion, 38 ScenarioHash: &alert.ScenarioHash, 39 Message: &alert.Message, 40 EventsCount: &alert.EventsCount, 41 StartAt: &startAt, 42 StopAt: &StopAt, 43 Capacity: &alert.Capacity, 44 Leakspeed: &alert.LeakSpeed, 45 Simulated: &alert.Simulated, 46 Source: &models.Source{ 47 Scope: &alert.SourceScope, 48 Value: &alert.SourceValue, 49 IP: alert.SourceIp, 50 Range: alert.SourceRange, 51 AsNumber: alert.SourceAsNumber, 52 AsName: alert.SourceAsName, 53 Cn: alert.SourceCountry, 54 Latitude: alert.SourceLatitude, 55 Longitude: alert.SourceLongitude, 56 }, 57 } 58 for _, eventItem := range alert.Edges.Events { 59 var Metas models.Meta 60 timestamp := eventItem.Time.String() 61 if err := json.Unmarshal([]byte(eventItem.Serialized), &Metas); err != nil { 62 log.Errorf("unable to unmarshall events meta '%s' : %s", eventItem.Serialized, err) 63 } 64 outputAlert.Events = append(outputAlert.Events, &models.Event{ 65 Timestamp: ×tamp, 66 Meta: Metas, 67 }) 68 } 69 for _, metaItem := range alert.Edges.Metas { 70 outputAlert.Meta = append(outputAlert.Meta, &models.MetaItems0{ 71 Key: metaItem.Key, 72 Value: metaItem.Value, 73 }) 74 } 75 for _, decisionItem := range alert.Edges.Decisions { 76 duration := decisionItem.Until.Sub(time.Now()).String() 77 outputAlert.Decisions = append(outputAlert.Decisions, &models.Decision{ 78 Duration: &duration, // transform into time.Time ? 79 Scenario: &decisionItem.Scenario, 80 Type: &decisionItem.Type, 81 Scope: &decisionItem.Scope, 82 Value: &decisionItem.Value, 83 Origin: &decisionItem.Origin, 84 Simulated: outputAlert.Simulated, 85 ID: int64(decisionItem.ID), 86 }) 87 } 88 return &outputAlert 89 } 90 91 // FormatAlerts : Format results from the database to be swagger model compliant 92 func FormatAlerts(result []*ent.Alert) models.AddAlertsRequest { 93 var data models.AddAlertsRequest 94 for _, alertItem := range result { 95 data = append(data, FormatOneAlert(alertItem)) 96 } 97 return data 98 } 99 100 // CreateAlert : write received alerts in body to the database 101 func (c *Controller) CreateAlert(gctx *gin.Context) { 102 defer types.CatchPanic("synsec/controllersV1/CreateAlert") 103 104 var input models.AddAlertsRequest 105 106 claims := jwt.ExtractClaims(gctx) 107 /*TBD : use defines rather than hardcoded key to find back owner*/ 108 machineID := claims["id"].(string) 109 110 if err := gctx.ShouldBindJSON(&input); err != nil { 111 gctx.JSON(http.StatusBadRequest, gin.H{"message": err.Error()}) 112 return 113 } 114 if err := input.Validate(strfmt.Default); err != nil { 115 c.HandleDBErrors(gctx, err) 116 return 117 } 118 119 for _, alert := range input { 120 if len(alert.Decisions) == 0 { 121 decisions, err := csprofiles.EvaluateProfiles(c.Profiles, alert) 122 if err != nil { 123 gctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) 124 return 125 } 126 alert.Decisions = decisions 127 } 128 } 129 130 alerts, err := c.DBClient.CreateAlert(machineID, input) 131 if err != nil { 132 c.HandleDBErrors(gctx, err) 133 return 134 } 135 for _, alert := range input { 136 alert.MachineID = machineID 137 } 138 select { 139 case c.CAPIChan <- input: 140 log.Debugf("alert send to CAPI channel") 141 default: 142 log.Warningf("Cannot send alert to Central API channel") 143 } 144 145 gctx.JSON(http.StatusCreated, alerts) 146 return 147 } 148 149 // FindAlerts : return alerts from database based on the specified filter 150 func (c *Controller) FindAlerts(gctx *gin.Context) { 151 defer types.CatchPanic("synsec/controllersV1/FindAlerts") 152 result, err := c.DBClient.QueryAlertWithFilter(gctx.Request.URL.Query()) 153 if err != nil { 154 c.HandleDBErrors(gctx, err) 155 return 156 } 157 data := FormatAlerts(result) 158 159 if gctx.Request.Method == "HEAD" { 160 gctx.String(http.StatusOK, "") 161 return 162 } 163 gctx.JSON(http.StatusOK, data) 164 return 165 } 166 167 // FindAlertByID return the alert assiocated to the ID 168 func (c *Controller) FindAlertByID(gctx *gin.Context) { 169 defer types.CatchPanic("synsec/controllersV1/FindAlertByID") 170 171 alertIDStr := gctx.Param("alert_id") 172 alertID, err := strconv.Atoi(alertIDStr) 173 if err != nil { 174 gctx.JSON(http.StatusBadRequest, gin.H{"message": "alert_id must be valid integer"}) 175 return 176 } 177 result, err := c.DBClient.GetAlertByID(alertID) 178 if err != nil { 179 c.HandleDBErrors(gctx, err) 180 return 181 } 182 data := FormatOneAlert(result) 183 184 if gctx.Request.Method == "HEAD" { 185 gctx.String(http.StatusOK, "") 186 return 187 } 188 gctx.JSON(http.StatusOK, data) 189 return 190 } 191 192 // DeleteAlerts : delete alerts from database based on the specified filter 193 func (c *Controller) DeleteAlerts(gctx *gin.Context) { 194 defer types.CatchPanic("synsec/controllersV1/DeleteAlerts") 195 196 if gctx.ClientIP() != "127.0.0.1" && gctx.ClientIP() != "::1" { 197 gctx.JSON(http.StatusForbidden, gin.H{"message": fmt.Sprintf("access forbidden from this IP (%s)", gctx.ClientIP())}) 198 return 199 } 200 var err error 201 nbDeleted, err := c.DBClient.DeleteAlertWithFilter(gctx.Request.URL.Query()) 202 if err != nil { 203 c.HandleDBErrors(gctx, err) 204 } 205 206 deleteAlertsResp := models.DeleteAlertsResponse{ 207 NbDeleted: strconv.Itoa(nbDeleted), 208 } 209 210 gctx.JSON(http.StatusOK, deleteAlertsResp) 211 return 212 }