diff --git a/thehive-backend/app/models/Alert.scala b/thehive-backend/app/models/Alert.scala index 2dcde4860f..01451cdd78 100644 --- a/thehive-backend/app/models/Alert.scala +++ b/thehive-backend/app/models/Alert.scala @@ -61,19 +61,19 @@ trait AlertAttributes { ) } - val alertId: A[String] = attribute("_id", F.stringFmt, "Alert id", O.readonly) - val tpe: A[String] = attribute("type", F.stringFmt, "Type of the alert", O.readonly) - val source: A[String] = attribute("source", F.stringFmt, "Source of the alert", O.readonly) - val sourceRef: A[String] = attribute("sourceRef", F.stringFmt, "Source reference of the alert", O.readonly) - val date: A[Date] = attribute("date", F.dateFmt, "Date of the alert", new Date(), O.readonly) - val lastSyncDate: A[Date] = attribute("lastSyncDate", F.dateFmt, "Date of the last synchronization", new Date()) - val caze: A[Option[String]] = optionalAttribute("case", F.stringFmt, "Id of the case, if created") - val title: A[String] = attribute("title", F.textFmt, "Title of the alert") - val description: A[String] = attribute("description", F.textFmt, "Description of the alert") - val severity: A[Long] = attribute("severity", SeverityAttributeFormat, "Severity if the alert (0-3)", 2L) - val tags: A[Seq[String]] = multiAttribute("tags", F.stringFmt, "Alert tags") - val tlp: A[Long] = attribute("tlp", TlpAttributeFormat, "TLP level", 2L) - val artifacts: A[Seq[JsObject]] = multiAttribute("artifacts", F.objectFmt(artifactAttributes), "Artifact of the alert", O.unaudited) + val alertId: A[String] = attribute("_id", F.stringFmt, "Alert id", O.readonly) + val tpe: A[String] = attribute("type", F.stringFmt, "Type of the alert", O.readonly) + val source: A[String] = attribute("source", F.stringFmt, "Source of the alert", O.readonly) + val sourceRef: A[String] = attribute("sourceRef", F.stringFmt, "Source reference of the alert", O.readonly) + val date: A[Date] = attribute("date", F.dateFmt, "Date of the alert", new Date(), O.readonly) + val lastSyncDate: A[Date] = attribute("lastSyncDate", F.dateFmt, "Date of the last synchronization", new Date()) + val caze: A[Option[String]] = optionalAttribute("case", F.stringFmt, "Id of the case, if created") + val title: A[String] = attribute("title", F.textFmt, "Title of the alert") + val description: A[String] = attribute("description", F.textFmt, "Description of the alert") + val severity: A[Long] = attribute("severity", SeverityAttributeFormat, "Severity if the alert (1-4)", 2L) + val tags: A[Seq[String]] = multiAttribute("tags", F.stringFmt, "Alert tags") + val tlp: A[Long] = attribute("tlp", TlpAttributeFormat, "TLP level", 2L) + val artifacts: A[Seq[JsObject]] = multiAttribute("artifacts", F.objectFmt(artifactAttributes), "Artifact of the alert", O.unaudited) val caseTemplate: A[Option[String]] = optionalAttribute("caseTemplate", F.stringFmt, "Case template to use") val status: A[AlertStatus.Value] = attribute("status", F.enumFmt(AlertStatus), "Status of the alert", AlertStatus.New) val follow: A[Boolean] = attribute("follow", F.booleanFmt, "", true) diff --git a/thehive-backend/app/models/AttributeFormat.scala b/thehive-backend/app/models/AttributeFormat.scala index debadb278e..c0fb7551ee 100644 --- a/thehive-backend/app/models/AttributeFormat.scala +++ b/thehive-backend/app/models/AttributeFormat.scala @@ -11,7 +11,7 @@ import org.elastic4play.{AttributeError, InvalidFormatAttributeError} object SeverityAttributeFormat extends NumberAttributeFormat { - def isValidValue(value: Long): Boolean = 1 <= value && value <= 3 + def isValidValue(value: Long): Boolean = 1 <= value && value <= 4 override def definition(dblists: DBLists, attribute: Attribute[Long]): Seq[AttributeDefinition] = Seq( diff --git a/thehive-backend/app/models/Case.scala b/thehive-backend/app/models/Case.scala index a6fe3984d5..80f99a4a86 100644 --- a/thehive-backend/app/models/Case.scala +++ b/thehive-backend/app/models/Case.scala @@ -20,7 +20,7 @@ import org.elastic4play.services.{FindSrv, SequenceSrv} object CaseStatus extends Enumeration with HiveEnumeration { type Type = Value - val Open, Resolved, Deleted = Value + val Open, Resolved, Pending, Hold, Review, Deleted = Value } object CaseResolutionStatus extends Enumeration with HiveEnumeration { diff --git a/thehive-backend/app/models/CaseTemplate.scala b/thehive-backend/app/models/CaseTemplate.scala index 83ef3a8f81..4f8d134ab2 100644 --- a/thehive-backend/app/models/CaseTemplate.scala +++ b/thehive-backend/app/models/CaseTemplate.scala @@ -45,4 +45,3 @@ class CaseTemplate(model: CaseTemplateModel, attributes: JsObject) extends EntityDef[CaseTemplateModel, CaseTemplate](model, attributes) with CaseTemplateAttributes { def taskAttributes = Nil -} diff --git a/thehive-cortex/app/connectors/cortex/services/ActionOperation.scala b/thehive-cortex/app/connectors/cortex/services/ActionOperation.scala index e5961c91c7..7dce31b4a6 100644 --- a/thehive-cortex/app/connectors/cortex/services/ActionOperation.scala +++ b/thehive-cortex/app/connectors/cortex/services/ActionOperation.scala @@ -98,6 +98,10 @@ case class AssignCase(owner: String, status: ActionOperationStatus.Type = Action override def updateStatus(newStatus: ActionOperationStatus.Type, newMessage: String): AssignCase = copy(status = newStatus, message = newMessage) } +case class SetCaseTitle(title: String, status: ActionOperationStatus.Type = ActionOperationStatus.Waiting, message: String = "") extends ActionOperation { + override def updateStatus(newStatus: ActionOperationStatus.Type, newMessage: String): SetCaseTitle = copy(status = newStatus, message = newMessage) +} + object ActionOperation { val addTagToCaseWrites = Json.writes[AddTagToCase] val addTagToArtifactWrites = Json.writes[AddTagToArtifact] diff --git a/ui/app/scripts/controllers/case/CaseListCtrl.js b/ui/app/scripts/controllers/case/CaseListCtrl.js index 933bb964f0..b4966531bb 100644 --- a/ui/app/scripts/controllers/case/CaseListCtrl.js +++ b/ui/app/scripts/controllers/case/CaseListCtrl.js @@ -131,11 +131,28 @@ this.filter(); }; - this.getStatuses = function() { - return $q.resolve([ + this.getStatuses = function(query) { + var defer = $q.defer(); + + $q.resolve([ {text: 'Open'}, - {text: 'Resolved'} - ]); + {text: 'Resolved'}, + {text: 'Hold'}, + {text: 'Review'}, + {text: 'Pending'} + ]).then(function(response) { + var statuses = []; + + statuses = _.filter(response, function(stat) { + var regex = new RegExp(query, 'gi'); + return regex.test(stat.text); + }); + + defer.resolve(statuses); + }); + + return defer.promise; + }; this.getSeverities = function(query) { diff --git a/ui/app/scripts/controllers/case/CaseMainCtrl.js b/ui/app/scripts/controllers/case/CaseMainCtrl.js index 07fa4844fc..168526068f 100644 --- a/ui/app/scripts/controllers/case/CaseMainCtrl.js +++ b/ui/app/scripts/controllers/case/CaseMainCtrl.js @@ -171,6 +171,34 @@ } }; + $scope.caseHold = function() { + $scope.updateField('status', 'Hold') + .then(function() { + NotificationSrv.log('The case #' + $scope.caze.caseId + ' has been set to Hold', 'success'); + }); + } + + $scope.caseReview = function() { + $scope.updateField('status', 'Review') + .then(function() { + NotificationSrv.log('The case #' + $scope.caze.caseId + ' has been set to Review', 'success'); + }); + } + + $scope.casePending = function() { + $scope.updateField('status', 'Pending') + .then(function() { + NotificationSrv.log('The case #' + $scope.caze.caseId + ' has been set to Pending', 'success'); + }); + } + + $scope.caseOpenFromOtherStatus = function() { + $scope.updateField('status', 'Open') + .then(function() { + NotificationSrv.log('The case #' + $scope.caze.caseId + ' has been set to Pending', 'success'); + }); + } + // update a specific case field $scope.updateField = function(fieldName, newValue) { var data = {}; diff --git a/ui/app/scripts/services/Constants.js b/ui/app/scripts/services/Constants.js index 0bae8587ac..9ae839dcb1 100644 --- a/ui/app/scripts/services/Constants.js +++ b/ui/app/scripts/services/Constants.js @@ -16,11 +16,12 @@ }) .value('Severity', { keys: { + Critical: 4, High: 3, Medium: 2, Low: 1 }, - values: ['Unknown', 'Low', 'Medium', 'High'] + values: ['Unknown', 'Low', 'Medium', 'High', 'Critical'] }) .value('AlertStatus', { values: ['New', 'Updated', 'Ignored', 'Imported'] diff --git a/ui/app/views/directives/severity.html b/ui/app/views/directives/severity.html index 193495b93a..373297371b 100644 --- a/ui/app/views/directives/severity.html +++ b/ui/app/views/directives/severity.html @@ -1,11 +1,14 @@
- L - M - H + L + M + H + !! +
- L - M - H + L + M + H + !! ? diff --git a/ui/app/views/partials/alert/list/filters.html b/ui/app/views/partials/alert/list/filters.html index 33c873611f..8f91ead91d 100644 --- a/ui/app/views/partials/alert/list/filters.html +++ b/ui/app/views/partials/alert/list/filters.html @@ -89,7 +89,7 @@

Filters

diff --git a/ui/app/views/partials/case/case.list.html b/ui/app/views/partials/case/case.list.html index 652263c438..4e632b3a1f 100644 --- a/ui/app/views/partials/case/case.list.html +++ b/ui/app/views/partials/case/case.list.html @@ -78,11 +78,16 @@

List of cases ({{$vm.list.total || 0}} of {{$vm.caseStats. -
+
(Closed at {{currentCase.endDate | showDate}} as {{$vm.CaseResolutionStatus[currentCase.resolutionStatus]}})
+
+ + (Status: {{currentCase.status}}) + +
Merged from Case #{{currentCase.stats.mergeFrom[0].caseId}} and diff --git a/ui/app/views/partials/case/case.panelinfo.html b/ui/app/views/partials/case/case.panelinfo.html index c7a15240bb..d815a9e31e 100644 --- a/ui/app/views/partials/case/case.panelinfo.html +++ b/ui/app/views/partials/case/case.panelinfo.html @@ -30,6 +30,9 @@

{{CaseResolutionStatus[caze.resolutionStatus]}} with {{caze.impactStatus === 'NoImpact' ? 'No Impact' : 'Impact'}}) + ( + Status {{caze.status}}) + @@ -93,6 +96,10 @@

+ + | + + @@ -105,6 +112,49 @@

Unflag + + + + + Hold + + + + + + + Hold + + + + + + + Pending + + + + + + + Pending + + + + + + + Review + + + + + + + Review + + + diff --git a/ui/app/views/partials/case/list/filters.html b/ui/app/views/partials/case/list/filters.html index 9566871ff9..a7208c5fc6 100644 --- a/ui/app/views/partials/case/list/filters.html +++ b/ui/app/views/partials/case/list/filters.html @@ -71,7 +71,7 @@

Filters