Skip to content

Commit

Permalink
#236 Add API to fix alert status
Browse files Browse the repository at this point in the history
  • Loading branch information
To-om committed Jun 14, 2017
1 parent 689801f commit 0bd6c54
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 38 deletions.
8 changes: 8 additions & 0 deletions thehive-backend/app/controllers/AlertCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class AlertCtrl @Inject() (
} yield renderer.toOutput(OK, updatedAlert)
}

@Timed
def createCase(id: String): Action[AnyContent] = authenticated(Role.write).async { implicit request
for {
alert alertSrv.get(id)
Expand All @@ -118,8 +119,15 @@ class AlertCtrl @Inject() (
.map { alert renderer.toOutput(OK, alert) }
}

@Timed
def unfollowAlert(id: String): Action[AnyContent] = authenticated(Role.write).async { implicit request
alertSrv.setFollowAlert(id, follow = false)
.map { alert renderer.toOutput(OK, alert) }
}

@Timed
def fixStatus() = authenticated(Role.admin).async { implicit request
alertSrv.fixStatus()
.map(_ NoContent)
}
}
32 changes: 32 additions & 0 deletions thehive-backend/app/services/AlertSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,36 @@ class AlertSrv(
def setFollowAlert(alertId: String, follow: Boolean)(implicit authContext: AuthContext): Future[Alert] = {
updateSrv[AlertModel, Alert](alertModel, alertId, Fields(Json.obj("follow" follow)))
}

def fixStatus()(implicit authContext: AuthContext): Future[Unit] = {
import org.elastic4play.services.QueryDSL._

val updatedStatusFields = Fields.empty.set("status", "Updated")
val (updateAlerts, updateAlertCount) = find("status" ~= "Update", Some("all"), Nil)
updateAlertCount.foreach(c logger.info(s"Updating $c alert with Update status"))
val updateAlertProcess = updateAlerts
.mapAsyncUnordered(3) { alert
logger.debug(s"Updating alert ${alert.id} (status: Update -> Updated)")
update(alert, updatedStatusFields)
.andThen {
case Failure(error) logger.warn(s"""Fail to set "Updated" status to alert ${alert.id}""", error)
}
}

val ignoredStatusFields = Fields.empty.set("status", "Ignored")
val (ignoreAlerts, ignoreAlertCount) = find("status" ~= "Ignore", Some("all"), Nil)
ignoreAlertCount.foreach(c logger.info(s"Updating $c alert with Ignore status"))
val ignoreAlertProcess = ignoreAlerts
.mapAsyncUnordered(3) { alert
logger.debug(s"Updating alert ${alert.id} (status: Ignore -> Ignored)")
update(alert, ignoredStatusFields)
.andThen {
case Failure(error) logger.warn(s"""Fail to set "Ignored" status to alert ${alert.id}""", error)
}
}

(updateAlertProcess ++ ignoreAlertProcess)
.runWith(Sink.ignore)
.map(_ ())
}
}
1 change: 1 addition & 0 deletions thehive-backend/conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ POST /api/alert/:alertId/markAsUnread controllers.AlertCtrl.markAsUn
POST /api/alert/:alertId/createCase controllers.AlertCtrl.createCase(alertId)
POST /api/alert/:alertId/follow controllers.AlertCtrl.followAlert(alertId)
POST /api/alert/:alertId/unfollow controllers.AlertCtrl.unfollowAlert(alertId)
GET /api/alert/_fixStatus controllers.AlertCtrl.fixStatus()

GET /api/flow controllers.FlowCtrl.flow(rootId: Option[String], count: Option[Int])

Expand Down
48 changes: 10 additions & 38 deletions thehive-misp/app/connectors/misp/MispSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -170,46 +170,14 @@ class MispSrv @Inject() (
}

def fullSynchronize()(implicit authContext: AuthContext): Future[immutable.Seq[Try[Alert]]] = {
import org.elastic4play.services.QueryDSL._

val updatedStatusFields = Fields.empty.set("status", "Updated")
val (updateAlerts, updateAlertCount) = alertSrv.find("status" ~= "Update", Some("all"), Nil)
updateAlertCount.foreach(c logger.info(s"Updating $c alert with Update status"))
val updateAlertProcess = updateAlerts
.mapAsyncUnordered(1) { alert
logger.debug(s"Updating alert ${alert.id} (status: Update -> Updated")
alertSrv.update(alert, updatedStatusFields)
.recover {
case error logger.warn(s"""Fail to set "Updated" status to alert ${alert.id}""", error)
}
}
.runWith(Sink.ignore)

val ignoredStatusFields = Fields.empty.set("status", "Ignored")
val (ignoreAlerts, ignoreAlertCount) = alertSrv.find("status" ~= "Ignore", Some("all"), Nil)
ignoreAlertCount.foreach(c logger.info(s"Updating $c alert with Ignore status"))
val ignoreAlertProcess = ignoreAlerts
.mapAsyncUnordered(1) { alert
logger.debug(s"Updating alert ${alert.id} (status: Ignore -> Ignored")
alertSrv.update(alert, ignoredStatusFields)
.recover {
case error logger.warn(s"""Fail to set "Ignored" status to alert ${alert.id}""", error)
}
}
.runWith(Sink.ignore)

updateAlertProcess
.flatMap(_ ignoreAlertProcess)
.flatMap { _
Source(mispConfig.connections.toList)
.flatMapConcat(mispConnection synchronize(mispConnection, new Date(0)))
.runWith(Sink.seq)
}
Source(mispConfig.connections.toList)
.flatMapConcat(mispConnection synchronize(mispConnection, new Date(1)))
.runWith(Sink.seq)
}

def synchronize(mispConnection: MispConnection, lastSyncDate: Date)(implicit authContext: AuthContext): Source[Try[Alert], NotUsed] = {
logger.info(s"Synchronize MISP ${mispConnection.name} from $lastSyncDate")
val fullSynchro = if (lastSyncDate.getTime == 0) Some(lastSyncDate) else None
val fullSynchro = if (lastSyncDate.getTime == 1) Some(lastSyncDate) else None
// get events that have been published after the last synchronization
getEventsFromDate(mispConnection, lastSyncDate)
// get related alert
Expand Down Expand Up @@ -247,7 +215,8 @@ class MispSrv @Inject() (
"caseTemplate" -
"date" +
("artifacts" JsArray(attrs)) +
("status" (if (!alert.follow()) Json.toJson(alert.status())
// if this is a full synchronization, don't update alert status
("status" (if (!alert.follow() || fullSynchro.isDefined) Json.toJson(alert.status())
else alert.status() match {
case AlertStatus.New Json.toJson(AlertStatus.New)
case _ Json.toJson(AlertStatus.Updated)
Expand All @@ -260,7 +229,10 @@ class MispSrv @Inject() (
case Some(caze)
for {
a fAlert
_ caseSrv.update(caze, Fields(alert.toCaseJson))
// if this is a full synchronization, don't update case status
caseFields = if (fullSynchro.isDefined) Fields(alert.toCaseJson).unset("status")
else Fields(alert.toCaseJson)
_ caseSrv.update(caze, caseFields)
_ artifactSrv.create(caze, attrs.map(Fields.apply))
} yield a
})
Expand Down

0 comments on commit 0bd6c54

Please sign in to comment.