From 12d45ec54293177b28382fc5166224eb2085788d Mon Sep 17 00:00:00 2001 From: To-om Date: Wed, 28 Oct 2020 08:17:30 +0100 Subject: [PATCH] #1579 Add APIs to list user and org configs --- .../thehive/controllers/v0/ConfigCtrl.scala | 73 +++++++++++++++++-- .../thp/thehive/controllers/v0/Router.scala | 8 +- 2 files changed, 72 insertions(+), 9 deletions(-) diff --git a/thehive/app/org/thp/thehive/controllers/v0/ConfigCtrl.scala b/thehive/app/org/thp/thehive/controllers/v0/ConfigCtrl.scala index 8f63df3e47..4b58eab688 100644 --- a/thehive/app/org/thp/thehive/controllers/v0/ConfigCtrl.scala +++ b/thehive/app/org/thp/thehive/controllers/v0/ConfigCtrl.scala @@ -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 ) { @@ -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] = @@ -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")) @@ -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 => diff --git a/thehive/app/org/thp/thehive/controllers/v0/Router.scala b/thehive/app/org/thp/thehive/controllers/v0/Router.scala index 547c48faf7..050122e10d 100644 --- a/thehive/app/org/thp/thehive/controllers/v0/Router.scala +++ b/thehive/app/org/thp/thehive/controllers/v0/Router.scala @@ -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