Skip to content

Commit f32f78d

Browse files
committed
#237 Fix artifact ID computation if attachmentInputValue is provided
1 parent 4622826 commit f32f78d

File tree

2 files changed

+29
-14
lines changed

2 files changed

+29
-14
lines changed

thehive-backend/app/models/Artifact.scala

+25-12
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,26 @@ package models
33
import java.util.Date
44
import javax.inject.{ Inject, Provider, Singleton }
55

6+
import akka.{ Done, NotUsed }
7+
68
import scala.concurrent.{ ExecutionContext, Future }
79
import scala.language.postfixOps
8-
import akka.stream.Materializer
9-
import play.api.libs.json.{ JsNull, JsObject, JsString, JsValue, JsArray }
10+
import akka.stream.{ IOResult, Materializer }
11+
import play.api.libs.json.{ JsArray, JsNull, JsObject, JsString, JsValue }
1012
import play.api.libs.json.JsLookupResult.jsLookupResultToJsLookup
1113
import play.api.libs.json.JsValue.jsValueToJsLookup
1214
import play.api.libs.json.Json
1315
import play.api.libs.json.Json.toJsFieldJsValueWrapper
14-
import org.elastic4play.BadRequestError
16+
import org.elastic4play.{ BadRequestError, InternalError }
1517
import org.elastic4play.models.{ AttributeDef, BaseEntity, ChildModelDef, EntityDef, HiveEnumeration, AttributeFormat F, AttributeOption O }
16-
import org.elastic4play.services.{ Attachment, DBLists }
18+
import org.elastic4play.services.{ Attachment, AttachmentSrv, DBLists }
1719
import org.elastic4play.utils.MultiHash
1820
import models.JsonFormat.artifactStatusFormat
21+
import play.api.Logger
1922
import services.{ ArtifactSrv, AuditedModel }
2023

24+
import scala.util.Success
25+
2126
object ArtifactStatus extends Enumeration with HiveEnumeration {
2227
type Type = Value
2328
val Ok, Deleted = Value
@@ -42,9 +47,11 @@ trait ArtifactAttributes { _: AttributeDef ⇒
4247
class ArtifactModel @Inject() (
4348
caseModel: CaseModel,
4449
val dblists: DBLists,
50+
attachmentSrv: AttachmentSrv,
4551
artifactSrv: Provider[ArtifactSrv],
4652
implicit val mat: Materializer,
4753
implicit val ec: ExecutionContext) extends ChildModelDef[ArtifactModel, Artifact, CaseModel, Case](caseModel, "case_artifact") with ArtifactAttributes with AuditedModel {
54+
private[ArtifactModel] lazy val logger = Logger(getClass)
4855
override val removeAttribute: JsObject = Json.obj("status" ArtifactStatus.Deleted)
4956

5057
override def apply(attributes: JsObject): Artifact = {
@@ -59,7 +66,7 @@ class ArtifactModel @Inject() (
5966
throw BadRequestError(s"Artifact must contain a message or on ore more tags")
6067
if (keys.contains("data") == keys.contains("attachment"))
6168
throw BadRequestError(s"Artifact must contain data or attachment (but not both)")
62-
computeId(parent, attrs).map { id
69+
computeId(parent.getOrElse(throw InternalError(s"artifact $attrs has no parent")), attrs).map { id
6370
attrs + ("_id" JsString(id))
6471
}
6572
}
@@ -85,17 +92,23 @@ class ArtifactModel @Inject() (
8592
Future.successful(updateAttrs)
8693
}
8794
}
88-
def computeId(parent: Option[BaseEntity], attrs: JsObject): Future[String] = {
95+
def computeId(parent: BaseEntity, attrs: JsObject): Future[String] = {
8996
// in order to make sure that there is no duplicated artifact, calculate its id from its content (dataType, data, attachment and parent)
9097
val mm = new MultiHash("MD5")
9198
mm.addValue((attrs \ "data").asOpt[JsValue].getOrElse(JsNull))
9299
mm.addValue((attrs \ "dataType").asOpt[JsValue].getOrElse(JsNull))
93-
(attrs \ "attachment" \ "filepath").asOpt[String]
94-
.fold(Future.successful(()))(file mm.addFile(file))
95-
.map { _
96-
mm.addValue(JsString(parent.fold("")(_.id)))
97-
mm.digest.toString
98-
}
100+
for {
101+
IOResult(_, done) (attrs \ "attachment" \ "filepath").asOpt[String]
102+
.fold(Future.successful(IOResult(0, Success(Done))))(file mm.addFile(file))
103+
_ Future.fromTry(done)
104+
_ (attrs \ "attachment" \ "id").asOpt[String]
105+
.fold(Future.successful(NotUsed: NotUsed)) { fileId
106+
mm.addFile(attachmentSrv.source(fileId))
107+
}
108+
} yield {
109+
mm.addValue(JsString(parent.id))
110+
mm.digest.toString
111+
}
99112
}
100113

101114
override def getStats(entity: BaseEntity): Future[JsObject] = {

thehive-backend/app/services/ArtifactSrv.scala

+4-2
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,15 @@ class ArtifactSrv @Inject() (
3636

3737
def create(caze: Case, fields: Fields)(implicit authContext: AuthContext): Future[Artifact] = {
3838
createSrv[ArtifactModel, Artifact, Case](artifactModel, caze, fields)
39-
.fallbackTo(updateIfDeleted(caze, fields)) // maybe the artifact already exists. If so, search it and update it
39+
.recoverWith {
40+
case error updateIfDeleted(caze, fields) // maybe the artifact already exists. If so, search it and update it
41+
}
4042
}
4143

4244
private def updateIfDeleted(caze: Case, fields: Fields)(implicit authContext: AuthContext): Future[Artifact] = {
4345
fieldsSrv.parse(fields, artifactModel).toFuture.flatMap { attrs
4446
val updatedArtifact = for {
45-
id artifactModel.computeId(Some(caze), attrs)
47+
id artifactModel.computeId(caze, attrs)
4648
artifact getSrv[ArtifactModel, Artifact](artifactModel, id)
4749
if artifact.status() == ArtifactStatus.Deleted
4850
updatedArtifact updateSrv[ArtifactModel, Artifact](artifactModel, artifact.id, fields.unset("data").unset("dataType").unset("attachment").set("status", "Ok"))

0 commit comments

Comments
 (0)