Skip to content

Commit

Permalink
#1579 Add APIs to list user and org configs
Browse files Browse the repository at this point in the history
  • Loading branch information
To-om committed Nov 13, 2020
1 parent df91967 commit 12d45ec
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 9 deletions.
73 changes: 67 additions & 6 deletions thehive/app/org/thp/thehive/controllers/v0/ConfigCtrl.scala
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
package org.thp.thehive.controllers.v0

import com.typesafe.config.{Config, ConfigRenderOptions}
import com.typesafe.config.{ConfigRenderOptions, Config => TypeSafeConfig}
import javax.inject.{Inject, Named, Singleton}
import org.thp.scalligraph.controllers.{Entrypoint, FieldsParser}
import org.thp.scalligraph.models.Database
import org.thp.scalligraph.services.config.{ApplicationConfig, ConfigItem}
import org.thp.scalligraph.traversal.TraversalOps._
import org.thp.scalligraph.{AuthorizationError, NotFoundError}
import org.thp.thehive.models.Permissions
import org.thp.thehive.services.OrganisationOps._
import org.thp.thehive.services.{OrganisationConfigContext, OrganisationSrv, UserConfigContext}
import play.api.libs.json.{JsNull, JsValue, Json, Writes}
import play.api.mvc.{Action, AnyContent, Results}
import play.api.{ConfigLoader, Logger}
import org.thp.thehive.services.UserOps._
import org.thp.thehive.services._
import play.api.libs.json._
import play.api.mvc.{Action, AnyContent, Result, Results}
import play.api.{ConfigLoader, Configuration, Logger}

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

@Singleton
class ConfigCtrl @Inject() (
configuration: Configuration,
appConfig: ApplicationConfig,
userConfigContext: UserConfigContext,
organisationConfigContext: OrganisationConfigContext,
organisationSrv: OrganisationSrv,
userSrv: UserSrv,
entrypoint: Entrypoint,
@Named("with-thehive-schema") db: Database
) {
Expand All @@ -36,7 +40,7 @@ class ConfigCtrl @Inject() (
)
)

implicit val jsonConfigLoader: ConfigLoader[JsValue] = (config: Config, path: String) =>
implicit val jsonConfigLoader: ConfigLoader[JsValue] = (config: TypeSafeConfig, path: String) =>
Json.parse(config.getValue(path).render(ConfigRenderOptions.concise()))

def list: Action[AnyContent] =
Expand Down Expand Up @@ -72,6 +76,40 @@ class ConfigCtrl @Inject() (
}
}

def mergeConfig(defaultValue: JsValue, names: Seq[String], value: JsValue): JsValue =
names
.headOption
.fold[JsValue](value) { key =>
defaultValue
.asOpt[JsObject]
.fold(names.foldRight(value)((k, v) => Json.obj(k -> v))) { default =>
default + (key -> mergeConfig((defaultValue \ key).getOrElse(JsNull), names.tail, value))
}
}

def userList: Action[AnyContent] =
entrypoint("list user configuration item")
.extract("path", FieldsParser[String].optional.on("path"))
.authRoTransaction(db) { implicit request => implicit graph =>
val defaultValue = configuration.get[JsValue]("user.defaults")
val userConfiguration = userSrv
.current
.config
.toIterator
.foldLeft(defaultValue)((default, config) => mergeConfig(default, config.name.split('.').toSeq, config.value))

request.body("path") match {
case Some(path: String) =>
path
.split('.')
.foldLeft[JsLookupResult](JsDefined(userConfiguration))((cfg, key) => cfg \ key)
.toOption
.fold[Try[Result]](Failure(NotFoundError(s"The configuration $path doesn't exist")))(v => Success(Results.Ok(v)))
case None =>
Success(Results.Ok(userConfiguration))
}
}

def userSet(path: String): Action[AnyContent] =
entrypoint("set user configuration item")
.extract("value", FieldsParser.json.on("value"))
Expand Down Expand Up @@ -113,6 +151,29 @@ class ConfigCtrl @Inject() (
}
}

def organisationList: Action[AnyContent] =
entrypoint("list organisation configuration item")
.extract("path", FieldsParser[String].optional.on("path"))
.authRoTransaction(db) { implicit request => implicit graph =>
val defaultValue = configuration.get[JsValue]("organisation.defaults")
val orgConfiguration = organisationSrv
.current
.config
.toIterator
.foldLeft(defaultValue)((default, config) => mergeConfig(default, config.name.split('.').toSeq, config.value))

request.body("path") match {
case Some(path: String) =>
path
.split('.')
.foldLeft[JsLookupResult](JsDefined(orgConfiguration))((cfg, key) => cfg \ key)
.toOption
.fold[Try[Result]](Failure(NotFoundError(s"The configuration $path doesn't exist")))(v => Success(Results.Ok(v)))
case None =>
Success(Results.Ok(orgConfiguration))
}
}

def organisationGet(path: String): Action[AnyContent] =
entrypoint("get organisation configuration item")
.auth { implicit request =>
Expand Down
8 changes: 5 additions & 3 deletions thehive/app/org/thp/thehive/controllers/v0/Router.scala
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,15 @@ class Router @Inject() (
case GET(p"/describe/_all") => describeCtrl.describeAll
case GET(p"/describe/$modelName") => describeCtrl.describe(modelName)

case GET(p"/config") => configCtrl.list
case GET(p"/config/$path") => configCtrl.get(path)
case PUT(p"/config/$path") => configCtrl.set(path)
case GET(p"/config/user") => configCtrl.userList
case GET(p"/config/user/$path") => configCtrl.userGet(path)
case PUT(p"/config/user/$path") => configCtrl.userSet(path)
case GET(p"/config/organisation") => configCtrl.organisationList
case GET(p"/config/organisation/$path") => configCtrl.organisationGet(path)
case PUT(p"/config/organisation/$path") => configCtrl.organisationSet(path)
case GET(p"/config") => configCtrl.list
case GET(p"/config/$path") => configCtrl.get(path)
case PUT(p"/config/$path") => configCtrl.set(path)

case GET(p"/profile") => profileCtrl.search
case POST(p"/profile/_search") => profileCtrl.search
Expand Down

0 comments on commit 12d45ec

Please sign in to comment.