Skip to content

Commit

Permalink
WIP merge should work, tests failed
Browse files Browse the repository at this point in the history
  • Loading branch information
rriclet committed Feb 25, 2021
1 parent 56d2059 commit b9a5788
Show file tree
Hide file tree
Showing 15 changed files with 186 additions and 121 deletions.
58 changes: 22 additions & 36 deletions thehive/app/org/thp/thehive/services/CaseSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class CaseSrv @Inject() (
val caseUserSrv = new EdgeSrv[CaseUser, Case, User]
val caseCustomFieldSrv = new EdgeSrv[CaseCustomField, Case, CustomField]
val caseCaseTemplateSrv = new EdgeSrv[CaseCaseTemplate, Case, CaseTemplate]
val caseProcedureSrv = new EdgeSrv[CaseProcedure, Case, Procedure]
val shareCaseSrv = new EdgeSrv[ShareCase, Share, Case]
val mergedFromSrv = new EdgeSrv[MergedFrom, Case, Case]

override def createEntity(e: Case)(implicit graph: Graph, authContext: AuthContext): Try[Case with Entity] =
Expand Down Expand Up @@ -315,44 +317,28 @@ class CaseSrv @Inject() (
user <- userSrv.get(EntityIdOrName(authContext.userId)).getOrFail("User")
orga <- organisationSrv.get(authContext.organisation).getOrFail("Organisation")
richCase <- create(mergedCase, Some(user), orga, tags.toSet, Seq(), None, Seq())
_ <- cases.toTry(c =>
get(c)
.shares
.toList
.toTry(s => shareCaseSrv.create(ShareCase(), s, richCase.`case`))
)
_ <- cases.toTry(c =>
get(c)
.procedure
.toList
.toTry(p => caseProcedureSrv.create(CaseProcedure(), richCase.`case`, p))
)
_ <- cases.toTry(c =>
get(c)
.richCustomFields
.toList
.toTry { c =>
caseCustomFieldSrv.create(CaseCustomField(), richCase.`case`, c.customField)
}
)
_ = cases.map(remove(_))
// TODO customFields: Seq[RichCustomField],
// TODO ShareCase link
// TODO Procedure link
// TODO tasks
// TODO cascadeRemove cases
// TODO link to share(s) of original cases
} yield richCase
// {
// caseUserSrv.create(CaseUser(), mergedCase, user)
// caseOrganisationSrv.create(CaseOrganisation(), mergedCase, organisation)
// cases
// .map(get)
// .flatMap(_.customFields().toList
// .groupBy(_.name)
// .foreach {
// case (name, l) =>
// val values = l.collect { case cfwv: CustomFieldWithValue if cfwv.value.isDefined => cfwv.value.get }
// val cf = customFieldSrv.getOrFail(name)
// val caseCustomField =
// if (values.size == 1) cf.`type`.setValue(CaseCustomField(), values.head)
// else CaseCustomField()
// caseCustomFieldSrv.create(caseCustomField, mergedCase, cf)
// }
//
// cases.foreach(mergedFromSrv.create(MergedFrom(), mergedCase, _))
//
// cases
// .map(get)
// .flatMap(_.tasks.toList
// .foreach(task => caseTaskSrv.create(CaseTask(), task, mergedCase))
//
// cases
// .map(get)
// .flatMap(_.observables.toList
// .foreach(observable => observableCaseSrv.create(ObservableCase(), observable, mergedCase))
//
// get(mergedCase).richCase.head
}
}

Expand Down
15 changes: 6 additions & 9 deletions thehive/test/org/thp/thehive/controllers/v0/CaseCtrlTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ case class TestCase(
)

object TestCase {

def apply(outputCase: OutputCase): TestCase =
outputCase.into[TestCase].transform
}
Expand Down Expand Up @@ -327,7 +326,7 @@ class CaseCtrlTest extends PlaySpecification with TestAppBuilder {
status(result) must_=== 200
val resultCase = contentAsJson(result)

(resultCase \ "count").asOpt[Int] must beSome(3)
(resultCase \ "count").asOpt[Int] must beSome(7)
(resultCase \ "testNamespace:testPredicate=\"t1\"" \ "count").asOpt[Int] must beSome(2)
(resultCase \ "testNamespace:testPredicate=\"t2\"" \ "count").asOpt[Int] must beSome(1)
(resultCase \ "testNamespace:testPredicate=\"t3\"" \ "count").asOpt[Int] must beSome(1)
Expand Down Expand Up @@ -370,14 +369,13 @@ class CaseCtrlTest extends PlaySpecification with TestAppBuilder {
status(case21) must equalTo(200).updateMessage(s => s"$s\n${contentAsString(case21)}")
val output21 = contentAsJson(case21).as[OutputCase]

val request = FakeRequest("GET", "/api/v1/case/21/_merge/22")
val request = FakeRequest("GET", "/api/v0/case/21/_merge/22")
.withHeaders("user" -> "[email protected]")

val result = app[CaseCtrl].merge("21", "22")(request)
status(result) must beEqualTo(201).updateMessage(s => s"$s\n${contentAsString(result)}")

val outputCase = contentAsJson(result).as[OutputCase]
// TODO Tags / CustomFields / ResolutionStatus / ImpactStatus / Alerts / Share / CaseTemplate ?

// Merge result
TestCase(outputCase) must equalTo(
Expand Down Expand Up @@ -405,17 +403,16 @@ class CaseCtrlTest extends PlaySpecification with TestAppBuilder {
}

"merge two cases error, not same organisation" in testApp { app =>
val request = FakeRequest("GET", "/api/v1/case/21/_merge/24")
val request = FakeRequest("GET", "/api/v0/case/21/_merge/24")
.withHeaders("user" -> "[email protected]")

val result = app[CaseCtrl].merge("21", "24")(request)
status(result) must beEqualTo(400).updateMessage(s => s"$s\n${contentAsString(result)}")
(contentAsJson(result) \ "type").as[String] must beEqualTo("BadRequest")
(contentAsJson(result) \ "message").as[String] must contain("different organisations")
// User shouldn't be able to see others cases, resulting in 404
status(result) must beEqualTo(404).updateMessage(s => s"$s\n${contentAsString(result)}")
}

"merge two cases error, not same profile" in testApp { app =>
val request = FakeRequest("GET", "/api/v1/case/21/_merge/25")
val request = FakeRequest("GET", "/api/v0/case/21/_merge/25")
.withHeaders("user" -> "[email protected]")

val result = app[CaseCtrl].merge("21", "25")(request)
Expand Down
53 changes: 20 additions & 33 deletions thehive/test/org/thp/thehive/controllers/v1/CaseCtrlTest.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package org.thp.thehive.controllers.v1

import io.scalaland.chimney.dsl.TransformerOps
import org.thp.thehive.TestAppBuilder
import org.thp.thehive.dto.v1.{InputCase, OutputCase, OutputCustomFieldValue}
import play.api.libs.json.{JsNull, JsString, JsValue, Json}
import play.api.test.{FakeRequest, PlaySpecification}

import java.util.Date

case class TestCustomFieldValue(name: String, description: String, `type`: String, value: JsValue, order: Int)

object TestCustomFieldValue {
def apply(outputCustomFieldValue: OutputCustomFieldValue): TestCustomFieldValue =
outputCustomFieldValue.into[TestCustomFieldValue].transform
}

case class TestCase(
title: String,
description: String,
Expand All @@ -19,40 +27,19 @@ case class TestCase(
pap: Int,
status: String,
summary: Option[String] = None,
impactStatus: Option[String] = None,
resolutionStatus: Option[String] = None,
user: Option[String],
customFields: Seq[TestCustomFieldValue] = Seq.empty
)

object TestCase {
def apply(outputCase: OutputCase): TestCase =
TestCase(
outputCase.title,
outputCase.description,
outputCase.severity,
outputCase.startDate,
outputCase.endDate,
outputCase.tags,
outputCase.flag,
outputCase.tlp,
outputCase.pap,
outputCase.status,
outputCase.summary,
outputCase.assignee,
outputCase.customFields.map(TestCustomFieldValue.apply).sortBy(_.order)
)
}

case class TestCustomFieldValue(name: String, description: String, `type`: String, value: JsValue, order: Int)

object TestCustomFieldValue {
def apply(outputCustomFieldValue: OutputCustomFieldValue): TestCustomFieldValue =
TestCustomFieldValue(
outputCustomFieldValue.name,
outputCustomFieldValue.description,
outputCustomFieldValue.`type`,
outputCustomFieldValue.value,
outputCustomFieldValue.order
)
outputCase
.into[TestCase]
.withFieldRenamed(_.assignee, _.user)
.withFieldComputed(_.customFields, _.customFields.map(TestCustomFieldValue.apply).sortBy(_.order))
.transform
}

class CaseCtrlTest extends PlaySpecification with TestAppBuilder {
Expand Down Expand Up @@ -211,7 +198,6 @@ class CaseCtrlTest extends PlaySpecification with TestAppBuilder {
status(result) must beEqualTo(201).updateMessage(s => s"$s\n${contentAsString(result)}")

val outputCase = contentAsJson(result).as[OutputCase]
// TODO Tags / CustomFields / ResolutionStatus / ImpactStatus / Alerts / Share / CaseTemplate ?

// Merge result
TestCase(outputCase) must equalTo(
Expand All @@ -221,12 +207,14 @@ class CaseCtrlTest extends PlaySpecification with TestAppBuilder {
severity = 3,
startDate = output21.startDate,
endDate = output21.endDate,
Set.empty,
Set("toMerge:pred1=\"value1\"", "toMerge:pred2=\"value2\""),
flag = true,
tlp = 4,
pap = 3,
status = "Open",
None,
None,
None,
Some("[email protected]"),
Seq()
)
Expand All @@ -246,9 +234,8 @@ class CaseCtrlTest extends PlaySpecification with TestAppBuilder {
.withHeaders("user" -> "[email protected]")

val result = app[CaseCtrl].merge("21,24")(request)
status(result) must beEqualTo(400).updateMessage(s => s"$s\n${contentAsString(result)}")
(contentAsJson(result) \ "type").as[String] must beEqualTo("BadRequest")
(contentAsJson(result) \ "message").as[String] must contain("different organisations")
// User shouldn't be able to see others cases, resulting in 404
status(result) must beEqualTo(404).updateMessage(s => s"$s\n${contentAsString(result)}")
}

"merge two cases error, not same profile" in testApp { app =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.thp.thehive.controllers.v1

import io.scalaland.chimney.dsl.TransformerOps
import org.thp.scalligraph.controllers.FakeTemporaryFile
import org.thp.thehive.TestAppBuilder
import org.thp.thehive.dto.v1._
Expand All @@ -18,12 +19,10 @@ case class TestTaxonomy(

object TestTaxonomy {
def apply(outputTaxonomy: OutputTaxonomy): TestTaxonomy =
TestTaxonomy(
outputTaxonomy.namespace,
outputTaxonomy.description,
outputTaxonomy.version,
outputTaxonomy.tags.toSet
)
outputTaxonomy
.into[TestTaxonomy]
.withFieldComputed(_.tags, _.tags.toSet)
.transform
}

class TaxonomyCtrlTest extends PlaySpecification with TestAppBuilder {
Expand Down
69 changes: 38 additions & 31 deletions thehive/test/org/thp/thehive/services/CaseSrvTest.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.thp.thehive.services

import java.util.Date

import org.specs2.matcher.Matcher
import org.thp.scalligraph.auth.AuthContext
import org.thp.scalligraph.controllers.FPathElem
Expand All @@ -16,11 +15,12 @@ import org.thp.thehive.services.ObservableOps._
import play.api.libs.json.Json
import play.api.test.PlaySpecification

import scala.util.Success
import scala.util.{Failure, Success}

class CaseSrvTest extends PlaySpecification with TestAppBuilder {
implicit val authContext: AuthContext =
DummyUserSrv(userId = "[email protected]", organisation = "cert", permissions = Profile.analyst.permissions).authContext

"case service" should {

"list all cases" in testApp { app =>
Expand Down Expand Up @@ -142,34 +142,6 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder {
}
}

"merge two cases" in testApp { app =>
pending
// app[Database].transaction { implicit graph =>
// Seq("#2", "#3").toTry(app[CaseSrv].getOrFail) must beSuccessfulTry.which { cases: Seq[Case with Entity] =>
// val mergedCase = app[CaseSrv].merge(cases)(graph, dummyUserSrv.getSystemAuthContext)
//
// mergedCase.title must_=== "case#2 / case#3"
// mergedCase.description must_=== "description of case #2\n\ndescription of case #3"
// mergedCase.severity must_=== 2
// mergedCase.startDate must_=== new Date(1531667370000L)
// mergedCase.endDate must beNone
// mergedCase.tags must_=== Nil
// mergedCase.flag must_=== false
// mergedCase.tlp must_=== 2
// mergedCase.pap must_=== 2
// mergedCase.status must_=== CaseStatus.Open
// mergedCase.summary must beNone
// mergedCase.impactStatus must beNone
// mergedCase.user must beSome("test")
// mergedCase.customFields.map(f => (f.name, f.typeName, f.value)) must contain(
// allOf[(String, String, Option[Any])](
// ("boolean1", "boolean", Some(true)),
// ("string1", "string", Some("string1 custom field"))
// ))
// }
// }
}

"add custom field with wrong type" in testApp { app =>
app[Database].transaction { implicit graph =>
app[CaseSrv].getOrFail(EntityName("3")) must beSuccessfulTry.which { `case`: Case with Entity =>
Expand Down Expand Up @@ -207,7 +179,7 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder {

"get correct next case number" in testApp { app =>
app[Database].roTransaction { implicit graph =>
app[CaseSrv].nextCaseNumber shouldEqual 6
app[CaseSrv].nextCaseNumber shouldEqual 26
}
}

Expand Down Expand Up @@ -419,5 +391,40 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder {
app[Database].roTransaction(implicit graph => app[CaseSrv].get(EntityName("1")).linkedCases must not(beEmpty))
}
}

"merge cases" in testApp { app =>
app[Database].tryTransaction { implicit graph =>
val case21 = app[CaseSrv].get(EntityName("21"))
val case22 = app[CaseSrv].get(EntityName("22"))
val case23 = app[CaseSrv].get(EntityName("23"))
// Tasks
case21.clone().tasks.toSeq.size mustEqual 2
case22.clone().tasks.toSeq.size mustEqual 0
case23.clone().tasks.toSeq.size mustEqual 1
// Observables
case21.clone().observables.toSeq.size mustEqual 1
case22.clone().observables.toSeq.size mustEqual 0
case23.clone().observables.toSeq.size mustEqual 2
// Procedures
case21.clone().procedure.toSeq.size mustEqual 1
case22.clone().procedure.toSeq.size mustEqual 2
case23.clone().procedure.toSeq.size mustEqual 0
// TODO CustomFields

for {
c21 <- case21.clone().getOrFail("Case")
c22 <- case22.clone().getOrFail("Case")
c23 <- case23.clone().getOrFail("Case")
newCase <- app[CaseSrv].merge(Seq(c21, c22, c23))
} yield newCase
} must beASuccessfulTry.which { richCase =>
app[Database].roTransaction { implicit graph =>
app[CaseSrv].get(EntityName(richCase.number.toString)).tasks.toSeq.size mustEqual 3
app[CaseSrv].get(EntityName(richCase.number.toString)).observables.toSeq.size mustEqual 3
app[CaseSrv].get(EntityName(richCase.number.toString)).procedure.toSeq.size mustEqual 3
}
}
}

}
}
5 changes: 4 additions & 1 deletion thehive/test/resources/data/CaseProcedure.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
[
{"from": "case1", "to": "testProcedure1"},
{"from": "case1", "to": "testProcedure2"}
{"from": "case1", "to": "testProcedure2"},
{"from": "caseMerge21", "to": "mergeProcedure211"},
{"from": "caseMerge22", "to": "mergeProcedure221"},
{"from": "caseMerge22", "to": "mergeProcedure222"}
]
4 changes: 3 additions & 1 deletion thehive/test/resources/data/CaseTag.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
{"from": "case2", "to": "tagt1"},
{"from": "case2", "to": "tagt2"},
{"from": "case1", "to": "tagt1"},
{"from": "case1", "to": "tagt3"}
{"from": "case1", "to": "tagt3"},
{"from": "caseMerge21", "to": "tagMerge1"},
{"from": "caseMerge22", "to": "tagMerge2"}
]
Loading

0 comments on commit b9a5788

Please sign in to comment.