Skip to content

Commit a7ba8bd

Browse files
committed
#1872 Added quota for alerts, case templates, custom fields & organisations
1 parent a8611b5 commit a7ba8bd

File tree

6 files changed

+74
-6
lines changed

6 files changed

+74
-6
lines changed

thehive/app/org/thp/thehive/controllers/v1/OrganisationCtrl.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class OrganisationCtrl @Inject() (
5858
val inputOrganisation: InputOrganisation = request.body("organisation")
5959
for {
6060
user <- userSrv.current.getOrFail("User")
61-
organisation <- organisationSrv.create(inputOrganisation.toOrganisation, user)
61+
organisation <- organisationSrv.createWithUserAsOrgadmin(inputOrganisation.toOrganisation, user)
6262
} yield Results.Created(organisation.toJson)
6363
}
6464

thehive/app/org/thp/thehive/services/AlertSrv.scala

+17
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import org.thp.thehive.services.CaseOps._
1919
import org.thp.thehive.services.CaseTemplateOps._
2020
import org.thp.thehive.services.CustomFieldOps._
2121
import org.thp.thehive.services.ObservableOps._
22+
import org.thp.thehive.services.OrganisationOps._
23+
import play.api.Configuration
2224
import play.api.libs.json.{JsObject, JsValue, Json}
2325

2426
import java.lang.{Long => JLong}
@@ -28,6 +30,7 @@ import scala.util.{Failure, Success, Try}
2830

2931
@Singleton
3032
class AlertSrv @Inject() (
33+
configuration: Configuration,
3134
caseSrv: CaseSrv,
3235
tagSrv: TagSrv,
3336
organisationSrv: OrganisationSrv,
@@ -79,6 +82,7 @@ class AlertSrv @Inject() (
7982
Failure(CreateError(s"Alert ${alert.`type`}:${alert.source}:${alert.sourceRef} already exist in organisation ${organisation.name}"))
8083
else
8184
for {
85+
_ <- checkAlertQuota(organisation)
8286
createdAlert <- createEntity(alert.copy(organisationId = organisation._id))
8387
_ <- alertOrganisationSrv.create(AlertOrganisation(), createdAlert, organisation)
8488
_ <- caseTemplate.map(ct => alertCaseTemplateSrv.create(AlertCaseTemplate(), createdAlert, ct)).flip
@@ -89,6 +93,19 @@ class AlertSrv @Inject() (
8993
} yield richAlert
9094
}
9195

96+
private def checkAlertQuota(organisation: Organisation with Entity)(implicit
97+
graph: Graph,
98+
authContext: AuthContext
99+
): Try[Unit] = {
100+
val alertQuota = configuration.getOptional[Long]("quota.organisation.alert.count")
101+
val alertCount = organisationSrv.get(organisation).alerts.getCount
102+
103+
alertQuota.fold[Try[Unit]](Success(()))(quota =>
104+
if (alertCount < quota) Success(())
105+
else Failure(BadRequestError(s"Alert quota is reached, this organisation cannot have more alerts"))
106+
)
107+
}
108+
92109
override def update(
93110
traversal: Traversal.V[Alert],
94111
propertyUpdaters: Seq[PropertyUpdater]

thehive/app/org/thp/thehive/services/CaseTemplateSrv.scala

+17-1
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,23 @@ import org.thp.scalligraph.query.PropertyUpdater
88
import org.thp.scalligraph.services._
99
import org.thp.scalligraph.traversal.TraversalOps._
1010
import org.thp.scalligraph.traversal.{Converter, Graph, StepLabel, Traversal}
11-
import org.thp.scalligraph.{CreateError, EntityIdOrName, EntityName, RichSeq}
11+
import org.thp.scalligraph.{BadRequestError, CreateError, EntityIdOrName, EntityName, RichSeq}
1212
import org.thp.thehive.controllers.v1.Conversion._
1313
import org.thp.thehive.models._
1414
import org.thp.thehive.services.CaseTemplateOps._
1515
import org.thp.thehive.services.CustomFieldOps._
1616
import org.thp.thehive.services.OrganisationOps._
1717
import org.thp.thehive.services.TaskOps._
1818
import org.thp.thehive.services.UserOps._
19+
import play.api.Configuration
1920
import play.api.libs.json.{JsObject, Json}
2021

2122
import java.util.{Map => JMap}
2223
import javax.inject.{Inject, Named}
2324
import scala.util.{Failure, Success, Try}
2425

2526
class CaseTemplateSrv @Inject() (
27+
configuration: Configuration,
2628
customFieldSrv: CustomFieldSrv,
2729
organisationSrv: OrganisationSrv,
2830
tagSrv: TagSrv,
@@ -57,6 +59,7 @@ class CaseTemplateSrv @Inject() (
5759
Failure(CreateError(s"""The case template "${caseTemplate.name}" already exists"""))
5860
else
5961
for {
62+
_ <- checkCaseTemplateQuota(organisation)
6063
createdCaseTemplate <- createEntity(caseTemplate)
6164
_ <- caseTemplateOrganisationSrv.create(CaseTemplateOrganisation(), createdCaseTemplate, organisation)
6265
createdTasks <- tasks.toTry(createTask(createdCaseTemplate, _))
@@ -66,6 +69,19 @@ class CaseTemplateSrv @Inject() (
6669
_ <- auditSrv.caseTemplate.create(createdCaseTemplate, richCaseTemplate.toJson)
6770
} yield richCaseTemplate
6871

72+
private def checkCaseTemplateQuota(organisation: Organisation with Entity)(implicit
73+
graph: Graph,
74+
authContext: AuthContext
75+
): Try[Unit] = {
76+
val caseTemplateQuota = configuration.getOptional[Long]("quota.organisation.caseTemplate.count")
77+
val caseTemplateCount = organisationSrv.get(organisation).caseTemplates.getCount
78+
79+
caseTemplateQuota.fold[Try[Unit]](Success(()))(quota =>
80+
if (caseTemplateCount < quota) Success(())
81+
else Failure(BadRequestError(s"Case template quota is reached, this organisation cannot have more case templates"))
82+
)
83+
}
84+
6985
def createTask(caseTemplate: CaseTemplate with Entity, task: Task)(implicit graph: Graph, authContext: AuthContext): Try[RichTask] =
7086
for {
7187
assignee <- task.assignee.map(u => organisationSrv.current.users(Permissions.manageTask).getByName(u).getOrFail("User")).flip

thehive/app/org/thp/thehive/services/CustomFieldSrv.scala

+18-2
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,21 @@ import org.thp.scalligraph.query.PropertyUpdater
88
import org.thp.scalligraph.services.{IntegrityCheckOps, VertexSrv}
99
import org.thp.scalligraph.traversal.TraversalOps._
1010
import org.thp.scalligraph.traversal._
11-
import org.thp.scalligraph.{EntityIdOrName, RichSeq}
11+
import org.thp.scalligraph.{BadRequestError, EntityIdOrName, RichSeq}
1212
import org.thp.thehive.controllers.v1.Conversion._
1313
import org.thp.thehive.models._
1414
import org.thp.thehive.services.CustomFieldOps._
15+
import play.api.Configuration
1516
import play.api.cache.SyncCacheApi
1617
import play.api.libs.json.{JsObject, JsValue}
1718

1819
import java.util.{Map => JMap}
1920
import javax.inject.{Inject, Named, Singleton}
20-
import scala.util.{Success, Try}
21+
import scala.util.{Failure, Success, Try}
2122

2223
@Singleton
2324
class CustomFieldSrv @Inject() (
25+
configuration: Configuration,
2426
auditSrv: AuditSrv,
2527
organisationSrv: OrganisationSrv,
2628
@Named("integrity-check-actor") integrityCheckActor: ActorRef,
@@ -36,10 +38,24 @@ class CustomFieldSrv @Inject() (
3638

3739
def create(e: CustomField)(implicit graph: Graph, authContext: AuthContext): Try[CustomField with Entity] =
3840
for {
41+
_ <- checkCustomFieldQuota
3942
created <- createEntity(e)
4043
_ <- auditSrv.customField.create(created, created.toJson)
4144
} yield created
4245

46+
private def checkCustomFieldQuota(implicit
47+
graph: Graph,
48+
authContext: AuthContext
49+
): Try[Unit] = {
50+
val customFieldQuota = configuration.getOptional[Long]("quota.customField.count")
51+
val customFieldCount = startTraversal.getCount
52+
53+
customFieldQuota.fold[Try[Unit]](Success(()))(quota =>
54+
if (customFieldCount < quota) Success(())
55+
else Failure(BadRequestError(s"Custom field quota is reached, no more custom fields can be created"))
56+
)
57+
}
58+
4359
override def exists(e: CustomField)(implicit graph: Graph): Boolean = startTraversal.getByName(e.name).exists
4460

4561
def delete(c: CustomField with Entity, force: Boolean)(implicit graph: Graph, authContext: AuthContext): Try[Unit] = {

thehive/app/org/thp/thehive/services/OrganisationSrv.scala

+20-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import org.thp.thehive.models._
1313
import org.thp.thehive.services.OrganisationOps._
1414
import org.thp.thehive.services.RoleOps._
1515
import org.thp.thehive.services.UserOps._
16+
import play.api.Configuration
1617
import play.api.cache.SyncCacheApi
1718
import play.api.libs.json.JsObject
1819

@@ -22,6 +23,7 @@ import scala.util.{Failure, Success, Try}
2223

2324
@Singleton
2425
class OrganisationSrv @Inject() (
26+
configuration: Configuration,
2527
taxonomySrvProvider: Provider[TaxonomySrv],
2628
roleSrv: RoleSrv,
2729
profileSrv: ProfileSrv,
@@ -42,7 +44,10 @@ class OrganisationSrv @Inject() (
4244

4345
override def getByName(name: String)(implicit graph: Graph): Traversal.V[Organisation] = startTraversal.getByName(name)
4446

45-
def create(organisation: Organisation, user: User with Entity)(implicit graph: Graph, authContext: AuthContext): Try[Organisation with Entity] =
47+
def createWithUserAsOrgadmin(organisation: Organisation, user: User with Entity)(implicit
48+
graph: Graph,
49+
authContext: AuthContext
50+
): Try[Organisation with Entity] =
4651
for {
4752
createdOrganisation <- create(organisation)
4853
_ <- roleSrv.create(user, createdOrganisation, profileSrv.orgAdmin)
@@ -51,13 +56,27 @@ class OrganisationSrv @Inject() (
5156
def create(e: Organisation)(implicit graph: Graph, authContext: AuthContext): Try[Organisation with Entity] = {
5257
val activeTaxos = getByName("admin").taxonomies.toSeq
5358
for {
59+
_ <- checkOrganisationQuota
5460
newOrga <- createEntity(e)
5561
_ <- taxonomySrv.createFreetagTaxonomy(newOrga)
5662
_ <- activeTaxos.toTry(t => organisationTaxonomySrv.create(OrganisationTaxonomy(), newOrga, t))
5763
_ <- auditSrv.organisation.create(newOrga, newOrga.toJson)
5864
} yield newOrga
5965
}
6066

67+
private def checkOrganisationQuota(implicit
68+
graph: Graph,
69+
authContext: AuthContext
70+
): Try[Unit] = {
71+
val organisationQuota = configuration.getOptional[Long]("quota.organisation.count")
72+
val organisationCount = startTraversal.getCount
73+
74+
organisationQuota.fold[Try[Unit]](Success(()))(quota =>
75+
if (organisationCount < quota) Success(())
76+
else Failure(BadRequestError(s"Organisation quota is reached, no more organisations can be created"))
77+
)
78+
}
79+
6180
def current(implicit graph: Graph, authContext: AuthContext): Traversal.V[Organisation] = get(authContext.organisation)
6281

6382
def currentId(implicit graph: Graph, authContext: AuthContext): EntityId =

thehive/app/org/thp/thehive/services/UserSrv.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class UserSrv @Inject() (
6767
else Failure(BadRequestError(s"User login is invalid, it must be an email address (found: ${user.login})"))
6868
}
6969

70-
def checkUserQuota(organisation: Organisation with Entity)(implicit
70+
private def checkUserQuota(organisation: Organisation with Entity)(implicit
7171
graph: Graph,
7272
authContext: AuthContext
7373
): Try[Unit] = {

0 commit comments

Comments
 (0)