Skip to content

Commit

Permalink
#1552 Fixed order when importing customFields
Browse files Browse the repository at this point in the history
  • Loading branch information
rriclet authored and To-om committed Nov 6, 2020
1 parent 4c57fec commit 0cdc56d
Show file tree
Hide file tree
Showing 10 changed files with 33 additions and 28 deletions.
15 changes: 8 additions & 7 deletions dto/src/main/scala/org/thp/thehive/dto/v0/CustomFieldValue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,21 @@ object InputCustomFieldValue {
case (_, FObject(fields)) =>
fields
.toSeq
.zipWithIndex
.validatedBy {
case (name, FString(value)) => Good(InputCustomFieldValue(name, Some(value), None))
case (name, FNumber(value)) => Good(InputCustomFieldValue(name, Some(value), None))
case (name, FBoolean(value)) => Good(InputCustomFieldValue(name, Some(value), None))
case (name, FAny(value :: _)) => Good(InputCustomFieldValue(name, Some(value), None))
case (name, FNull) => Good(InputCustomFieldValue(name, None, None))
case (name, obj: FObject) =>
case ((name, FString(value)), i) => Good(InputCustomFieldValue(name, Some(value), Some(i)))
case ((name, FNumber(value)), i) => Good(InputCustomFieldValue(name, Some(value), Some(i)))
case ((name, FBoolean(value)), i) => Good(InputCustomFieldValue(name, Some(value), Some(i)))
case ((name, FAny(value :: _)), i) => Good(InputCustomFieldValue(name, Some(value), Some(i)))
case ((name, FNull), i) => Good(InputCustomFieldValue(name, None, Some(i)))
case ((name, obj: FObject), i) =>
getStringCustomField(name, obj) orElse
getIntegerCustomField(name, obj) orElse
getFloatCustomField(name, obj) orElse
getDateCustomField(name, obj) orElse
getBooleanCustomField(name, obj) getOrElse
Good(InputCustomFieldValue(name, None, None))
case (name, other) =>
case ((name, other), i) =>
Bad(
One(
InvalidFormatAttributeError(name, "CustomFieldValue", Set("field: string", "field: number", "field: boolean", "field: date"), other)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,15 @@ object InputCustomFieldValue {
case (_, FObject(fields)) =>
fields
.toSeq
.zipWithIndex
.validatedBy {
case (name, valueField) => valueParser(valueField).map(v => InputCustomFieldValue(name, v, None))
case ((name, valueField), i) => valueParser(valueField).map(v => InputCustomFieldValue(name, v, Some(i)))
}
.map(_.toSeq)
case (_, FSeq(list)) =>
list.zipWithIndex.validatedBy {
list
.zipWithIndex
.validatedBy {
case (cf: FObject, i) =>
val order = FieldsParser.int(cf.get("order")).getOrElse(i)
for {
Expand All @@ -63,7 +66,7 @@ object InputCustomFieldValue {
case (other, i) =>
Bad(
One(
InvalidFormatAttributeError(s"customFild[$i]", "CustomFieldValue", Set.empty, other)
InvalidFormatAttributeError(s"customField[$i]", "CustomFieldValue", Set.empty, other)
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ class Output @Inject() (
_ <- alertSrv.alertOrganisationSrv.create(AlertOrganisation(), alert, organisation)
_ <- caseTemplate.map(ct => alertSrv.alertCaseTemplateSrv.create(AlertCaseTemplate(), alert, ct)).flip
_ <- tags.toTry(t => alertSrv.alertTagSrv.create(AlertTag(), alert, t))
_ <- inputAlert.customFields.toTry { case (name, value) => alertSrv.createCustomField(alert, name, value) }
_ <- inputAlert.customFields.toTry { case (name, value) => alertSrv.createCustomField(alert, name, value, None) }
_ = updateMetaData(alert, inputAlert.metaData)
_ = inputAlert.caseId.flatMap(c => getCase(EntityId.read(c)).toOption).foreach(alertSrv.alertCaseSrv.create(AlertCase(), alert, _))
} yield IdMapping(inputAlert.metaData.id, alert._id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ class MispExportSrv @Inject() (
)
}
org <- organisationSrv.getOrFail(authContext.organisation)
createdAlert <- alertSrv.create(alert.copy(lastSyncDate = new Date(0L)), org, Seq.empty[Tag with Entity], Map.empty[String, Option[Any]], None)
createdAlert <- alertSrv.create(alert.copy(lastSyncDate = new Date(0L)), org, Seq.empty[Tag with Entity], Seq(), None)
_ <- alertSrv.alertCaseSrv.create(AlertCase(), createdAlert.alert, `case`)
} yield createdAlert

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ class MispImportSrv @Inject() (
case None => // if the related alert doesn't exist, create it
logger.debug(s"Event ${client.name}#${event.id} has no related alert for organisation ${organisation.name}")
alertSrv
.create(alert, organisation, event.tags.map(_.name).toSet, Map.empty[String, Option[Any]], caseTemplate)
.create(alert, organisation, event.tags.map(_.name).toSet, Seq(), caseTemplate)
.map(_.alert)
case Some(richAlert) =>
logger.debug(s"Event ${client.name}#${event.id} have already been imported for organisation ${organisation.name}, updating the alert")
Expand Down
4 changes: 2 additions & 2 deletions thehive/app/org/thp/thehive/controllers/v0/AlertCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class AlertCtrl @Inject() (
val caseTemplateName: Option[String] = request.body("caseTemplate")
val inputAlert: InputAlert = request.body("alert")
val observables: Seq[InputObservable] = request.body("observables")
val customFields = inputAlert.customFields.map(c => c.name -> c.value).toMap
val customFields = inputAlert.customFields.map(c => (c.name, c.value, c.order))
val caseTemplate = caseTemplateName.flatMap(ct => caseTemplateSrv.get(EntityIdOrName(ct)).visible.headOption)
for {
organisation <-
Expand Down Expand Up @@ -428,7 +428,7 @@ class PublicAlert @Inject() (
case (FPathElem(_, FPathElem(name, _)), value, vertex, _, graph, authContext) =>
for {
c <- alertSrv.getByIds(EntityId(vertex.id))(graph).getOrFail("Alert")
_ <- alertSrv.setOrCreateCustomField(c, name, Some(value))(graph, authContext)
_ <- alertSrv.setOrCreateCustomField(c, name, Some(value), None)(graph, authContext)
} yield Json.obj(s"customField.$name" -> value)
case (FPathElem(_, FPathEmpty), values: JsObject, vertex, _, graph, authContext) =>
for {
Expand Down
2 changes: 1 addition & 1 deletion thehive/app/org/thp/thehive/controllers/v1/AlertCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class AlertCtrl @Inject() (
val caseTemplate = caseTemplateName.flatMap(ct => caseTemplateSrv.get(EntityIdOrName(ct)).visible.headOption)
for {
organisation <- userSrv.current.organisations(Permissions.manageAlert).getOrFail("Organisation")
customFields = inputAlert.customFieldValue.map(cf => cf.name -> cf.value).toMap
customFields = inputAlert.customFieldValue.map(cf => (cf.name, cf.value, cf.order))
richAlert <- alertSrv.create(inputAlert.toAlert, organisation, inputAlert.tags, customFields, caseTemplate)
} yield Results.Created(richAlert.toJson)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class Properties @Inject() (
case (FPathElem(_, FPathElem(name, _)), value, vertex, _, graph, authContext) =>
for {
c <- alertSrv.getOrFail(vertex)(graph)
_ <- alertSrv.setOrCreateCustomField(c, name, Some(value))(graph, authContext)
_ <- alertSrv.setOrCreateCustomField(c, name, Some(value), None)(graph, authContext)
} yield Json.obj(s"customField.$name" -> value)
case _ => Failure(BadRequestError("Invalid custom fields format"))
})
Expand Down
21 changes: 11 additions & 10 deletions thehive/app/org/thp/thehive/services/AlertSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class AlertSrv @Inject() (
alert: Alert,
organisation: Organisation with Entity,
tagNames: Set[String],
customFields: Map[String, Option[Any]],
customFields: Seq[(String, Option[Any], Option[Int])],
caseTemplate: Option[CaseTemplate with Entity]
)(implicit
graph: Graph,
Expand All @@ -67,7 +67,7 @@ class AlertSrv @Inject() (
alert: Alert,
organisation: Organisation with Entity,
tags: Seq[Tag with Entity],
customFields: Map[String, Option[Any]],
customFields: Seq[(String, Option[Any], Option[Int])],
caseTemplate: Option[CaseTemplate with Entity]
)(implicit
graph: Graph,
Expand All @@ -82,7 +82,7 @@ class AlertSrv @Inject() (
_ <- alertOrganisationSrv.create(AlertOrganisation(), createdAlert, organisation)
_ <- caseTemplate.map(ct => alertCaseTemplateSrv.create(AlertCaseTemplate(), createdAlert, ct)).flip
_ <- tags.toTry(t => alertTagSrv.create(AlertTag(), createdAlert, t))
cfs <- customFields.toTry { case (name, value) => createCustomField(createdAlert, name, value) }
cfs <- customFields.toTry { case (name, value, order) => createCustomField(createdAlert, name, value, order) }
richAlert = RichAlert(createdAlert, organisation.name, tags, cfs, None, caseTemplate.map(_.name), 0)
_ <- auditSrv.alert.create(createdAlert, richAlert.toJson)
} yield richAlert
Expand Down Expand Up @@ -170,24 +170,25 @@ class AlertSrv @Inject() (

def createCustomField(
alert: Alert with Entity,
customFieldName: String,
customFieldValue: Option[Any]
name: String,
value: Option[Any],
order: Option[Int]
)(implicit graph: Graph, authContext: AuthContext): Try[RichCustomField] =
for {
cf <- customFieldSrv.getOrFail(EntityIdOrName(customFieldName))
ccf <- CustomFieldType.map(cf.`type`).setValue(AlertCustomField(), customFieldValue)
cf <- customFieldSrv.getOrFail(EntityIdOrName(name))
ccf <- CustomFieldType.map(cf.`type`).setValue(AlertCustomField(), value).map(_.order_=(order))
ccfe <- alertCustomFieldSrv.create(ccf, alert, cf)
} yield RichCustomField(cf, ccfe)

def setOrCreateCustomField(alert: Alert with Entity, customFieldName: String, value: Option[Any])(implicit
def setOrCreateCustomField(alert: Alert with Entity, customFieldName: String, value: Option[Any], order: Option[Int])(implicit
graph: Graph,
authContext: AuthContext
): Try[Unit] = {
val cfv = get(alert).customFields(customFieldName)
if (cfv.clone().exists)
cfv.setValue(value)
else
createCustomField(alert, customFieldName, value).map(_ => ())
createCustomField(alert, customFieldName, value, order).map(_ => ())
}

def getCustomField(alert: Alert with Entity, customFieldName: String)(implicit graph: Graph): Option[RichCustomField] =
Expand All @@ -205,7 +206,7 @@ class AlertSrv @Inject() (
.filterNot(rcf => customFieldNames.contains(rcf.name))
.foreach(rcf => get(alert).customFields(rcf.name).remove())
customFieldValues
.toTry { case (cf, v) => setOrCreateCustomField(alert, cf.name, Some(v)) }
.toTry { case (cf, v) => setOrCreateCustomField(alert, cf.name, Some(v), None) }
.map(_ => ())
}

Expand Down
2 changes: 1 addition & 1 deletion thehive/test/org/thp/thehive/services/AlertSrvTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class AlertSrvTest extends PlaySpecification with TestAppBuilder {
),
app[OrganisationSrv].getOrFail(EntityName("cert")).get,
Set("tag1", "tag2"),
Map("string1" -> Some("lol")),
Seq(("string1", Some("lol"), None)),
Some(app[CaseTemplateSrv].getOrFail(EntityName("spam")).get)
)
}
Expand Down

0 comments on commit 0cdc56d

Please sign in to comment.