Skip to content

Commit

Permalink
#1731 Fix tags in case template during migration
Browse files Browse the repository at this point in the history
  • Loading branch information
To-om committed Mar 9, 2021
1 parent ec1c646 commit 7c1922f
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ case class InputCaseTemplate(
metaData: MetaData,
caseTemplate: CaseTemplate,
organisation: String,
tags: Set[String],
customFields: Seq[InputCustomFieldValue]
)
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,6 @@ trait Conversion {
summary = summary
),
mainOrganisation,
tags,
(metricsValue ++ customFieldsValue).toSeq
)
}
Expand Down
58 changes: 41 additions & 17 deletions migration/src/main/scala/org/thp/thehive/migration/th4/Output.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package org.thp.thehive.migration.th4
import akka.actor.ActorSystem
import akka.actor.typed.Scheduler
import akka.stream.Materializer
import com.google.inject.Guice
import com.google.inject.{Guice, Injector => GInjector}
import net.codingwell.scalaguice.{ScalaModule, ScalaMultibinder}
import org.apache.tinkerpop.gremlin.process.traversal.P
import org.thp.scalligraph._
Expand All @@ -21,7 +21,6 @@ import org.thp.thehive.migration.dto._
import org.thp.thehive.models._
import org.thp.thehive.services._
import org.thp.thehive.{migration, ClusterSetup}
import play.api.cache.SyncCacheApi
import play.api.cache.ehcache.EhCacheModule
import play.api.inject.guice.GuiceInjector
import play.api.inject.{ApplicationLifecycle, DefaultApplicationLifecycle, Injector}
Expand All @@ -35,7 +34,7 @@ import scala.util.{Failure, Success, Try}

object Output {

private def buildApp(configuration: Configuration)(implicit actorSystem: ActorSystem) =
private def buildApp(configuration: Configuration)(implicit actorSystem: ActorSystem): GInjector =
Guice
.createInjector(
(play.api.inject.guice.GuiceableModule.guiceable(new EhCacheModule).guiced(Environment.simple(), configuration, Set.empty) :+
Expand Down Expand Up @@ -109,8 +108,7 @@ class Output @Inject() (
resolutionStatusSrv: ResolutionStatusSrv,
jobSrv: JobSrv,
actionSrv: ActionSrv,
db: Database,
cache: SyncCacheApi
db: Database
) extends migration.Output {
lazy val logger: Logger = Logger(getClass)
val defaultUserDomain: String = userSrv
Expand All @@ -129,6 +127,7 @@ class Output @Inject() (
private var caseTemplates: Map[String, CaseTemplate with Entity] = Map.empty
private var caseNumbers: Set[Int] = Set.empty
private var alerts: Set[(String, String, String)] = Set.empty
private var tags: Map[String, Tag with Entity] = Map.empty

private def retrieveExistingData(): Unit = {
val profilesBuilder = Map.newBuilder[String, Profile with Entity]
Expand All @@ -141,6 +140,7 @@ class Output @Inject() (
val caseTemplatesBuilder = Map.newBuilder[String, CaseTemplate with Entity]
val caseNumbersBuilder = Set.newBuilder[Int]
val alertsBuilder = Set.newBuilder[(String, String, String)]
val tagsBuilder = Map.newBuilder[String, Tag with Entity]

db.roTransaction { implicit graph =>
graph
Expand All @@ -157,7 +157,8 @@ class Output @Inject() (
"CustomField",
"CaseTemplate",
"Case",
"Alert"
"Alert",
"Tag"
)
)
.toIterator
Expand Down Expand Up @@ -194,6 +195,12 @@ class Output @Inject() (
val source = UMapping.string.getProperty(vertex, "source")
val sourceRef = UMapping.string.getProperty(vertex, "sourceRef")
alertsBuilder += ((`type`, source, sourceRef))
case ("Tag", vertex) =>
val tag = tagSrv.model.converter(vertex)
if (tag.namespace.startsWith(s"_freetags_"))
tagsBuilder += (s"${tag.namespace.drop(10)}-${tag.predicate}" -> tag)
else
tagsBuilder += (tag.toString -> tag)
case _ =>
}
}
Expand All @@ -207,6 +214,7 @@ class Output @Inject() (
caseTemplates = caseTemplatesBuilder.result()
caseNumbers = caseNumbersBuilder.result()
alerts = alertsBuilder.result()
tags = tagsBuilder.result()
if (
profiles.nonEmpty ||
organisations.nonEmpty ||
Expand All @@ -217,7 +225,8 @@ class Output @Inject() (
customFields.nonEmpty ||
caseTemplates.nonEmpty ||
caseNumbers.nonEmpty ||
alerts.nonEmpty
alerts.nonEmpty ||
tags.nonEmpty
)
logger.info(s"""Already migrated:
| ${profiles.size} profiles
Expand All @@ -229,7 +238,8 @@ class Output @Inject() (
| ${customFields.size} customFields
| ${caseTemplates.size} caseTemplates
| ${caseNumbers.size} caseNumbers
| ${alerts.size} alerts""".stripMargin)
| ${alerts.size} alerts
| ${tags.size} tags""".stripMargin)
}

def startMigration(): Try[Unit] =
Expand Down Expand Up @@ -282,9 +292,15 @@ class Output @Inject() (
}

def getTag(tagName: String, organisationId: String)(implicit graph: Graph, authContext: AuthContext): Try[Tag with Entity] =
cache.getOrElseUpdate(s"tag-$tagName")(
tagSrv.createEntity(Tag(s"_freetags_$organisationId", tagName, None, None, tagSrv.freeTagColour))
)
tags
.get(tagName)
.orElse(tags.get(s"$organisationId-$tagName"))
.fold[Try[Tag with Entity]] {
tagSrv.createEntity(Tag(s"_freetags_$organisationId", tagName, None, None, tagSrv.freeTagColour)).map { tag =>
tags += (tagName -> tag)
tag
}
}(Success.apply)

override def organisationExists(inputOrganisation: InputOrganisation): Boolean = organisations.contains(inputOrganisation.organisation.name)

Expand Down Expand Up @@ -462,19 +478,27 @@ class Output @Inject() (
authTransaction(inputCaseTemplate.metaData.createdBy) { implicit graph => implicit authContext =>
logger.debug(s"Create case template ${inputCaseTemplate.caseTemplate.name}")
for {
organisation <- getOrganisation(inputCaseTemplate.organisation)
richCaseTemplate <- caseTemplateSrv.create(inputCaseTemplate.caseTemplate, organisation, Nil, Nil)
_ = updateMetaData(richCaseTemplate.caseTemplate, inputCaseTemplate.metaData)
organisation <- getOrganisation(inputCaseTemplate.organisation)
createdCaseTemplate <- caseTemplateSrv.createEntity(inputCaseTemplate.caseTemplate)
_ <- caseTemplateSrv.caseTemplateOrganisationSrv.create(CaseTemplateOrganisation(), createdCaseTemplate, organisation)
_ <-
inputCaseTemplate
.caseTemplate
.tags
.toTry(
getTag(_, organisation._id.value).flatMap(t => caseTemplateSrv.caseTemplateTagSrv.create(CaseTemplateTag(), createdCaseTemplate, t))
)
_ = updateMetaData(createdCaseTemplate, inputCaseTemplate.metaData)
_ = inputCaseTemplate.customFields.foreach {
case InputCustomFieldValue(name, value, order) =>
(for {
cf <- getCustomField(name)
ccf <- CustomFieldType.map(cf.`type`).setValue(CaseTemplateCustomField(order = order), value)
_ <- caseTemplateSrv.caseTemplateCustomFieldSrv.create(ccf, richCaseTemplate.caseTemplate, cf)
_ <- caseTemplateSrv.caseTemplateCustomFieldSrv.create(ccf, createdCaseTemplate, cf)
} yield ()).logFailure(s"Unable to set custom field $name=${value.getOrElse("<not set>")}")
}
_ = caseTemplates += (inputCaseTemplate.caseTemplate.name -> richCaseTemplate.caseTemplate)
} yield IdMapping(inputCaseTemplate.metaData.id, richCaseTemplate._id)
_ = caseTemplates += (inputCaseTemplate.caseTemplate.name -> createdCaseTemplate)
} yield IdMapping(inputCaseTemplate.metaData.id, createdCaseTemplate._id)
}

override def createCaseTemplateTask(caseTemplateId: EntityId, inputTask: InputTask): Try[IdMapping] =
Expand Down

0 comments on commit 7c1922f

Please sign in to comment.