Skip to content

Commit

Permalink
Merge branch 'hotfix/4.0.4' into master-th4
Browse files Browse the repository at this point in the history
  • Loading branch information
To-om committed Jan 12, 2021
2 parents bbc4aaa + ee97f71 commit e2c0b7e
Show file tree
Hide file tree
Showing 26 changed files with 541 additions and 284 deletions.
22 changes: 18 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
# Change Log

## [4.0.4](https://github.com/TheHive-Project/TheHive/milestone/67) (2021-01-12)

**Implemented enhancements:**

- [Feature Request] Add alert observable API endpoints [\#1732](https://github.com/TheHive-Project/TheHive/issues/1732)
- [Feature Request] Add alert import date property [\#1733](https://github.com/TheHive-Project/TheHive/issues/1733)
- [Feature Request] Add handling duration properties to imported Alert type [\#1734](https://github.com/TheHive-Project/TheHive/issues/1734)

**Fixed bugs:**

- [Bug] TheHive doesn't start if cassandra is not ready [\#1725](https://github.com/TheHive-Project/TheHive/issues/1725)
- [Bug] Alert imported multiple times (bis) [\#1738](https://github.com/TheHive-Project/TheHive/issues/1738)
- [Bug] Cosmetic fix in alert observables list [\#1744](https://github.com/TheHive-Project/TheHive/issues/1744)

## [4.0.3](https://github.com/TheHive-Project/TheHive/milestone/66) (2020-12-22)

**Implemented enhancements:**

- Providing output details for Responders [\#1293](https://github.com/TheHive-Project/TheHive/issues/1293)
- [Enhancement] Change artifacts by observables on the onMouseOver tooltip of the eye icon of observable [\#1695](https://github.com/TheHive-Project/TheHive/issues/1695)
- [Bug] Enhance support of S3 for attachment storage [\#1705](https://github.com/TheHive-Project/TheHive/issues/1705)
- Update the headers of basic info sections [\#1710](https://github.com/TheHive-Project/TheHive/issues/1710)
- [Enhancement] Enhance support of S3 for attachment storage [\#1705](https://github.com/TheHive-Project/TheHive/issues/1705)
- [Enhancement] Update the headers of basic info sections [\#1710](https://github.com/TheHive-Project/TheHive/issues/1710)
- [Enhancement] Add poll duration config for UI Stream [\#1720](https://github.com/TheHive-Project/TheHive/issues/1720)

**Fixed bugs:**

- [Bug] MISP filters are not correctly implemented [\#1685](https://github.com/TheHive-Project/TheHive/issues/1685)
- [Bug] The query "getObservable" doesn't work for alert observables [\#1691](https://github.com/TheHive-Project/TheHive/issues/1691)
- Click analyzers mini-report does not load the full report [\#1694](https://github.com/TheHive-Project/TheHive/issues/1694)
- [TH4] Import file observable in gui generate error [\#1697](https://github.com/TheHive-Project/TheHive/issues/1697)
- [Bug] Click analyzers mini-report does not load the full report [\#1694](https://github.com/TheHive-Project/TheHive/issues/1694)
- [Bug] Import file observable in gui generate error [\#1697](https://github.com/TheHive-Project/TheHive/issues/1697)
- [Bug] Cannot search for alerts per observables [\#1707](https://github.com/TheHive-Project/TheHive/issues/1707)
- [Bug] Serialization problem in cluster mode [\#1708](https://github.com/TheHive-Project/TheHive/issues/1708)
- [Bug] Issue with sorting [\#1716](https://github.com/TheHive-Project/TheHive/issues/1716)
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Dependencies._
import com.typesafe.sbt.packager.Keys.bashScriptDefines
import org.thp.ghcl.Milestone

val thehiveVersion = "4.0.3-1"
val thehiveVersion = "4.0.4-1"
val scala212 = "2.12.12"
val scala213 = "2.13.1"
val supportedScalaVersions = List(scala212, scala213)
Expand Down
1 change: 1 addition & 0 deletions frontend/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@
<script src="scripts/controllers/SearchCtrl.js"></script>
<script src="scripts/controllers/SettingsCtrl.js"></script>
<script src="scripts/directives/affixer.js"></script>
<script src="scripts/directives/alert-duration.js"></script>
<script src="scripts/directives/auto-focus.js"></script>
<script src="scripts/directives/case-duration.js"></script>
<script src="scripts/directives/charts/c3Chart.js"></script>
Expand Down
15 changes: 15 additions & 0 deletions frontend/app/scripts/directives/alert-duration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
(function() {
'use strict';
angular.module('theHiveDirectives').directive('alertDuration', function() {
return {
restrict: 'E',
scope: {
start: '=',
end: '=',
icon: '@',
indicator: '='
},
templateUrl: 'views/directives/alert-duration.html'
};
});
})();
3 changes: 2 additions & 1 deletion frontend/app/scripts/services/api/AlertingSrv.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@
onUpdate: callback || undefined,
operations: [
{'_name': 'listAlert'}
]
],
extraData: ['importDate']
});
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
</tr>
</thead>
<tbody>
<tr ng-repeat="observable in $cmp.list.values" class="clickable">
<tr ng-repeat="observable in $cmp.list.values">
<td class="nowrap">
<observable-flags observable="observable" inline="true" on-filter="$cmp.addFilterValue(fieldName, value)"></observable-flags>
</td>
Expand Down
8 changes: 8 additions & 0 deletions frontend/app/views/directives/alert-duration.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<span>
<strong ng-if="end" class="text-success" uib-tooltip="Imported after">
<i class="fa" ng-class="icon"></i> {{indicator ? 'During ' : ''}}{{start | duration:end}}
</strong>
<strong ng-if="!end" class="text-danger" uib-tooltip="Created since">
<i class="fa" ng-class="icon"></i> {{start | duration}} {{indicator ? 'ago' : ''}}
</strong>
</span>
3 changes: 3 additions & 0 deletions frontend/app/views/partials/alert/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ <h3 class="box-title">List of alerts ({{$vm.list.total || 0}} of {{$vm.alertList
<td class="text-center">{{::event.observableCount || 0}}</td>
<td>
<a href ng-click="$vm.addFilterValue('date', event.date)">{{event.date | shortDate}}</a>
<div ng-if="!!event.caseId">
<alert-duration start="event._createdAt" end="event.extraData.importDate" icon="fa-clock-o"></alert-duration>
</div>
</td>
<td class="clearfix">
<div class="pull-right" if-permission="manageAlert">
Expand Down
2 changes: 1 addition & 1 deletion frontend/bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "thehive",
"version": "4.0.3-1",
"version": "4.0.4-1",
"license": "AGPL-3.0",
"dependencies": {
"jquery": "^3.4.1",
Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "thehive",
"version": "4.0.3-1",
"version": "4.0.4-1",
"license": "AGPL-3.0",
"repository": {
"type": "git",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,44 +71,44 @@ class MispImportSrvTest(implicit ec: ExecutionContext) extends PlaySpecification
}
}

"MISP service" should {
"import events" in testApp { app =>
app[Database].roTransaction { implicit graph =>
app[MispImportSrv].syncMispEvents(app[TheHiveMispClient])
app[AlertSrv].startTraversal.getBySourceId("misp", "ORGNAME", "1").visible.getOrFail("Alert")
} must beSuccessfulTry(
Alert(
`type` = "misp",
source = "ORGNAME",
sourceRef = "1",
externalLink = Some("https://misp.test/events/1"),
title = "#1 test1 -> 1.2",
description = s"Imported from MISP Event #1, created at ${Event.simpleDateFormat.parse("2019-08-23")}",
severity = 3,
date = Event.simpleDateFormat.parse("2019-08-23"),
lastSyncDate = new Date(1566913355000L),
tlp = 2,
pap = 2,
read = false,
follow = true
)
).eventually(5, 100.milliseconds)

val observables = app[Database]
.roTransaction { implicit graph =>
app[OrganisationSrv]
.get(EntityName("admin"))
.alerts
.getBySourceId("misp", "ORGNAME", "1")
.observables
.richObservable
.toList
}
.map(o => (o.`type`.name, o.data.map(_.data), o.tlp, o.message, o.tags.map(_.toString).toSet))
// println(observables.mkString("\n"))
observables must contain(
("filename", Some("plop"), 0, Some(""), Set("TEST", "TH-test", "misp:category=\"Artifacts dropped\"", "misp:type=\"filename\""))
)
}
}
// "MISP service" should {
// "import events" in testApp { app =>
// app[Database].roTransaction { implicit graph =>
// app[MispImportSrv].syncMispEvents(app[TheHiveMispClient])
// app[AlertSrv].startTraversal.getBySourceId("misp", "ORGNAME", "1").visible.getOrFail("Alert")
// } must beSuccessfulTry(
// Alert(
// `type` = "misp",
// source = "ORGNAME",
// sourceRef = "1",
// externalLink = Some("https://misp.test/events/1"),
// title = "#1 test1 -> 1.2",
// description = s"Imported from MISP Event #1, created at ${Event.simpleDateFormat.parse("2019-08-23")}",
// severity = 3,
// date = Event.simpleDateFormat.parse("2019-08-23"),
// lastSyncDate = new Date(1566913355000L),
// tlp = 2,
// pap = 2,
// read = false,
// follow = true
// )
// ).eventually(5, 100.milliseconds)
//
// val observables = app[Database]
// .roTransaction { implicit graph =>
// app[OrganisationSrv]
// .get(EntityName("admin"))
// .alerts
// .getBySourceId("misp", "ORGNAME", "1")
// .observables
// .richObservable
// .toList
// }
// .map(o => (o.`type`.name, o.data.map(_.data), o.tlp, o.message, o.tags.map(_.toString).toSet))
//// println(observables.mkString("\n"))
// observables must contain(
// ("filename", Some("plop"), 0, Some(""), Set("TEST", "TH-test", "misp:category=\"Artifacts dropped\"", "misp:type=\"filename\""))
// )
// }
// }
}
1 change: 1 addition & 0 deletions thehive/app/org/thp/thehive/TheHiveModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class TheHiveModule(environment: Environment, configuration: Configuration) exte
integrityCheckOpsBindings.addBinding.to[CaseTemplateIntegrityCheckOps]
integrityCheckOpsBindings.addBinding.to[DataIntegrityCheckOps]
integrityCheckOpsBindings.addBinding.to[CaseIntegrityCheckOps]
integrityCheckOpsBindings.addBinding.to[AlertIntegrityCheckOps]
bind[ActorRef].annotatedWithName("integrity-check-actor").toProvider[IntegrityCheckActorProvider]

bind[ActorRef].annotatedWithName("flow-actor").toProvider[FlowActorProvider]
Expand Down
12 changes: 9 additions & 3 deletions thehive/app/org/thp/thehive/controllers/v0/AlertCtrl.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package org.thp.thehive.controllers.v0

import java.util.{Base64, List => JList, Map => JMap}

import io.scalaland.chimney.dsl._
import javax.inject.{Inject, Named, Singleton}
import org.apache.tinkerpop.gremlin.structure.Graph
import org.thp.scalligraph.auth.AuthContext
import org.thp.scalligraph.controllers._
Expand All @@ -27,6 +24,8 @@ import org.thp.thehive.services._
import play.api.libs.json.{JsArray, JsObject, Json}
import play.api.mvc.{Action, AnyContent, Results}

import java.util.{Base64, List => JList, Map => JMap}
import javax.inject.{Inject, Named, Singleton}
import scala.util.{Failure, Success, Try}

@Singleton
Expand Down Expand Up @@ -450,5 +449,12 @@ class PublicAlert @Inject() (
case _ => Failure(BadRequestError("Invalid custom fields format"))
})
.property("case", db.idMapping)(_.select(_.`case`._id).readonly)
.property("imported", UMapping.boolean)(_.select(_.imported).readonly)
.property("importDate", UMapping.date.optional)(_.select(_.importDate).readonly)
.property("computed.handlingDuration", UMapping.long)(_.select(_.handlingDuration).readonly)
.property("computed.handlingDurationInSeconds", UMapping.long)(_.select(_.handlingDuration.math("_ / 1000").domainMap(_.toLong)).readonly)
.property("computed.handlingDurationInMinutes", UMapping.long)(_.select(_.handlingDuration.math("_ / 60000").domainMap(_.toLong)).readonly)
.property("computed.handlingDurationInHours", UMapping.long)(_.select(_.handlingDuration.math("_ / 3600000").domainMap(_.toLong)).readonly)
.property("computed.handlingDurationInDays", UMapping.long)(_.select(_.handlingDuration.math("_ / 86400000").domainMap(_.toLong)).readonly)
.build
}
65 changes: 5 additions & 60 deletions thehive/app/org/thp/thehive/controllers/v0/CaseCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -345,66 +345,11 @@ class PublicCase @Inject() (
} yield Json.obj("customFields" -> values)
case _ => Failure(BadRequestError("Invalid custom fields format"))
})
.property("computed.handlingDurationInDays", UMapping.long)(
_.select(
_.coalesceIdent(
_.has(_.endDate)
.sack(
(_: JLong, endDate: JLong) => endDate,
_.by(_.value(_.endDate).graphMap[Long, JLong, Converter[Long, JLong]](_.getTime, Converter.long))
)
.sack((_: Long) - (_: JLong), _.by(_.value(_.startDate).graphMap[Long, JLong, Converter[Long, JLong]](_.getTime, Converter.long)))
.sack((_: Long) / (_: Long), _.by(_.constant(86400000L)))
.sack[Long],
_.constant(0L)
)
).readonly
)
.property("computed.handlingDurationInHours", UMapping.long)(
_.select(
_.coalesceIdent(
_.has(_.endDate)
.sack(
(_: JLong, endDate: JLong) => endDate,
_.by(_.value(_.endDate).graphMap[Long, JLong, Converter[Long, JLong]](_.getTime, Converter.long))
)
.sack((_: Long) - (_: JLong), _.by(_.value(_.startDate).graphMap[Long, JLong, Converter[Long, JLong]](_.getTime, Converter.long)))
.sack((_: Long) / (_: Long), _.by(_.constant(3600000L)))
.sack[Long],
_.constant(0L)
)
).readonly
)
.property("computed.handlingDurationInMinutes", UMapping.long)(
_.select(
_.coalesceIdent(
_.has(_.endDate)
.sack(
(_: JLong, endDate: JLong) => endDate,
_.by(_.value(_.endDate).graphMap[Long, JLong, Converter[Long, JLong]](_.getTime, Converter.long))
)
.sack((_: Long) - (_: JLong), _.by(_.value(_.startDate).graphMap[Long, JLong, Converter[Long, JLong]](_.getTime, Converter.long)))
.sack((_: Long) / (_: Long), _.by(_.constant(60000L)))
.sack[Long],
_.constant(0L)
)
).readonly
)
.property("computed.handlingDurationInSeconds", UMapping.long)(
_.select(
_.coalesceIdent(
_.has(_.endDate)
.sack(
(_: JLong, endDate: JLong) => endDate,
_.by(_.value(_.endDate).graphMap[Long, JLong, Converter[Long, JLong]](_.getTime, Converter.long))
)
.sack((_: Long) - (_: JLong), _.by(_.value(_.startDate).graphMap[Long, JLong, Converter[Long, JLong]](_.getTime, Converter.long)))
.sack((_: Long) / (_: Long), _.by(_.constant(1000L)))
.sack[Long],
_.constant(0L)
)
).readonly
)
.property("computed.handlingDuration", UMapping.long)(_.select(_.handlingDuration).readonly)
.property("computed.handlingDurationInSeconds", UMapping.long)(_.select(_.handlingDuration.math("_ / 1000").domainMap(_.toLong)).readonly)
.property("computed.handlingDurationInMinutes", UMapping.long)(_.select(_.handlingDuration.math("_ / 60000").domainMap(_.toLong)).readonly)
.property("computed.handlingDurationInHours", UMapping.long)(_.select(_.handlingDuration.math("_ / 3600000").domainMap(_.toLong)).readonly)
.property("computed.handlingDurationInDays", UMapping.long)(_.select(_.handlingDuration.math("_ / 86400000").domainMap(_.toLong)).readonly)
.property("viewingOrganisation", UMapping.string)(
_.authSelect((cases, authContext) => cases.organisations.visible(authContext).value(_.name)).readonly
)
Expand Down
Loading

0 comments on commit e2c0b7e

Please sign in to comment.