Skip to content

Commit

Permalink
#1670 Add extra data on tags to see usage
Browse files Browse the repository at this point in the history
  • Loading branch information
To-om committed Mar 5, 2021
1 parent 0f2bbc6 commit b36f8e8
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 6 deletions.
5 changes: 3 additions & 2 deletions dto/src/main/scala/org/thp/thehive/dto/v1/Tag.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.thp.thehive.dto.v1

import play.api.libs.json.{Json, OFormat}
import play.api.libs.json.{JsObject, Json, OFormat}

import java.util.Date

Expand All @@ -15,7 +15,8 @@ case class OutputTag(
predicate: String,
value: Option[String],
description: Option[String],
colour: String
colour: String,
extraData: JsObject
)

object OutputTag {
Expand Down
18 changes: 18 additions & 0 deletions thehive/app/org/thp/thehive/controllers/v1/Conversion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,27 @@ object Conversion {
.withFieldConst(_._createdBy, tag._createdBy)
.withFieldConst(_._type, "Tag")
.withFieldComputed(_.namespace, t => if (t.isFreeTag) "_freetags_" else t.namespace)
.withFieldConst(_.extraData, JsObject.empty)
.transform
)

implicit val tagWithStatsOutput: Renderer.Aux[(Tag with Entity, JsObject), OutputTag] =
Renderer.toJson[(Tag with Entity, JsObject), OutputTag] {
case (tag, stats) =>
tag
.asInstanceOf[Tag]
.into[OutputTag]
.withFieldConst(_._id, tag._id.toString)
.withFieldConst(_._updatedAt, tag._updatedAt)
.withFieldConst(_._updatedBy, tag._updatedBy)
.withFieldConst(_._createdAt, tag._createdAt)
.withFieldConst(_._createdBy, tag._createdBy)
.withFieldConst(_._type, "Tag")
.withFieldComputed(_.namespace, t => if (t.isFreeTag) "_freetags_" else t.namespace)
.withFieldConst(_.extraData, stats)
.transform
}

implicit class InputUserOps(inputUser: InputUser) {

def toUser: User =
Expand Down
10 changes: 7 additions & 3 deletions thehive/app/org/thp/thehive/controllers/v1/TagCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,20 @@ class TagCtrl @Inject() (
entrypoint: Entrypoint,
db: Database,
tagSrv: TagSrv,
organisationSrv: OrganisationSrv,
val organisationSrv: OrganisationSrv,
properties: Properties
) extends QueryableCtrl {
) extends QueryableCtrl
with TagRenderer {
override val entityName: String = "Tag"
override val publicProperties: PublicProperties = properties.tag
override val initialQuery: Query =
Query.init[Traversal.V[Tag]]("listTag", (graph, authContext) => tagSrv.startTraversal(graph).visible(authContext))
override val pageQuery: ParamQuery[OutputParam] = Query.withParam[OutputParam, Traversal.V[Tag], IteratorOutput](
"page",
(range, tagSteps, _) => tagSteps.page(range.from, range.to, withTotal = true)
(params, tagSteps, authContext) =>
tagSteps.richPage(params.from, params.to, params.extraData.contains("total"))(
_.withCustomRenderer(tagStatsRenderer(params.extraData - "total")(authContext))
)
)
override val outputQuery: Query = Query.output[Tag with Entity]
override val getQuery: ParamQuery[EntityIdOrName] = Query.initWithParam[EntityIdOrName, Traversal.V[Tag]](
Expand Down
42 changes: 42 additions & 0 deletions thehive/app/org/thp/thehive/controllers/v1/TagRenderer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.thp.thehive.controllers.v1

import org.thp.scalligraph.auth.AuthContext
import org.thp.scalligraph.traversal.TraversalOps._
import org.thp.scalligraph.traversal.{Converter, Traversal}
import org.thp.thehive.models.Tag
import org.thp.thehive.services.TagOps._
import play.api.libs.json._

import java.util.{Map => JMap}

trait TagRenderer extends BaseRenderer[Tag] {

def usageStats(implicit
authContext: AuthContext
): Traversal.V[Tag] => Traversal[JsObject, JMap[String, Any], Converter[JsObject, JMap[String, Any]]] =
_.project(
_.by(_.`case`.count)
.by(_.alert.count)
.by(_.observable.count)
).domainMap {
case (caseCount, alertCount, observableCount) =>
Json.obj(
"case" -> caseCount,
"alert" -> alertCount,
"observable" -> observableCount
)
}

def tagStatsRenderer(extraData: Set[String])(implicit
authContext: AuthContext
): Traversal.V[Tag] => JsTraversal = { implicit traversal =>
baseRenderer(
extraData,
traversal,
{
case (f, "usage") => addData("usage", f)(usageStats)
case (f, _) => f
}
)
}
}
11 changes: 10 additions & 1 deletion thehive/app/org/thp/thehive/services/TagSrv.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.thp.thehive.services

import java.util.{Map => JMap}
import akka.actor.ActorRef
import org.apache.tinkerpop.gremlin.process.traversal.TextP
import org.apache.tinkerpop.gremlin.structure.Vertex
Expand Down Expand Up @@ -109,10 +110,13 @@ object TagOps {
def displayName: Traversal[String, Vertex, Converter[String, Vertex]] = traversal.domainMap(_.toString)

def fromCase: Traversal.V[Tag] = traversal.filter(_.in[CaseTag])
def `case`: Traversal.V[Case] = traversal.in[CaseTag].v[Case]

def fromObservable: Traversal.V[Tag] = traversal.filter(_.in[ObservableTag])
def fromObservable: Traversal.V[Tag] = traversal.filter(_.in[ObservableTag])
def observable: Traversal.V[Observable] = traversal.in[ObservableTag].v[Observable]

def fromAlert: Traversal.V[Tag] = traversal.filter(_.in[AlertTag])
def alert: Traversal.V[Alert] = traversal.in[AlertTag].v[Alert]

def freetags(organisationSrv: OrganisationSrv)(implicit authContext: AuthContext): Traversal.V[Tag] = {
val freeTagNamespace: String = s"_freetags_${organisationSrv.currentId(traversal.graph, authContext).value}"
Expand Down Expand Up @@ -140,6 +144,11 @@ object TagOps {

def visible(implicit authContext: AuthContext): Traversal.V[Tag] =
traversal.filter(_.organisation.current)

def withCustomRenderer[D, G, C <: Converter[D, G]](
entityRenderer: Traversal.V[Tag] => Traversal[D, G, C]
): Traversal[(Tag with Entity, D), JMap[String, Any], Converter[(Tag with Entity, D), JMap[String, Any]]] =
traversal.project(_.by.by(entityRenderer))
}
}

Expand Down

0 comments on commit b36f8e8

Please sign in to comment.