From 0d680698287ec2fbd77a1a30f8baf19da9ab0e76 Mon Sep 17 00:00:00 2001 From: To-om Date: Wed, 15 May 2019 17:10:44 +0200 Subject: [PATCH 01/17] #191 Add support of ElasticSearch 6 --- .../cortex/controllers/AttachmentCtrl.scala | 4 +-- .../thp/cortex/controllers/DBListCtrl.scala | 4 +-- .../thp/cortex/controllers/StatusCtrl.scala | 9 ++--- app/org/thp/cortex/models/Migration.scala | 16 +++++++-- app/org/thp/cortex/models/Roles.scala | 6 ++-- app/org/thp/cortex/models/package.scala | 2 +- .../thp/cortex/services/ErrorHandler.scala | 36 ++++++++++--------- project/Dependencies.scala | 2 +- 8 files changed, 45 insertions(+), 34 deletions(-) diff --git a/app/org/thp/cortex/controllers/AttachmentCtrl.scala b/app/org/thp/cortex/controllers/AttachmentCtrl.scala index 7a8bb43c8..5fb21beaf 100644 --- a/app/org/thp/cortex/controllers/AttachmentCtrl.scala +++ b/app/org/thp/cortex/controllers/AttachmentCtrl.scala @@ -53,7 +53,7 @@ class AttachmentCtrl( * open the document directly. It must be used only for safe file */ @Timed("controllers.AttachmentCtrl.download") - def download(hash: String, name: Option[String]): Action[AnyContent] = authenticated(Roles.read) { implicit request ⇒ + def download(hash: String, name: Option[String]): Action[AnyContent] = authenticated(Roles.read) { _ ⇒ if (hash.startsWith("{{")) // angularjs hack NoContent else if (!name.getOrElse("").intersect(AttachmentAttributeFormat.forbiddenChar).isEmpty) @@ -74,7 +74,7 @@ class AttachmentCtrl( * File name can be specified (zip extension is append) */ @Timed("controllers.AttachmentCtrl.downloadZip") - def downloadZip(hash: String, name: Option[String]): Action[AnyContent] = authenticated(Roles.read) { implicit request ⇒ + def downloadZip(hash: String, name: Option[String]): Action[AnyContent] = authenticated(Roles.read) { _ ⇒ if (!name.getOrElse("").intersect(AttachmentAttributeFormat.forbiddenChar).isEmpty) BadRequest("File name is invalid") else { diff --git a/app/org/thp/cortex/controllers/DBListCtrl.scala b/app/org/thp/cortex/controllers/DBListCtrl.scala index f812475b4..aa47fa631 100644 --- a/app/org/thp/cortex/controllers/DBListCtrl.scala +++ b/app/org/thp/cortex/controllers/DBListCtrl.scala @@ -22,13 +22,13 @@ class DBListCtrl @Inject() ( fieldsBodyParser: FieldsBodyParser, implicit val ec: ExecutionContext) extends AbstractController(components) { - def list: Action[AnyContent] = authenticated(Roles.read).async { implicit request ⇒ + def list: Action[AnyContent] = authenticated(Roles.read).async { _ ⇒ dblists.listAll.map { listNames ⇒ renderer.toOutput(OK, listNames) } } - def listItems(listName: String): Action[AnyContent] = authenticated(Roles.read) { implicit request ⇒ + def listItems(listName: String): Action[AnyContent] = authenticated(Roles.read) { _ ⇒ val (src, _) = dblists(listName).getItems[JsValue] val items = src.map { case (id, value) ⇒ s""""$id":$value""" } .intersperse("{", ",", "}") diff --git a/app/org/thp/cortex/controllers/StatusCtrl.scala b/app/org/thp/cortex/controllers/StatusCtrl.scala index 165a1b492..859ae2d5f 100644 --- a/app/org/thp/cortex/controllers/StatusCtrl.scala +++ b/app/org/thp/cortex/controllers/StatusCtrl.scala @@ -9,7 +9,7 @@ import play.api.libs.json.{ JsBoolean, JsString, Json } import play.api.libs.json.Json.toJsFieldJsValueWrapper import play.api.mvc.{ AbstractController, Action, AnyContent, ControllerComponents } -import com.sksamuel.elastic4s.ElasticDsl +import com.sksamuel.elastic4s.http.ElasticDsl import org.thp.cortex.models.Worker import org.elastic4play.database.DBIndex @@ -26,16 +26,14 @@ class StatusCtrl @Inject() ( private[controllers] def getVersion(c: Class[_]) = Option(c.getPackage.getImplementationVersion).getOrElse("SNAPSHOT") - def get: Action[AnyContent] = Action.async { _ ⇒ - dbIndex.clusterVersions.map { versions ⇒ + def get: Action[AnyContent] = Action { Ok(Json.obj( "versions" → Json.obj( "Cortex" → getVersion(classOf[Worker]), "Elastic4Play" → getVersion(classOf[AuthSrv]), "Play" → getVersion(classOf[AbstractController]), "Elastic4s" → getVersion(classOf[ElasticDsl]), - "ElasticSearch client" → getVersion(classOf[org.elasticsearch.Build]), - "ElasticSearch cluster" → versions.mkString(", ")), + "ElasticSearch client" → getVersion(classOf[org.elasticsearch.client.Node])), "config" → Json.obj( "authType" → (authSrv match { case multiAuthSrv: MultiAuthSrv ⇒ multiAuthSrv.authProviders.map { a ⇒ JsString(a.name) } @@ -44,7 +42,6 @@ class StatusCtrl @Inject() ( "capabilities" → authSrv.capabilities.map(c ⇒ JsString(c.toString)), "ssoAutoLogin" → JsBoolean(configuration.getOptional[Boolean]("auth.sso.autologin").getOrElse(false))))) } - } def health: Action[AnyContent] = TODO } diff --git a/app/org/thp/cortex/models/Migration.scala b/app/org/thp/cortex/models/Migration.scala index 17f16d408..2203a55d0 100644 --- a/app/org/thp/cortex/models/Migration.scala +++ b/app/org/thp/cortex/models/Migration.scala @@ -5,13 +5,13 @@ import scala.concurrent.{ ExecutionContext, Future } import scala.util.Success import play.api.Logger -import play.api.libs.json.{ JsNull, JsString, JsValue, Json } +import play.api.libs.json.{ JsNull, JsNumber, JsString, JsValue, Json } import org.thp.cortex.services.{ OrganizationSrv, UserSrv, WorkerSrv } import org.elastic4play.controllers.Fields import org.elastic4play.services.Operation._ -import org.elastic4play.services.{ DatabaseState, MigrationOperations, Operation } +import org.elastic4play.services.{ DatabaseState, IndexType, MigrationOperations, Operation } import org.elastic4play.utils.Hasher @Singleton @@ -34,6 +34,8 @@ class Migration @Inject() ( } } + override def indexType(version: Int): IndexType.Value = if (version > 3) IndexType.indexWithoutMappingTypes else IndexType.indexWithMappingTypes + val operations: PartialFunction[DatabaseState, Seq[Operation]] = { case DatabaseState(1) ⇒ val hasher = Hasher("MD5") @@ -83,5 +85,15 @@ class Migration @Inject() ( ("baseConfig" -> definition.baseConfiguration.fold[JsValue](JsNull)(JsString.apply)) } }) + + case DatabaseState(3) ⇒ Seq( + mapEntity("sequence") { seq => + val oldId = (seq \ "_id").as[String] + val counter = (seq \ "counter").as[JsNumber] + seq - "counter" - "_routing" + + ("_id" -> JsString("sequence_" + oldId)) + + ("sequenceCounter" -> counter) + } + ) } } diff --git a/app/org/thp/cortex/models/Roles.scala b/app/org/thp/cortex/models/Roles.scala index f268adfa1..1e73e522a 100644 --- a/app/org/thp/cortex/models/Roles.scala +++ b/app/org/thp/cortex/models/Roles.scala @@ -2,8 +2,8 @@ package org.thp.cortex.models import play.api.libs.json.{ JsString, JsValue } -import com.sksamuel.elastic4s.ElasticDsl.keywordField -import com.sksamuel.elastic4s.mappings.KeywordFieldDefinition +import com.sksamuel.elastic4s.http.ElasticDsl.keywordField +import com.sksamuel.elastic4s.mappings.KeywordField import org.scalactic.{ Every, Good, One, Or } import org.elastic4play.{ AttributeError, InvalidFormatAttributeError } @@ -47,5 +47,5 @@ object RoleAttributeFormat extends AttributeFormat[Role]("role") { } - override def elasticType(attributeName: String): KeywordFieldDefinition = keywordField(attributeName) + override def elasticType(attributeName: String): KeywordField = keywordField(attributeName) } \ No newline at end of file diff --git a/app/org/thp/cortex/models/package.scala b/app/org/thp/cortex/models/package.scala index bafbee1ba..0bbb2c3af 100644 --- a/app/org/thp/cortex/models/package.scala +++ b/app/org/thp/cortex/models/package.scala @@ -1,5 +1,5 @@ package org.thp.cortex package object models { - val modelVersion = 3 + val modelVersion = 4 } diff --git a/app/org/thp/cortex/services/ErrorHandler.scala b/app/org/thp/cortex/services/ErrorHandler.scala index 217a4d7a3..0757378b5 100644 --- a/app/org/thp/cortex/services/ErrorHandler.scala +++ b/app/org/thp/cortex/services/ErrorHandler.scala @@ -1,20 +1,21 @@ package org.thp.cortex.services -import org.thp.cortex.models.{ WorkerNotFoundError, JobNotFoundError, RateLimitExceeded } -import play.api.Logger -import play.api.http.{ HttpErrorHandler, Status, Writeable } -import play.api.mvc.{ RequestHeader, ResponseHeader, Result, Results } +import java.net.ConnectException + import scala.concurrent.Future +import org.thp.cortex.models.{ JobNotFoundError, RateLimitExceeded, WorkerNotFoundError } +import play.api.Logger +import play.api.http.{ HttpErrorHandler, Status, Writeable } import play.api.libs.json.{ JsNull, JsValue, Json } +import play.api.mvc.{ RequestHeader, ResponseHeader, Result, Results } -import org.elasticsearch.client.transport.NoNodeAvailableException - -import org.elastic4play._ -import org.elastic4play.JsonFormat._ -import org.elasticsearch.index.IndexNotFoundException -import org.elasticsearch.index.query.QueryShardException +import org.elastic4play.{ AttributeCheckingError, AuthenticationError, AuthorizationError, BadRequestError, CreateError, ErrorWithObject, GetError, IndexNotFoundException, InternalError, MultiError, NotFoundError, SearchError, UpdateError } +import org.elastic4play.JsonFormat.attributeCheckingExceptionWrites +/** + * This class handles errors. It traverses all causes of exception to find known error and shows the appropriate message + */ class ErrorHandler extends HttpErrorHandler { private[ErrorHandler] lazy val logger = Logger(getClass) def onClientError(request: RequestHeader, statusCode: Int, message: String): Future[Result] = Future.successful { @@ -31,12 +32,12 @@ class ErrorHandler extends HttpErrorHandler { case nfe: NumberFormatException ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "NumberFormatException", "message" → ("Invalid format " + nfe.getMessage))) case NotFoundError(message) ⇒ Some(Status.NOT_FOUND → Json.obj("type" → "NotFoundError", "message" → message)) case BadRequestError(message) ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "BadRequest", "message" → message)) - case SearchError(message, cause) ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "SearchError", "message" → s"$message (${cause.getMessage})")) + case SearchError(message) ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "SearchError", "message" → s"$message")) case ace: AttributeCheckingError ⇒ Some(Status.BAD_REQUEST → Json.toJson(ace)) case iae: IllegalArgumentException ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "IllegalArgument", "message" → iae.getMessage)) - case _: NoNodeAvailableException ⇒ Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "NoNodeAvailable", "message" → "ElasticSearch cluster is unreachable")) + case _: ConnectException ⇒ Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "NoNodeAvailable", "message" → "ElasticSearch cluster is unreachable")) case CreateError(_, message, attributes) ⇒ Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "CreateError", "message" → message, "object" → attributes)) - case ErrorWithObject(tpe, message, obj) ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → tpe, "message" → message, "object" → obj)) + case ErrorWithObject(tpe, message, obj) ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → tpe, "message" → message, "object" → obj)) case GetError(message) ⇒ Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "GetError", "message" → message)) case MultiError(message, exceptions) ⇒ val suberrors = exceptions.map(e ⇒ toErrorResult(e)).collect { @@ -45,16 +46,17 @@ class ErrorHandler extends HttpErrorHandler { Some(Status.MULTI_STATUS → Json.obj("type" → "MultiError", "error" → message, "suberrors" → suberrors)) case JobNotFoundError(jobId) ⇒ Some(Status.NOT_FOUND → Json.obj("type" → "JobNotFoundError", "message" → s"Job $jobId not found")) case WorkerNotFoundError(analyzerId) ⇒ Some(Status.NOT_FOUND → Json.obj("type" → "AnalyzerNotFoundError", "message" → s"analyzer $analyzerId not found")) - case _: IndexNotFoundException ⇒ Some(520 → JsNull) - case qse: QueryShardException ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "Invalid search query", "message" → qse.getMessage)) - case t: Throwable ⇒ Option(t.getCause).flatMap(toErrorResult) + case IndexNotFoundException ⇒ Some(520 → JsNull) + case t: Throwable ⇒ Option(t.getCause).flatMap(toErrorResult) } } def toResult[C](status: Int, c: C)(implicit writeable: Writeable[C]) = Result(header = ResponseHeader(status), body = writeable.toEntity(c)) def onServerError(request: RequestHeader, exception: Throwable): Future[Result] = { - val (status, body) = toErrorResult(exception).getOrElse(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → exception.getClass.getName, "message" → exception.getMessage)) + val (status, body) = toErrorResult(exception).getOrElse( + Status.INTERNAL_SERVER_ERROR → Json.obj("type" → exception.getClass.getName, "message" → exception.getMessage) + ) logger.info(s"${request.method} ${request.uri} returned $status", exception) Future.successful(toResult(status, body)) } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 364d0ce38..d08cccb79 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -18,7 +18,7 @@ object Dependencies { val reflections = "org.reflections" % "reflections" % "0.9.11" val zip4j = "net.lingala.zip4j" % "zip4j" % "1.3.2" - val elastic4play = "org.thehive-project" %% "elastic4play" % "1.10.0" + val elastic4play = "org.thehive-project" %% "elastic4play" % "1.11.0" val dockerClient = "com.spotify" % "docker-client" % "8.14.4" } From caccab7c58212bdf213c4159d86c0da93b63297c Mon Sep 17 00:00:00 2001 From: To-om Date: Mon, 20 May 2019 16:29:48 +0200 Subject: [PATCH 02/17] #191 Fix index creation with ES6 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index d08cccb79..147b2bbfa 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -18,7 +18,7 @@ object Dependencies { val reflections = "org.reflections" % "reflections" % "0.9.11" val zip4j = "net.lingala.zip4j" % "zip4j" % "1.3.2" - val elastic4play = "org.thehive-project" %% "elastic4play" % "1.11.0" + val elastic4play = "org.thehive-project" %% "elastic4play" % "1.11.1" val dockerClient = "com.spotify" % "docker-client" % "8.14.4" } From 8f3068cf83eaa501bf94bd0cc2b54a589b00bae6 Mon Sep 17 00:00:00 2001 From: Nabil Adouani Date: Tue, 14 May 2019 11:05:05 +0200 Subject: [PATCH 03/17] #190 Update AngularJs version and UI libraries --- www/package.json | 68 +++++++++---------- .../user-dialog/user.edit.controller.js | 36 +++++----- .../user-dialog/user.edit.controller.js | 36 +++++----- www/src/app/pages/login/login.controller.js | 3 +- .../maintenance/maintenance.controller.js | 8 +-- 5 files changed, 73 insertions(+), 78 deletions(-) diff --git a/www/package.json b/www/package.json index 892c0f20c..a6461a06c 100755 --- a/www/package.json +++ b/www/package.json @@ -2,8 +2,9 @@ "name": "cortex", "version": "3.0.0-RC2", "description": "A powerfull observable analysis engine", - "license": "AGPL-v3", + "license": "AGPL-3.0-or-later", "homepage": "https://github.com/TheHive-Project/Cortex", + "repository": "https://github.com/TheHive-Project/Cortex", "bin": { "cross-env": "./node_modules/cross-env/bin/cross-env.js", "webpack": "./node_modules/webpack/bin/webpack.js", @@ -15,65 +16,64 @@ "build": "cross-env NODE_ENV=production webpack -p --colors" }, "dependencies": { - "@uirouter/angularjs": "^1.0.12", - "angular": "1.6.8", + "@uirouter/angularjs": "^1.0.22", + "angular": "^1.7.8", "angular-base64-upload": "^0.1.23", "angular-bootstrap-multiselect": "git+https://github.com/bentorfs/angular-bootstrap-multiselect.git", - "angular-clipboard": "^1.6.2", - "angular-images-resizer": "^2.0.2", - "angular-input-masks": "^4.1.0", + "angular-clipboard": "^1.7.0", + "angular-images-resizer": "^2.0.3", + "angular-input-masks": "^4.3.0", "angular-local-storage": "^0.7.1", - "angular-messages": "1.6.8", - "angular-moment": "^1.2.0", - "angular-resource": "1.6.8", - "angular-sanitize": "1.6.8", + "angular-messages": "^1.7.8", + "angular-moment": "^1.3.0", + "angular-resource": "^1.7.8", + "angular-sanitize": "^1.7.8", "angular-ui-bootstrap": "^2.5.6", "angular-ui-notification": "^0.3.6", "angular-utils-pagination": "^0.11.1", + "bootstrap-sass": "^3.4.1", + "dropzone": "^5.5.1", + "es6-promise": "^4.2.6", + "font-awesome": "^4.7.0", + "jquery": "^3.4.1", + "lodash": "^4.17.11", + "moment": "^2.24.0", + "ng-storage": "^0.3.2", + "oclazyload": "^1.1.0", + "url": "^0.11.0" + }, + "engines": { + "node": ">=0.12.0" + }, + "devDependencies": { + "babel-eslint": "^8.2.1", + "babel-plugin-angularjs-annotate": "^0.5.3", "assets-webpack-plugin": "^3.4.0", "autoprefixer": "^6.5.0", - "babel-core": "^6.14.0", + "babel-core": "^6.26.3", "babel-loader": "^6.2.5", - "babel-preset-es2015": "^6.16.0", - "babel-preset-es2017": "^6.16.0", - "babel-preset-stage-1": "^6.16.0", + "babel-preset-es2015": "^6.24.1", + "babel-preset-es2017": "^6.24.1", + "babel-preset-stage-1": "^6.24.1", "baggage-loader": "^0.2.4", - "bootstrap-sass": "^3.3.7", "clean-webpack-plugin": "^0.1.10", "cross-env": "^3.0.0", "css-loader": "^0.25.0", "css-spaces": "^0.3.5", - "dropzone": "^5.2.0", - "es6-promise": "^4.0.3", "eslint": "^4.14.0", "eslint-loader": "^1.5.0", "extract-text-webpack-plugin": "^2.0.0-beta.4", "file-loader": "^0.9.0", - "font-awesome": "^4.7.0", "html-loader": "^0.4.4", "html-webpack-plugin": "^2.22.0", - "jquery": "^3.2.1", - "js-url": "^2.3.0", - "lodash": "^4.17.4", "manifest-revision-webpack-plugin": "^0.3.0", - "moment": "^2.20.1", - "ng-storage": "^0.3.2", "ngtemplate-loader": "^1.3.1", - "node-sass": "^4.11.0", - "oclazyload": "^1.1.0", + "node-sass": "^4.12.0", "postcss-loader": "^0.13.0", "sass-loader": "^4.0.2", "style-loader": "^0.13.1", - "url": "^0.11.0", "url-loader": "^0.5.7", "webpack": "^3.5.0", "webpack-dev-server": "^2.2.0" - }, - "engines": { - "node": ">=0.12.0" - }, - "devDependencies": { - "babel-eslint": "^8.2.1", - "babel-plugin-angularjs-annotate": "^0.5.3" } -} +} \ No newline at end of file diff --git a/www/src/app/components/user-dialog/user.edit.controller.js b/www/src/app/components/user-dialog/user.edit.controller.js index bc5617a86..d469058f4 100644 --- a/www/src/app/components/user-dialog/user.edit.controller.js +++ b/www/src/app/components/user-dialog/user.edit.controller.js @@ -35,14 +35,10 @@ export default class UserEditController { this.orgId = orgId; this.formData = _.defaults( - _.pick(this.user, 'id', 'name', 'roles', 'organization'), - { + _.pick(this.user, 'id', 'name', 'roles', 'organization'), { id: null, name: null, - roles: - orgId && orgId === 'cortex' - ? [Roles.SUPERADMIN] - : [Roles.READ, Roles.ANALYZE], + roles: orgId && orgId === 'cortex' ? [Roles.SUPERADMIN] : [Roles.READ, Roles.ANALYZE], organization: orgId } ); @@ -58,13 +54,13 @@ export default class UserEditController { } getRolesList(orgId) { - return orgId && orgId === 'cortex' - ? [[this.Roles.SUPERADMIN]] - : [ - [this.Roles.READ], - [this.Roles.READ, this.Roles.ANALYZE], - [this.Roles.READ, this.Roles.ANALYZE, this.Roles.ORGADMIN] - ]; + return orgId && orgId === 'cortex' ? [ + [this.Roles.SUPERADMIN] + ] : [ + [this.Roles.READ], + [this.Roles.READ, this.Roles.ANALYZE], + [this.Roles.READ, this.Roles.ANALYZE, this.Roles.ORGADMIN] + ]; } onOrgChange() { @@ -73,9 +69,7 @@ export default class UserEditController { this.rolesList = this.getRolesList(this.formData.organization); this.formData.roles = - this.formData.organization === 'cortex' - ? [this.Roles.SUPERADMIN] - : [this.Roles.READ, this.Roles.ANALYZE]; + this.formData.organization === 'cortex' ? [this.Roles.SUPERADMIN] : [this.Roles.READ, this.Roles.ANALYZE]; } onSuccess(data) { @@ -105,14 +99,18 @@ export default class UserEditController { if (this.user.id) { promise = this.UserService.update(this.user.id, postData); } else { - postData.login = angular.lowercase(this.formData.id); + postData.login = _.lowerCase(this.formData.id); promise = this.UserService.save(postData); } return promise .then(response => this.onSuccess(response.data)) .catch(rejection => { - const { data: { type } } = rejection; + const { + data: { + type + } + } = rejection; if (type === 'ConflictError') { form.login.$setValidity('exists', false); } else { @@ -120,4 +118,4 @@ export default class UserEditController { } }); } -} +} \ No newline at end of file diff --git a/www/src/app/pages/admin/common/user-dialog/user.edit.controller.js b/www/src/app/pages/admin/common/user-dialog/user.edit.controller.js index ad3d19eb4..4afe30b2c 100644 --- a/www/src/app/pages/admin/common/user-dialog/user.edit.controller.js +++ b/www/src/app/pages/admin/common/user-dialog/user.edit.controller.js @@ -35,14 +35,10 @@ export default class UserEditController { this.orgId = orgId; this.formData = _.defaults( - _.pick(this.user, 'id', 'name', 'roles', 'organization'), - { + _.pick(this.user, 'id', 'name', 'roles', 'organization'), { id: null, name: null, - roles: - orgId && orgId === 'cortex' - ? [Roles.SUPERADMIN] - : [Roles.READ, Roles.ANALYZE], + roles: orgId && orgId === 'cortex' ? [Roles.SUPERADMIN] : [Roles.READ, Roles.ANALYZE], organization: orgId } ); @@ -58,13 +54,13 @@ export default class UserEditController { } getRolesList(orgId) { - return orgId && orgId === 'cortex' - ? [[this.Roles.SUPERADMIN]] - : [ - [this.Roles.READ], - [this.Roles.READ, this.Roles.ANALYZE], - [this.Roles.READ, this.Roles.ANALYZE, this.Roles.ORGADMIN] - ]; + return orgId && orgId === 'cortex' ? [ + [this.Roles.SUPERADMIN] + ] : [ + [this.Roles.READ], + [this.Roles.READ, this.Roles.ANALYZE], + [this.Roles.READ, this.Roles.ANALYZE, this.Roles.ORGADMIN] + ]; } onOrgChange() { @@ -73,9 +69,7 @@ export default class UserEditController { this.rolesList = this.getRolesList(this.formData.organization); this.formData.roles = - this.formData.organization === 'cortex' - ? [this.Roles.SUPERADMIN] - : [this.Roles.READ, this.Roles.ANALYZE]; + this.formData.organization === 'cortex' ? [this.Roles.SUPERADMIN] : [this.Roles.READ, this.Roles.ANALYZE]; } onSuccess(data) { @@ -113,14 +107,18 @@ export default class UserEditController { if (this.user.id) { promise = this.UserService.update(this.user.id, postData); } else { - postData.login = angular.lowercase(this.formData.id); + postData.login = _.lowerCase(this.formData.id); promise = this.UserService.save(postData); } return promise .then(response => this.onSuccess(response.data)) .catch(rejection => { - const { data: { type } } = rejection; + const { + data: { + type + } + } = rejection; if (type === 'ConflictError') { form.login.$setValidity('exists', false); } else { @@ -128,4 +126,4 @@ export default class UserEditController { } }); } -} +} \ No newline at end of file diff --git a/www/src/app/pages/login/login.controller.js b/www/src/app/pages/login/login.controller.js index dc51b9273..0640d73ee 100644 --- a/www/src/app/pages/login/login.controller.js +++ b/www/src/app/pages/login/login.controller.js @@ -1,3 +1,4 @@ +import _ from 'lodash'; export default class LoginController { constructor( $log, @@ -26,7 +27,7 @@ export default class LoginController { } login() { - this.params.username = angular.lowercase(this.params.username); + this.params.username = _.lowerCase(this.params.username); this.AuthService.login(this.params.username, this.params.password) .then(() => this.$state.go('index')) diff --git a/www/src/app/pages/maintenance/maintenance.controller.js b/www/src/app/pages/maintenance/maintenance.controller.js index 1e2fdea1a..6344309f3 100644 --- a/www/src/app/pages/maintenance/maintenance.controller.js +++ b/www/src/app/pages/maintenance/maintenance.controller.js @@ -35,9 +35,7 @@ export default class MaintenanceController { this.migrating = true; this.$http .post( - './api/maintenance/migrate', - {}, - { + './api/maintenance/migrate', {}, { timeout: 10 * 60 * 60 * 1000 // 10 minutes } ) @@ -61,7 +59,7 @@ export default class MaintenanceController { createInitialUser() { this.UserService.save({ - login: angular.lowercase(this.newUser.login), + login: _.lowerCase(this.newUser.login), name: this.newUser.name, password: this.newUser.password, roles: ['superadmin'], @@ -110,4 +108,4 @@ export default class MaintenanceController { } }); } -} +} \ No newline at end of file From 49045a2eec2ef424e3e5131256e0d59762a0fd70 Mon Sep 17 00:00:00 2001 From: Nabil Adouani Date: Tue, 14 May 2019 11:16:25 +0200 Subject: [PATCH 04/17] #190 Remove unused libraries and fix some dependency vulns --- www/package.json | 2 - www/src/app/index.module.js | 1 - www/src/app/index.vendor.js | 2 - .../async-page-example/async.controller.js | 10 - .../app/pages/async-page-example/async.html | 27 - .../pages/async-page-example/async.module.js | 11 - .../app/pages/async-page-example/async.scss | 4 - www/yarn.lock | 7410 ----------------- 8 files changed, 7467 deletions(-) delete mode 100755 www/src/app/pages/async-page-example/async.controller.js delete mode 100755 www/src/app/pages/async-page-example/async.html delete mode 100755 www/src/app/pages/async-page-example/async.module.js delete mode 100644 www/src/app/pages/async-page-example/async.scss delete mode 100644 www/yarn.lock diff --git a/www/package.json b/www/package.json index a6461a06c..faa593832 100755 --- a/www/package.json +++ b/www/package.json @@ -38,8 +38,6 @@ "jquery": "^3.4.1", "lodash": "^4.17.11", "moment": "^2.24.0", - "ng-storage": "^0.3.2", - "oclazyload": "^1.1.0", "url": "^0.11.0" }, "engines": { diff --git a/www/src/app/index.module.js b/www/src/app/index.module.js index d1fc651ed..ad1d8c62b 100755 --- a/www/src/app/index.module.js +++ b/www/src/app/index.module.js @@ -25,7 +25,6 @@ const App = angular.module('cortex', [ 'ngSanitize', 'ngMessages', 'ngResource', - 'oc.lazyLoad', 'ui.bootstrap', 'ui-notification', 'angularUtils.directives.dirPagination', diff --git a/www/src/app/index.vendor.js b/www/src/app/index.vendor.js index 3d05a6d6c..b135a70d3 100755 --- a/www/src/app/index.vendor.js +++ b/www/src/app/index.vendor.js @@ -8,8 +8,6 @@ import '@uirouter/angularjs'; import 'angular-resource'; -import 'oclazyload'; - import 'angular-sanitize'; import 'angular-messages'; diff --git a/www/src/app/pages/async-page-example/async.controller.js b/www/src/app/pages/async-page-example/async.controller.js deleted file mode 100755 index 232f0b846..000000000 --- a/www/src/app/pages/async-page-example/async.controller.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict'; - -function MainController($log) { - 'ngInject'; - - $log.debug('Hello from Lazy Loaded controller!'); - -} - -export default MainController; diff --git a/www/src/app/pages/async-page-example/async.html b/www/src/app/pages/async-page-example/async.html deleted file mode 100755 index 635b96dbf..000000000 --- a/www/src/app/pages/async-page-example/async.html +++ /dev/null @@ -1,27 +0,0 @@ -
-
-

Hello, from the dark side Lazy Loaded page!!!

-

Just set resolve rule with require.ensure statement and then use angularOcLazyLoad to init module

-
-
- -
-    resolve: {
-        modulePreloading: function($q, $ocLazyLoad) {
-            "ngInject";
-
-            var deferred = $q.defer();
-
-            require.ensure([], function (require) {
-              var asyncModule = require('./async.module');
-              $ocLazyLoad.load({
-                name: asyncModule.default.name,
-              });
-
-              deferred.resolve(asyncModule.default.controller);
-            });
-
-            return deferred.promise;
-        }
-    }
-
\ No newline at end of file diff --git a/www/src/app/pages/async-page-example/async.module.js b/www/src/app/pages/async-page-example/async.module.js deleted file mode 100755 index 0c75e94d9..000000000 --- a/www/src/app/pages/async-page-example/async.module.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -import './async.scss'; - -import asyncController from './async.controller.js'; - -const asyncModule = angular.module('async-module', []); - -asyncModule.controller('asyncController', asyncController); - -export default asyncModule; \ No newline at end of file diff --git a/www/src/app/pages/async-page-example/async.scss b/www/src/app/pages/async-page-example/async.scss deleted file mode 100644 index fa3dbdcb0..000000000 --- a/www/src/app/pages/async-page-example/async.scss +++ /dev/null @@ -1,4 +0,0 @@ -.jumbotron.async-box { - background-color: #000; - color: #fff; -} \ No newline at end of file diff --git a/www/yarn.lock b/www/yarn.lock deleted file mode 100644 index c1c3915a8..000000000 --- a/www/yarn.lock +++ /dev/null @@ -1,7410 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@7.0.0-beta.36": - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.36.tgz#2349d7ec04b3a06945ae173280ef8579b63728e4" - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^3.0.0" - -"@babel/helper-function-name@7.0.0-beta.36": - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.36.tgz#366e3bc35147721b69009f803907c4d53212e88d" - dependencies: - "@babel/helper-get-function-arity" "7.0.0-beta.36" - "@babel/template" "7.0.0-beta.36" - "@babel/types" "7.0.0-beta.36" - -"@babel/helper-get-function-arity@7.0.0-beta.36": - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.36.tgz#f5383bac9a96b274828b10d98900e84ee43e32b8" - dependencies: - "@babel/types" "7.0.0-beta.36" - -"@babel/template@7.0.0-beta.36": - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.36.tgz#02e903de5d68bd7899bce3c5b5447e59529abb00" - dependencies: - "@babel/code-frame" "7.0.0-beta.36" - "@babel/types" "7.0.0-beta.36" - babylon "7.0.0-beta.36" - lodash "^4.2.0" - -"@babel/traverse@7.0.0-beta.36": - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.36.tgz#1dc6f8750e89b6b979de5fe44aa993b1a2192261" - dependencies: - "@babel/code-frame" "7.0.0-beta.36" - "@babel/helper-function-name" "7.0.0-beta.36" - "@babel/types" "7.0.0-beta.36" - babylon "7.0.0-beta.36" - debug "^3.0.1" - globals "^11.1.0" - invariant "^2.2.0" - lodash "^4.2.0" - -"@babel/types@7.0.0-beta.36": - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.36.tgz#64f2004353de42adb72f9ebb4665fc35b5499d23" - dependencies: - esutils "^2.0.2" - lodash "^4.2.0" - to-fast-properties "^2.0.0" - -"@uirouter/angularjs@^1.0.12": - version "1.0.12" - resolved "https://registry.yarnpkg.com/@uirouter/angularjs/-/angularjs-1.0.12.tgz#b2275b7e33e0024a485f96568a18d350539880f3" - dependencies: - "@uirouter/core" "5.0.13" - -"@uirouter/core@5.0.13": - version "5.0.13" - resolved "https://registry.yarnpkg.com/@uirouter/core/-/core-5.0.13.tgz#e1b31626c393cbdd82651755ff1ce3fc55163fd0" - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - -accepts@~1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" - dependencies: - mime-types "~2.1.16" - negotiator "0.6.1" - -acorn-dynamic-import@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" - dependencies: - acorn "^4.0.3" - -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - dependencies: - acorn "^3.0.4" - -acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - -acorn@^4.0.3: - version "4.0.13" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" - -acorn@^5.0.0, acorn@^5.2.1: - version "5.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" - -active-x-obfuscator@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/active-x-obfuscator/-/active-x-obfuscator-0.0.1.tgz#089b89b37145ff1d9ec74af6530be5526cae1f1a" - dependencies: - zeparser "0.0.5" - -ajv-keywords@^2.0.0, ajv-keywords@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" - -ajv@^4.9.1: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - -ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5, ajv@^5.2.3, ajv@^5.3.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - -align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" - -alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" - -amdefine@>=0.0.4: - version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - -angular-messages@1.6.8: - version "1.6.8" - resolved "https://registry.yarnpkg.com/angular-messages/-/angular-messages-1.6.8.tgz#4f1090b6ee38081fd073c5dfb7576016d18fc458" - -angular-resource@1.6.8: - version "1.6.8" - resolved "https://registry.yarnpkg.com/angular-resource/-/angular-resource-1.6.8.tgz#cc2172f8ec4a3a8340c43c600a5fed543e4168af" - -angular-sanitize@1.6.8: - version "1.6.8" - resolved "https://registry.yarnpkg.com/angular-sanitize/-/angular-sanitize-1.6.8.tgz#68175a1a5853a6439fffcb251a88a538a44a8e70" - -angular-ui-bootstrap@^2.5.6: - version "2.5.6" - resolved "https://registry.yarnpkg.com/angular-ui-bootstrap/-/angular-ui-bootstrap-2.5.6.tgz#23937322ec641a6fbee16498cc32452aa199e7c5" - -angular@1.6.8: - version "1.6.8" - resolved "https://registry.yarnpkg.com/angular/-/angular-1.6.8.tgz#5be378a58be91a5489e78b59c4518cd9fd273ffb" - -ansi-escapes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" - -ansi-gray@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" - dependencies: - ansi-wrap "0.1.0" - -ansi-html@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - -ansi-styles@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" - dependencies: - color-convert "^1.9.0" - -ansi-wrap@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" - -anymatch@^1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" - dependencies: - micromatch "^2.1.5" - normalize-path "^2.0.0" - -aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - -archive-type@^3.0.0, archive-type@^3.0.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/archive-type/-/archive-type-3.2.0.tgz#9cd9c006957ebe95fadad5bd6098942a813737f6" - dependencies: - file-type "^3.1.0" - -are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - -argparse@^1.0.7: - version "1.0.9" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" - dependencies: - sprintf-js "~1.0.2" - -"argparse@~ 0.1.11": - version "0.1.16" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-0.1.16.tgz#cfd01e0fbba3d6caed049fbd758d40f65196f57c" - dependencies: - underscore "~1.7.0" - underscore.string "~2.4.0" - -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - dependencies: - arr-flatten "^1.0.1" - -arr-flatten@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - -array-differ@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" - -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - -array-flatten@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.1.tgz#426bb9da84090c1838d812c8150af20a8331e296" - -array-includes@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" - dependencies: - define-properties "^1.1.2" - es-abstract "^1.7.0" - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - dependencies: - array-uniq "^1.0.1" - -array-uniq@^1.0.0, array-uniq@^1.0.1, array-uniq@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - -arrify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - -asn1.js@^4.0.0: - version "4.9.2" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.2.tgz#8117ef4f7ed87cd8f89044b5bff97ac243a16c9a" - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - -assert@^1.1.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" - dependencies: - util "0.10.3" - -assets-webpack-plugin@^3.4.0: - version "3.5.1" - resolved "https://registry.yarnpkg.com/assets-webpack-plugin/-/assets-webpack-plugin-3.5.1.tgz#931ce0d66d42e88ed5e7f18d65522943c57a387d" - dependencies: - camelcase "^1.2.1" - escape-string-regexp "^1.0.3" - lodash.assign "^3.2.0" - lodash.merge "^3.3.2" - mkdirp "^0.5.1" - -ast-types@0.9.6: - version "0.9.6" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" - -async-each-series@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/async-each-series/-/async-each-series-1.1.0.tgz#f42fd8155d38f21a5b8ea07c28e063ed1700b138" - -async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - -async-foreach@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" - -async@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - -async@^2.0.1, async@^2.1.2: - version "2.6.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" - dependencies: - lodash "^4.14.0" - -async@~0.1.22: - version "0.1.22" - resolved "https://registry.yarnpkg.com/async/-/async-0.1.22.tgz#0fc1aaa088a0e3ef0ebe2d8831bab0dcf8845061" - -async@~0.2.6, async@~0.2.9: - version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - -autoprefixer@^6.3.1, autoprefixer@^6.5.0: - version "6.7.7" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014" - dependencies: - browserslist "^1.7.6" - caniuse-db "^1.0.30000634" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^5.2.16" - postcss-value-parser "^3.2.3" - -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - -aws4@^1.2.1, aws4@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - -babel-code-frame@^6.11.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-core@^6.14.0, babel-core@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" - dependencies: - babel-code-frame "^6.26.0" - babel-generator "^6.26.0" - babel-helpers "^6.24.1" - babel-messages "^6.23.0" - babel-register "^6.26.0" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - convert-source-map "^1.5.0" - debug "^2.6.8" - json5 "^0.5.1" - lodash "^4.17.4" - minimatch "^3.0.4" - path-is-absolute "^1.0.1" - private "^0.1.7" - slash "^1.0.0" - source-map "^0.5.6" - -babel-eslint@^8.2.1: - version "8.2.1" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.1.tgz#136888f3c109edc65376c23ebf494f36a3e03951" - dependencies: - "@babel/code-frame" "7.0.0-beta.36" - "@babel/traverse" "7.0.0-beta.36" - "@babel/types" "7.0.0-beta.36" - babylon "7.0.0-beta.36" - eslint-scope "~3.7.1" - eslint-visitor-keys "^1.0.0" - -babel-generator@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.6" - trim-right "^1.0.1" - -babel-helper-bindify-decorators@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - dependencies: - babel-helper-explode-assignable-expression "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-call-delegate@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-define-map@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-explode-assignable-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-explode-class@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" - dependencies: - babel-helper-bindify-decorators "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - dependencies: - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-get-function-arity@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-hoist-variables@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-optimise-call-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-regex@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" - dependencies: - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-remap-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-replace-supers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - dependencies: - babel-helper-optimise-call-expression "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helpers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-loader@^6.2.5: - version "6.4.1" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.4.1.tgz#0b34112d5b0748a8dcdbf51acf6f9bd42d50b8ca" - dependencies: - find-cache-dir "^0.1.1" - loader-utils "^0.2.16" - mkdirp "^0.5.1" - object-assign "^4.0.1" - -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-angularjs-annotate@^0.5.2: - version "0.5.3" - resolved "https://registry.yarnpkg.com/babel-plugin-angularjs-annotate/-/babel-plugin-angularjs-annotate-0.5.3.tgz#1b3cd6d21adcb4f9865ea8592423639acab4fed9" - dependencies: - babel-plugin-transform-es2015-function-name "^6.9.0" - babel-types "^6.10.2" - simple-is "~0.2.0" - -babel-plugin-check-es2015-constants@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-syntax-async-functions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - -babel-plugin-syntax-async-generators@^6.5.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" - -babel-plugin-syntax-class-constructor-call@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" - -babel-plugin-syntax-class-properties@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" - -babel-plugin-syntax-decorators@^6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" - -babel-plugin-syntax-dynamic-import@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" - -babel-plugin-syntax-exponentiation-operator@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - -babel-plugin-syntax-export-extensions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" - -babel-plugin-syntax-object-rest-spread@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" - -babel-plugin-syntax-trailing-function-commas@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - -babel-plugin-transform-async-generator-functions@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-generators "^6.5.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-class-constructor-call@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" - dependencies: - babel-plugin-syntax-class-constructor-call "^6.18.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-class-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" - dependencies: - babel-helper-function-name "^6.24.1" - babel-plugin-syntax-class-properties "^6.8.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-decorators@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" - dependencies: - babel-helper-explode-class "^6.24.1" - babel-plugin-syntax-decorators "^6.13.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-arrow-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoping@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" - dependencies: - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-plugin-transform-es2015-classes@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" - dependencies: - babel-helper-define-map "^6.24.1" - babel-helper-function-name "^6.24.1" - babel-helper-optimise-call-expression "^6.24.1" - babel-helper-replace-supers "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-computed-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-destructuring@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-duplicate-keys@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-for-of@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-function-name@^6.24.1, babel-plugin-transform-es2015-function-name@^6.9.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-modules-amd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" - dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-commonjs@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" - dependencies: - babel-plugin-transform-strict-mode "^6.24.1" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-types "^6.26.0" - -babel-plugin-transform-es2015-modules-systemjs@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-umd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" - dependencies: - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-object-super@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" - dependencies: - babel-helper-replace-supers "^6.24.1" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-parameters@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" - dependencies: - babel-helper-call-delegate "^6.24.1" - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-shorthand-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-spread@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-sticky-regex@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-template-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-typeof-symbol@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-unicode-regex@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - regexpu-core "^2.0.0" - -babel-plugin-transform-exponentiation-operator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" - dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" - babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-export-extensions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" - dependencies: - babel-plugin-syntax-export-extensions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-object-rest-spread@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" - dependencies: - babel-plugin-syntax-object-rest-spread "^6.8.0" - babel-runtime "^6.26.0" - -babel-plugin-transform-regenerator@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" - dependencies: - regenerator-transform "^0.10.0" - -babel-plugin-transform-strict-mode@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-preset-es2015@^6.16.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.24.1" - babel-plugin-transform-es2015-classes "^6.24.1" - babel-plugin-transform-es2015-computed-properties "^6.24.1" - babel-plugin-transform-es2015-destructuring "^6.22.0" - babel-plugin-transform-es2015-duplicate-keys "^6.24.1" - babel-plugin-transform-es2015-for-of "^6.22.0" - babel-plugin-transform-es2015-function-name "^6.24.1" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-plugin-transform-es2015-modules-systemjs "^6.24.1" - babel-plugin-transform-es2015-modules-umd "^6.24.1" - babel-plugin-transform-es2015-object-super "^6.24.1" - babel-plugin-transform-es2015-parameters "^6.24.1" - babel-plugin-transform-es2015-shorthand-properties "^6.24.1" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.24.1" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.22.0" - babel-plugin-transform-es2015-unicode-regex "^6.24.1" - babel-plugin-transform-regenerator "^6.24.1" - -babel-preset-es2017@^6.16.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-es2017/-/babel-preset-es2017-6.24.1.tgz#597beadfb9f7f208bcfd8a12e9b2b29b8b2f14d1" - dependencies: - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-to-generator "^6.24.1" - -babel-preset-stage-1@^6.16.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0" - dependencies: - babel-plugin-transform-class-constructor-call "^6.24.1" - babel-plugin-transform-export-extensions "^6.22.0" - babel-preset-stage-2 "^6.24.1" - -babel-preset-stage-2@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" - dependencies: - babel-plugin-syntax-dynamic-import "^6.18.0" - babel-plugin-transform-class-properties "^6.24.1" - babel-plugin-transform-decorators "^6.24.1" - babel-preset-stage-3 "^6.24.1" - -babel-preset-stage-3@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" - dependencies: - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-generator-functions "^6.24.1" - babel-plugin-transform-async-to-generator "^6.24.1" - babel-plugin-transform-exponentiation-operator "^6.24.1" - babel-plugin-transform-object-rest-spread "^6.22.0" - -babel-register@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - dependencies: - babel-core "^6.26.0" - babel-runtime "^6.26.0" - core-js "^2.5.0" - home-or-tmp "^2.0.0" - lodash "^4.17.4" - mkdirp "^0.5.1" - source-map-support "^0.4.15" - -babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -babel-template@^6.24.1, babel-template@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - dependencies: - babel-runtime "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - lodash "^4.17.4" - -babel-traverse@^6.24.1, babel-traverse@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - -babel-types@^6.10.2, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - -babylon@7.0.0-beta.36: - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.36.tgz#3a3683ba6a9a1e02b0aa507c8e63435e39305b9e" - -babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - -baggage-loader@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/baggage-loader/-/baggage-loader-0.2.4.tgz#f99bc8c15b16f0d0468ba9d248ee98fad9032e06" - -balanced-match@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - -base64-js@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" - -base64id@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" - -batch@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" - -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - dependencies: - tweetnacl "^0.14.3" - -beeper@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" - -big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - -bin-build@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/bin-build/-/bin-build-2.2.0.tgz#11f8dd61f70ffcfa2bdcaa5b46f5e8fedd4221cc" - dependencies: - archive-type "^3.0.1" - decompress "^3.0.0" - download "^4.1.2" - exec-series "^1.0.0" - rimraf "^2.2.6" - tempfile "^1.0.0" - url-regex "^3.0.0" - -bin-check@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/bin-check/-/bin-check-2.0.0.tgz#86f8e6f4253893df60dc316957f5af02acb05930" - dependencies: - executable "^1.0.0" - -bin-version-check@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/bin-version-check/-/bin-version-check-2.1.0.tgz#e4e5df290b9069f7d111324031efc13fdd11a5b0" - dependencies: - bin-version "^1.0.0" - minimist "^1.1.0" - semver "^4.0.3" - semver-truncate "^1.0.0" - -bin-version@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/bin-version/-/bin-version-1.0.4.tgz#9eb498ee6fd76f7ab9a7c160436f89579435d78e" - dependencies: - find-versions "^1.0.0" - -bin-wrapper@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/bin-wrapper/-/bin-wrapper-3.0.2.tgz#67d3306262e4b1a5f2f88ee23464f6a655677aeb" - dependencies: - bin-check "^2.0.0" - bin-version-check "^2.1.0" - download "^4.0.0" - each-async "^1.1.1" - lazy-req "^1.0.0" - os-filter-obj "^1.0.0" - -binary-extensions@^1.0.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" - -bl@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e" - dependencies: - readable-stream "^2.0.5" - -bl@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e" - dependencies: - readable-stream "~2.0.5" - -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - dependencies: - inherits "~2.0.0" - -bluebird@^3.4.7: - version "3.5.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - -body-parser@1.18.2: - version "1.18.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" - dependencies: - bytes "3.0.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.1" - http-errors "~1.6.2" - iconv-lite "0.4.19" - on-finished "~2.3.0" - qs "6.5.1" - raw-body "2.3.2" - type-is "~1.6.15" - -bonjour@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" - dependencies: - array-flatten "^2.1.0" - deep-equal "^1.0.1" - dns-equal "^1.0.0" - dns-txt "^2.0.2" - multicast-dns "^6.0.1" - multicast-dns-service-types "^1.1.0" - -boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" - -boom@4.x.x: - version "4.3.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" - dependencies: - hoek "4.x.x" - -boom@5.x.x: - version "5.2.0" - resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" - dependencies: - hoek "4.x.x" - -bootstrap-sass@^3.3.7: - version "3.3.7" - resolved "https://registry.yarnpkg.com/bootstrap-sass/-/bootstrap-sass-3.3.7.tgz#6596c7ab40f6637393323ab0bc80d064fc630498" - -brace-expansion@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - -brorand@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f" - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - -browserify-rsa@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - dependencies: - bn.js "^4.1.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" - dependencies: - bn.js "^4.1.1" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.2" - elliptic "^6.0.0" - inherits "^2.0.1" - parse-asn1 "^5.0.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - dependencies: - pako "~1.0.5" - -browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: - version "1.7.7" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" - dependencies: - caniuse-db "^1.0.30000639" - electron-to-chromium "^1.2.7" - -buffer-crc32@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.1.tgz#be3e5382fc02b6d6324956ac1af98aa98b08534c" - -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - -buffer-indexof@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" - -buffer-to-vinyl@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-to-vinyl/-/buffer-to-vinyl-1.1.0.tgz#00f15faee3ab7a1dda2cde6d9121bffdd07b2262" - dependencies: - file-type "^3.1.0" - readable-stream "^2.0.2" - uuid "^2.0.1" - vinyl "^1.0.0" - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - -buffer@^4.3.0: - version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -builtin-modules@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - -bytes@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-0.2.0.tgz#aad33ec14e3dc2ca74e8e7d451f9ba053ad4f7a0" - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - dependencies: - callsites "^0.2.0" - -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - -camel-case@3.0.x: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" - dependencies: - no-case "^2.2.0" - upper-case "^1.1.1" - -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - -camelcase@^1.0.2, camelcase@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - -camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - -camelcase@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" - -camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - -caniuse-api@^1.5.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" - dependencies: - browserslist "^1.3.6" - caniuse-db "^1.0.30000529" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: - version "1.0.30000784" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000784.tgz#1be95012d9489c7719074f81aee57dbdffe6361b" - -capture-stack-trace@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" - -caseless@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - -caw@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/caw/-/caw-1.2.0.tgz#ffb226fe7efc547288dc62ee3e97073c212d1034" - dependencies: - get-proxy "^1.0.1" - is-obj "^1.0.0" - object-assign "^3.0.0" - tunnel-agent "^0.4.0" - -center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" - -chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" - dependencies: - ansi-styles "^3.1.0" - escape-string-regexp "^1.0.5" - supports-color "^4.0.0" - -chardet@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" - -chokidar@^1.6.0, chokidar@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" - dependencies: - anymatch "^1.3.0" - async-each "^1.0.0" - glob-parent "^2.0.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^2.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - optionalDependencies: - fsevents "^1.0.0" - -chokidar@~0.8.0: - version "0.8.4" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-0.8.4.tgz#3b2b5066817086534ba81a092bdcf4be25b8bee0" - optionalDependencies: - fsevents pipobscure/fsevents#7dcdf9fa3f8956610fd6f69f72c67bace2de7138 - recursive-readdir "0.0.2" - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -circular-json@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - -clap@^1.0.9: - version "1.2.3" - resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51" - dependencies: - chalk "^1.1.3" - -clean-css@4.1.x: - version "4.1.9" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.9.tgz#35cee8ae7687a49b98034f70de00c4edd3826301" - dependencies: - source-map "0.5.x" - -clean-webpack-plugin@^0.1.10: - version "0.1.17" - resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-0.1.17.tgz#71c57242e6d47204d46f809413176e7bed28ec49" - dependencies: - rimraf "^2.6.1" - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - dependencies: - restore-cursor "^2.0.0" - -cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" - -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - -clone-stats@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" - -clone@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" - -clone@^1.0.0, clone@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" - -co@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/co/-/co-3.1.0.tgz#4ea54ea5a08938153185e15210c68d9092bc1b78" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - -coa@~1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd" - dependencies: - q "^1.1.2" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - -coffee-script@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.3.3.tgz#150d6b4cb522894369efed6a2101c20bc7f4a4f4" - -coffee-script@~1.6: - version "1.6.3" - resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.6.3.tgz#6355d32cf1b04cdff6b484e5e711782b2f0c39be" - -coffee-script@~1.7: - version "1.7.1" - resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.7.1.tgz#62996a861780c75e6d5069d13822723b73404bfc" - dependencies: - mkdirp "~0.3.5" - -color-convert@^1.3.0, color-convert@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" - dependencies: - color-name "^1.1.1" - -color-name@^1.0.0, color-name@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - -color-string@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" - dependencies: - color-name "^1.0.0" - -color-support@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - -color@^0.11.0: - version "0.11.4" - resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" - dependencies: - clone "^1.0.2" - color-convert "^1.3.0" - color-string "^0.3.0" - -colormin@^1.0.5: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" - dependencies: - color "^0.11.0" - css-color-names "0.0.4" - has "^1.0.1" - -colors@0.6.0-1: - version "0.6.0-1" - resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.0-1.tgz#6dbb68ceb8bc60f2b313dcc5ce1599f06d19e67a" - -colors@0.x.x, colors@~0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" - -colors@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" - -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" - dependencies: - delayed-stream "~1.0.0" - -commander@2.12.x, commander@^2.9.0, commander@~2.12.1: - version "2.12.2" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" - -commander@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" - -commander@~2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" - dependencies: - graceful-readlink ">= 1.0.0" - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - -compressible@~2.0.11: - version "2.0.12" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.12.tgz#c59a5c99db76767e9876500e271ef63b3493bd66" - dependencies: - mime-db ">= 1.30.0 < 2" - -compression@^1.5.2: - version "1.7.1" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.1.tgz#eff2603efc2e22cf86f35d2eb93589f9875373db" - dependencies: - accepts "~1.3.4" - bytes "3.0.0" - compressible "~2.0.11" - debug "2.6.9" - on-headers "~1.0.1" - safe-buffer "5.1.1" - vary "~1.1.2" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -concat-stream@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" - dependencies: - inherits "~2.0.1" - readable-stream "~2.0.0" - typedarray "~0.0.5" - -concat-stream@^1.4.6, concat-stream@^1.4.7, concat-stream@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -connect-history-api-fallback@^1.3.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" - -connect@~2.8.4: - version "2.8.8" - resolved "https://registry.yarnpkg.com/connect/-/connect-2.8.8.tgz#b9abf8caf0bd9773cb3dea29344119872582446d" - dependencies: - buffer-crc32 "0.2.1" - bytes "0.2.0" - cookie "0.1.0" - cookie-signature "1.0.1" - debug "*" - formidable "1.0.14" - fresh "0.2.0" - methods "0.0.1" - pause "0.0.1" - qs "0.6.5" - send "0.1.4" - uid2 "0.0.2" - -console-browserify@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" - dependencies: - date-now "^0.1.4" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - -console-stream@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/console-stream/-/console-stream-0.1.1.tgz#a095fe07b20465955f2fafd28b5d72bccd949d44" - -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - -content-disposition@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - -convert-source-map@^1.1.1, convert-source-map@^1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" - -cookie-signature@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.1.tgz#44e072148af01e6e8e24afbf12690d68ae698ecb" - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - -cookie@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.1.0.tgz#90eb469ddce905c866de687efc43131d8801f9d0" - -cookie@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" - -core-js@^2.4.0, core-js@^2.5.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -create-ecdh@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" - dependencies: - bn.js "^4.1.0" - elliptic "^6.0.0" - -create-error-class@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" - dependencies: - capture-stack-trace "^1.0.0" - -create-hash@^1.1.0, create-hash@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - ripemd160 "^2.0.0" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: - version "1.1.6" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cross-env@^3.0.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-3.2.4.tgz#9e0585f277864ed421ce756f81a980ff0d698aba" - dependencies: - cross-spawn "^5.1.0" - is-windows "^1.0.0" - -cross-spawn@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" - dependencies: - lru-cache "^4.0.1" - which "^1.2.9" - -cross-spawn@^5.0.1, cross-spawn@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" - -cryptiles@3.x.x: - version "3.1.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" - dependencies: - boom "5.x.x" - -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -css-color-names@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" - -css-loader@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.25.0.tgz#c3febc8ce28f4c83576b6b13707f47f90c390223" - dependencies: - babel-code-frame "^6.11.0" - css-selector-tokenizer "^0.6.0" - cssnano ">=2.6.1 <4" - loader-utils "~0.2.2" - lodash.camelcase "^3.0.1" - object-assign "^4.0.1" - postcss "^5.0.6" - postcss-modules-extract-imports "^1.0.0" - postcss-modules-local-by-default "^1.0.1" - postcss-modules-scope "^1.0.0" - postcss-modules-values "^1.1.0" - source-list-map "^0.1.4" - -css-select@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" - dependencies: - boolbase "~1.0.0" - css-what "2.1" - domutils "1.5.1" - nth-check "~1.0.1" - -css-selector-tokenizer@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.6.0.tgz#6445f582c7930d241dcc5007a43d6fcb8f073152" - dependencies: - cssesc "^0.1.0" - fastparse "^1.1.1" - regexpu-core "^1.0.0" - -css-selector-tokenizer@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" - dependencies: - cssesc "^0.1.0" - fastparse "^1.1.1" - regexpu-core "^1.0.0" - -css-what@2.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" - -cssesc@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" - -"cssnano@>=2.6.1 <4": - version "3.10.0" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38" - dependencies: - autoprefixer "^6.3.1" - decamelize "^1.1.2" - defined "^1.0.0" - has "^1.0.1" - object-assign "^4.0.1" - postcss "^5.0.14" - postcss-calc "^5.2.0" - postcss-colormin "^2.1.8" - postcss-convert-values "^2.3.4" - postcss-discard-comments "^2.0.4" - postcss-discard-duplicates "^2.0.1" - postcss-discard-empty "^2.0.1" - postcss-discard-overridden "^0.1.1" - postcss-discard-unused "^2.2.1" - postcss-filter-plugins "^2.0.0" - postcss-merge-idents "^2.1.5" - postcss-merge-longhand "^2.0.1" - postcss-merge-rules "^2.0.3" - postcss-minify-font-values "^1.0.2" - postcss-minify-gradients "^1.0.1" - postcss-minify-params "^1.0.4" - postcss-minify-selectors "^2.0.4" - postcss-normalize-charset "^1.1.0" - postcss-normalize-url "^3.0.7" - postcss-ordered-values "^2.1.0" - postcss-reduce-idents "^2.2.2" - postcss-reduce-initial "^1.0.0" - postcss-reduce-transforms "^1.0.3" - postcss-svgo "^2.1.1" - postcss-unique-selectors "^2.0.2" - postcss-value-parser "^3.2.3" - postcss-zindex "^2.0.1" - -csso@~2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85" - dependencies: - clap "^1.0.9" - source-map "^0.5.3" - -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - dependencies: - array-find-index "^1.0.1" - -d@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" - dependencies: - es5-ext "^0.10.9" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - -date-now@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" - -dateformat@1.0.2-1.2.3: - version "1.0.2-1.2.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.2-1.2.3.tgz#b0220c02de98617433b72851cf47de3df2cdbee9" - -dateformat@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" - -debug@*, debug@^3.0.1, debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - dependencies: - ms "2.0.0" - -debug@0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" - -debug@2.6.9, debug@^2.2.0, debug@^2.6.6, debug@^2.6.8: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - -decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - -decompress-tar@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-3.1.0.tgz#217c789f9b94450efaadc5c5e537978fc333c466" - dependencies: - is-tar "^1.0.0" - object-assign "^2.0.0" - strip-dirs "^1.0.0" - tar-stream "^1.1.1" - through2 "^0.6.1" - vinyl "^0.4.3" - -decompress-tarbz2@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-3.1.0.tgz#8b23935681355f9f189d87256a0f8bdd96d9666d" - dependencies: - is-bzip2 "^1.0.0" - object-assign "^2.0.0" - seek-bzip "^1.0.3" - strip-dirs "^1.0.0" - tar-stream "^1.1.1" - through2 "^0.6.1" - vinyl "^0.4.3" - -decompress-targz@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-3.1.0.tgz#b2c13df98166268991b715d6447f642e9696f5a0" - dependencies: - is-gzip "^1.0.0" - object-assign "^2.0.0" - strip-dirs "^1.0.0" - tar-stream "^1.1.1" - through2 "^0.6.1" - vinyl "^0.4.3" - -decompress-unzip@^3.0.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-3.4.0.tgz#61475b4152066bbe3fee12f9d629d15fe6478eeb" - dependencies: - is-zip "^1.0.0" - read-all-stream "^3.0.0" - stat-mode "^0.2.0" - strip-dirs "^1.0.0" - through2 "^2.0.0" - vinyl "^1.0.0" - yauzl "^2.2.1" - -decompress@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/decompress/-/decompress-3.0.0.tgz#af1dd50d06e3bfc432461d37de11b38c0d991bed" - dependencies: - buffer-to-vinyl "^1.0.0" - concat-stream "^1.4.6" - decompress-tar "^3.0.0" - decompress-tarbz2 "^3.0.0" - decompress-targz "^3.0.0" - decompress-unzip "^3.0.0" - stream-combiner2 "^1.1.1" - vinyl-assign "^1.0.1" - vinyl-fs "^2.2.0" - -deep-equal@*, deep-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" - -deep-extend@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - -define-properties@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" - dependencies: - foreach "^2.0.5" - object-keys "^1.0.8" - -defined@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - -del@^2.0.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" - dependencies: - globby "^5.0.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - rimraf "^2.2.8" - -del@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5" - dependencies: - globby "^6.1.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - p-map "^1.1.1" - pify "^3.0.0" - rimraf "^2.2.8" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - -depd@1.1.1, depd@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" - -des.js@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - dependencies: - repeating "^2.0.0" - -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - -detect-node@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" - -di@~0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" - -diffie-hellman@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dns-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" - -dns-packet@^1.0.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.2.2.tgz#a8a26bec7646438963fc86e06f8f8b16d6c8bf7a" - dependencies: - ip "^1.1.0" - safe-buffer "^5.0.1" - -dns-txt@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" - dependencies: - buffer-indexof "^1.0.0" - -doctrine@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.2.tgz#68f96ce8efc56cc42651f1faadb4f175273b0075" - dependencies: - esutils "^2.0.2" - -dom-converter@~0.1: - version "0.1.4" - resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b" - dependencies: - utila "~0.3" - -dom-serializer@0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" - dependencies: - domelementtype "~1.1.1" - entities "~1.1.1" - -domain-browser@^1.1.1: - version "1.1.7" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" - -domelementtype@1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" - -domelementtype@~1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" - -domhandler@2.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.1.0.tgz#d2646f5e57f6c3bab11cf6cb05d3c0acf7412594" - dependencies: - domelementtype "1" - -domutils@1.1: - version "1.1.6" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485" - dependencies: - domelementtype "1" - -domutils@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" - dependencies: - dom-serializer "0" - domelementtype "1" - -download@^4.0.0, download@^4.1.2: - version "4.4.3" - resolved "https://registry.yarnpkg.com/download/-/download-4.4.3.tgz#aa55fdad392d95d4b68e8c2be03e0c2aa21ba9ac" - dependencies: - caw "^1.0.1" - concat-stream "^1.4.7" - each-async "^1.0.0" - filenamify "^1.0.1" - got "^5.0.0" - gulp-decompress "^1.2.0" - gulp-rename "^1.2.0" - is-url "^1.2.0" - object-assign "^4.0.1" - read-all-stream "^3.0.0" - readable-stream "^2.0.2" - stream-combiner2 "^1.1.1" - vinyl "^1.0.0" - vinyl-fs "^2.2.0" - ware "^1.2.0" - -duplexer2@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" - dependencies: - readable-stream "~1.1.9" - -duplexer2@^0.1.4, duplexer2@~0.1.0: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" - dependencies: - readable-stream "^2.0.2" - -duplexify@^3.2.0: - version "3.5.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.1.tgz#4e1516be68838bc90a49994f0b39a6e5960befcd" - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - -each-async@^1.0.0, each-async@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/each-async/-/each-async-1.1.1.tgz#dee5229bdf0ab6ba2012a395e1b869abf8813473" - dependencies: - onetime "^1.0.0" - set-immediate-shim "^1.0.0" - -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - dependencies: - jsbn "~0.1.0" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - -electron-releases@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/electron-releases/-/electron-releases-2.1.0.tgz#c5614bf811f176ce3c836e368a0625782341fd4e" - -electron-to-chromium@^1.2.7: - version "1.3.30" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.30.tgz#9666f532a64586651fc56a72513692e820d06a80" - dependencies: - electron-releases "^2.1.0" - -elliptic@^6.0.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - hmac-drbg "^1.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.0" - -emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - -encodeurl@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" - -end-of-stream@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206" - dependencies: - once "^1.4.0" - -enhanced-resolve@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.4.0" - object-assign "^4.0.1" - tapable "^0.2.7" - -entities@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" - -errno@^0.1.3: - version "0.1.6" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.6.tgz#c386ce8a6283f14fc09563b71560908c9bf53026" - dependencies: - prr "~1.0.1" - -error-ex@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.7.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" - dependencies: - es-to-primitive "^1.1.1" - function-bind "^1.1.1" - has "^1.0.1" - is-callable "^1.1.3" - is-regex "^1.0.4" - -es-to-primitive@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" - dependencies: - is-callable "^1.1.1" - is-date-object "^1.0.1" - is-symbol "^1.0.1" - -es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.37" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.37.tgz#0ee741d148b80069ba27d020393756af257defc3" - dependencies: - es6-iterator "~2.0.1" - es6-symbol "~3.1.1" - -es6-iterator@^2.0.1, es6-iterator@~2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-map@^0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - -es6-promise@^4.0.3: - version "4.2.2" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.2.tgz#f722d7769af88bd33bc13ec6605e1f92966b82d9" - -es6-set@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" - -es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - dependencies: - d "1" - es5-ext "~0.10.14" - -es6-templates@^0.2.2: - version "0.2.3" - resolved "https://registry.yarnpkg.com/es6-templates/-/es6-templates-0.2.3.tgz#5cb9ac9fb1ded6eb1239342b81d792bbb4078ee4" - dependencies: - recast "~0.11.12" - through "~2.3.6" - -es6-weak-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-iterator "^2.0.1" - es6-symbol "^3.1.1" - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - -escope@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" - dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-loader@^1.5.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-1.9.0.tgz#7e1be9feddca328d3dcfaef1ad49d5beffe83a13" - dependencies: - loader-fs-cache "^1.0.0" - loader-utils "^1.0.2" - object-assign "^4.0.1" - object-hash "^1.1.4" - rimraf "^2.6.1" - -eslint-scope@^3.7.1, eslint-scope@~3.7.1: - version "3.7.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-visitor-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" - -eslint@^4.14.0: - version "4.14.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.14.0.tgz#96609768d1dd23304faba2d94b7fefe5a5447a82" - dependencies: - ajv "^5.3.0" - babel-code-frame "^6.22.0" - chalk "^2.1.0" - concat-stream "^1.6.0" - cross-spawn "^5.1.0" - debug "^3.1.0" - doctrine "^2.0.2" - eslint-scope "^3.7.1" - eslint-visitor-keys "^1.0.0" - espree "^3.5.2" - esquery "^1.0.0" - esutils "^2.0.2" - file-entry-cache "^2.0.0" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.0.1" - ignore "^3.3.3" - imurmurhash "^0.1.4" - inquirer "^3.0.6" - is-resolvable "^1.0.0" - js-yaml "^3.9.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.4" - minimatch "^3.0.2" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - pluralize "^7.0.0" - progress "^2.0.0" - require-uncached "^1.0.3" - semver "^5.3.0" - strip-ansi "^4.0.0" - strip-json-comments "~2.0.1" - table "^4.0.1" - text-table "~0.2.0" - -espree@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.2.tgz#756ada8b979e9dcfcdb30aad8d1a9304a905e1ca" - dependencies: - acorn "^5.2.1" - acorn-jsx "^3.0.0" - -esprima@^2.6.0: - version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - -esprima@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" - -"esprima@~ 1.0.2": - version "1.0.4" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad" - -esprima@~3.1.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - -esquery@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" - dependencies: - estraverse "^4.0.0" - -esrecurse@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" - dependencies: - estraverse "^4.1.0" - object-assign "^4.0.1" - -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - -event-emitter@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - dependencies: - d "1" - es5-ext "~0.10.14" - -eventemitter2@~0.4.13: - version "0.4.14" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" - -eventemitter3@1.x.x: - version "1.2.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" - -events@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - -eventsource@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" - dependencies: - original ">=0.0.5" - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -exec-buffer@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/exec-buffer/-/exec-buffer-3.2.0.tgz#b1686dbd904c7cf982e652c1f5a79b1e5573082b" - dependencies: - execa "^0.7.0" - p-finally "^1.0.0" - pify "^3.0.0" - rimraf "^2.5.4" - tempfile "^2.0.0" - -exec-series@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/exec-series/-/exec-series-1.0.3.tgz#6d257a9beac482a872c7783bc8615839fc77143a" - dependencies: - async-each-series "^1.1.0" - object-assign "^4.1.0" - -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -executable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/executable/-/executable-1.1.0.tgz#877980e9112f3391066da37265de7ad8434ab4d9" - dependencies: - meow "^3.1.0" - -exit@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - dependencies: - is-posix-bracket "^0.1.0" - -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - dependencies: - fill-range "^2.1.0" - -express@^4.16.2: - version "4.16.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" - dependencies: - accepts "~1.3.4" - array-flatten "1.1.1" - body-parser "1.18.2" - content-disposition "0.5.2" - content-type "~1.0.4" - cookie "0.3.1" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.1" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.1.0" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.2" - path-to-regexp "0.1.7" - proxy-addr "~2.0.2" - qs "6.5.1" - range-parser "~1.2.0" - safe-buffer "5.1.1" - send "0.16.1" - serve-static "1.13.1" - setprototypeof "1.1.0" - statuses "~1.3.1" - type-is "~1.6.15" - utils-merge "1.0.1" - vary "~1.1.2" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - dependencies: - is-extendable "^0.1.0" - -extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - -external-editor@^2.0.4: - version "2.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" - dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" - tmp "^0.0.33" - -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - dependencies: - is-extglob "^1.0.0" - -extract-text-webpack-plugin@^2.0.0-beta.4: - version "2.1.2" - resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-2.1.2.tgz#756ef4efa8155c3681833fbc34da53b941746d6c" - dependencies: - async "^2.1.2" - loader-utils "^1.0.2" - schema-utils "^0.3.0" - webpack-sources "^1.0.1" - -extract-zip@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" - dependencies: - concat-stream "1.5.0" - debug "0.7.4" - mkdirp "0.5.0" - yauzl "2.4.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - -fancy-log@^1.1.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.2.tgz#f41125e3d84f2e7d89a43d06d958c8f78be16be1" - dependencies: - ansi-gray "^0.1.1" - color-support "^1.1.3" - time-stamp "^1.0.0" - -fast-deep-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - -fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - -fastparse@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" - -faye-websocket@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" - dependencies: - websocket-driver ">=0.5.1" - -faye-websocket@~0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" - dependencies: - websocket-driver ">=0.5.1" - -fd-slicer@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" - dependencies: - pend "~1.2.0" - -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" - dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" - -file-loader@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.9.0.tgz#1d2daddd424ce6d1b07cfe3f79731bed3617ab42" - dependencies: - loader-utils "~0.2.5" - -file-type@^3.1.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" - -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - -filename-reserved-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz#e61cf805f0de1c984567d0386dc5df50ee5af7e4" - -filenamify@^1.0.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-1.2.1.tgz#a9f2ffd11c503bed300015029272378f1f1365a5" - dependencies: - filename-reserved-regex "^1.0.0" - strip-outer "^1.0.0" - trim-repeated "^1.0.0" - -fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^1.1.3" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - -finalhandler@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" - dependencies: - debug "2.6.9" - encodeurl "~1.0.1" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.2" - statuses "~1.3.1" - unpipe "~1.0.0" - -find-cache-dir@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" - dependencies: - commondir "^1.0.1" - mkdirp "^0.5.1" - pkg-dir "^1.0.0" - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - dependencies: - locate-path "^2.0.0" - -find-versions@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-1.2.1.tgz#cbde9f12e38575a0af1be1b9a2c5d5fd8f186b62" - dependencies: - array-uniq "^1.0.0" - get-stdin "^4.0.1" - meow "^3.5.0" - semver-regex "^1.0.0" - -findup-sync@~0.1.0, findup-sync@~0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.1.3.tgz#7f3e7a97b82392c653bf06589bd85190e93c3683" - dependencies: - glob "~3.2.9" - lodash "~2.4.1" - -first-chunk-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" - -flat-cache@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" - dependencies: - circular-json "^0.3.1" - del "^2.0.2" - graceful-fs "^4.1.2" - write "^0.2.1" - -flatten@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" - -font-awesome@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133" - -for-in@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - dependencies: - for-in "^1.0.1" - -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - -foreachasync@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/foreachasync/-/foreachasync-3.0.0.tgz#5502987dc8714be3392097f32e0071c9dee07cf6" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@~1.0.0-rc3: - version "1.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" - dependencies: - async "^2.0.1" - combined-stream "^1.0.5" - mime-types "^2.1.11" - -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - -form-data@~2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - -formidable@1.0.14: - version "1.0.14" - resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.0.14.tgz#2b3f4c411cbb5fdd695c44843e2a23514a43231a" - -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - -fresh@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.2.0.tgz#bfd9402cf3df12c4a4c310c79f99a3dde13d34a7" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - -fs-extra@~0.26.4: - version "0.26.7" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -fsevents@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" - dependencies: - nan "^2.3.0" - node-pre-gyp "^0.6.39" - -fsevents@pipobscure/fsevents#7dcdf9fa3f8956610fd6f69f72c67bace2de7138: - version "0.2.1" - resolved "https://codeload.github.com/pipobscure/fsevents/tar.gz/7dcdf9fa3f8956610fd6f69f72c67bace2de7138" - dependencies: - nan "~0.8.0" - -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - -function-bind@^1.0.2, function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -gaze@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105" - dependencies: - globule "^1.0.0" - -generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - -get-caller-file@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" - -get-proxy@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/get-proxy/-/get-proxy-1.1.0.tgz#894854491bc591b0f147d7ae570f5c678b7256eb" - dependencies: - rc "^1.1.2" - -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - -getobject@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/getobject/-/getobject-0.1.0.tgz#047a449789fa160d018f5486ed91320b6ec7885c" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" - -glob-parent@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-stream@^5.3.2: - version "5.3.5" - resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22" - dependencies: - extend "^3.0.0" - glob "^5.0.3" - glob-parent "^3.0.0" - micromatch "^2.3.7" - ordered-read-streams "^0.3.0" - through2 "^0.6.0" - to-absolute-glob "^0.1.1" - unique-stream "^2.0.2" - -glob@^5.0.3: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@~7.1.1: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@~3.1.21: - version "3.1.21" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd" - dependencies: - graceful-fs "~1.2.0" - inherits "1" - minimatch "~0.2.11" - -glob@~3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" - dependencies: - inherits "2" - minimatch "0.3" - -globals@^11.0.1, globals@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.1.0.tgz#632644457f5f0e3ae711807183700ebf2e4633e4" - -globals@^9.18.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - -globby@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" - dependencies: - array-union "^1.0.1" - arrify "^1.0.0" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -globule@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.0.tgz#1dc49c6822dd9e8a2fa00ba2a295006e8664bd09" - dependencies: - glob "~7.1.1" - lodash "~4.17.4" - minimatch "~3.0.2" - -glogg@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5" - dependencies: - sparkles "^1.0.0" - -got@^5.0.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35" - dependencies: - create-error-class "^3.0.1" - duplexer2 "^0.1.4" - is-redirect "^1.0.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - lowercase-keys "^1.0.0" - node-status-codes "^1.0.0" - object-assign "^4.0.1" - parse-json "^2.1.0" - pinkie-promise "^2.0.0" - read-all-stream "^3.0.0" - readable-stream "^2.0.5" - timed-out "^3.0.0" - unzip-response "^1.0.2" - url-parse-lax "^1.0.0" - -graceful-fs@^4.0.0, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - -graceful-fs@~1, graceful-fs@~1.2.0, graceful-fs@~1.2.1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" - -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - -grunt-cli@^0.1.11: - version "0.1.13" - resolved "https://registry.yarnpkg.com/grunt-cli/-/grunt-cli-0.1.13.tgz#e9ebc4047631f5012d922770c39378133cad10f4" - dependencies: - findup-sync "~0.1.0" - nopt "~1.0.10" - resolve "~0.3.1" - -grunt-contrib-uglify@^0.2.7: - version "0.2.7" - resolved "https://registry.yarnpkg.com/grunt-contrib-uglify/-/grunt-contrib-uglify-0.2.7.tgz#e6bda51e0c40a1459f6cead423c65efd725a1bf7" - dependencies: - grunt-lib-contrib "~0.6.1" - uglify-js "~2.4.0" - -grunt-karma@^0.7.2: - version "0.7.3" - resolved "https://registry.yarnpkg.com/grunt-karma/-/grunt-karma-0.7.3.tgz#938f86b4ac4c5e0e347cabc56fb47720c5a7b060" - dependencies: - lodash "~2.4.1" - optimist "~0.6.1" - -grunt-legacy-log-utils@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz#c0706b9dd9064e116f36f23fe4e6b048672c0f7e" - dependencies: - colors "~0.6.2" - lodash "~2.4.1" - underscore.string "~2.3.3" - -grunt-legacy-log@~0.1.0: - version "0.1.3" - resolved "https://registry.yarnpkg.com/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz#ec29426e803021af59029f87d2f9cd7335a05531" - dependencies: - colors "~0.6.2" - grunt-legacy-log-utils "~0.1.1" - hooker "~0.2.3" - lodash "~2.4.1" - underscore.string "~2.3.3" - -grunt-legacy-util@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz#93324884dbf7e37a9ff7c026dff451d94a9e554b" - dependencies: - async "~0.1.22" - exit "~0.1.1" - getobject "~0.1.0" - hooker "~0.2.3" - lodash "~0.9.2" - underscore.string "~2.2.1" - which "~1.0.5" - -grunt-lib-contrib@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/grunt-lib-contrib/-/grunt-lib-contrib-0.6.1.tgz#3f56adb7da06e814795ee2415b0ebe5fb8903ebb" - dependencies: - zlib-browserify "0.0.1" - -grunt@^0.4.2: - version "0.4.5" - resolved "https://registry.yarnpkg.com/grunt/-/grunt-0.4.5.tgz#56937cd5194324adff6d207631832a9d6ba4e7f0" - dependencies: - async "~0.1.22" - coffee-script "~1.3.3" - colors "~0.6.2" - dateformat "1.0.2-1.2.3" - eventemitter2 "~0.4.13" - exit "~0.1.1" - findup-sync "~0.1.2" - getobject "~0.1.0" - glob "~3.1.21" - grunt-legacy-log "~0.1.0" - grunt-legacy-util "~0.2.0" - hooker "~0.2.3" - iconv-lite "~0.2.11" - js-yaml "~2.0.5" - lodash "~0.9.2" - minimatch "~0.2.12" - nopt "~1.0.10" - rimraf "~2.2.8" - underscore.string "~2.2.1" - which "~1.0.5" - -gulp-decompress@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/gulp-decompress/-/gulp-decompress-1.2.0.tgz#8eeb65a5e015f8ed8532cafe28454960626f0dc7" - dependencies: - archive-type "^3.0.0" - decompress "^3.0.0" - gulp-util "^3.0.1" - readable-stream "^2.0.2" - -gulp-rename@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/gulp-rename/-/gulp-rename-1.2.2.tgz#3ad4428763f05e2764dec1c67d868db275687817" - -gulp-sourcemaps@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c" - dependencies: - convert-source-map "^1.1.1" - graceful-fs "^4.1.2" - strip-bom "^2.0.0" - through2 "^2.0.0" - vinyl "^1.0.0" - -gulp-util@^3.0.1: - version "3.0.8" - resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" - dependencies: - array-differ "^1.0.0" - array-uniq "^1.0.2" - beeper "^1.0.0" - chalk "^1.0.0" - dateformat "^2.0.0" - fancy-log "^1.1.0" - gulplog "^1.0.0" - has-gulplog "^0.1.0" - lodash._reescape "^3.0.0" - lodash._reevaluate "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.template "^3.0.0" - minimist "^1.1.0" - multipipe "^0.1.2" - object-assign "^3.0.0" - replace-ext "0.0.1" - through2 "^2.0.0" - vinyl "^0.5.0" - -gulplog@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5" - dependencies: - glogg "^1.0.0" - -handle-thing@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" - -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - -har-validator@~2.0.2: - version "2.0.6" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" - dependencies: - chalk "^1.1.1" - commander "^2.9.0" - is-my-json-valid "^2.12.4" - pinkie-promise "^2.0.0" - -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" - dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" - -har-validator@~5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" - dependencies: - ajv "^5.1.0" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - dependencies: - ansi-regex "^2.0.0" - -has-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" - -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" - -has-gulplog@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" - dependencies: - sparkles "^1.0.0" - -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - -has@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" - dependencies: - function-bind "^1.0.2" - -hash-base@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" - dependencies: - inherits "^2.0.1" - -hash-base@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.0" - -hasha@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" - dependencies: - is-stream "^1.0.1" - pinkie-promise "^2.0.0" - -hawk@3.1.3, hawk@~3.1.0, hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - -hawk@~6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" - dependencies: - boom "4.x.x" - cryptiles "3.x.x" - hoek "4.x.x" - sntp "2.x.x" - -he@1.1.x: - version "1.1.1" - resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" - -hmac-drbg@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - -hoek@4.x.x: - version "4.2.0" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" - -home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" - -hooker@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/hooker/-/hooker-0.2.3.tgz#b834f723cc4a242aa65963459df6d984c5d3d959" - -hosted-git-info@^2.1.4: - version "2.5.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" - -hpack.js@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" - dependencies: - inherits "^2.0.1" - obuf "^1.0.0" - readable-stream "^2.0.1" - wbuf "^1.1.0" - -html-comment-regex@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" - -html-entities@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" - -html-loader@^0.4.4: - version "0.4.5" - resolved "https://registry.yarnpkg.com/html-loader/-/html-loader-0.4.5.tgz#5fbcd87cd63a5c49a7fce2fe56f425e05729c68c" - dependencies: - es6-templates "^0.2.2" - fastparse "^1.1.1" - html-minifier "^3.0.1" - loader-utils "^1.0.2" - object-assign "^4.1.0" - -html-minifier@^3.0.1, html-minifier@^3.2.3: - version "3.5.8" - resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.8.tgz#5ccdb1f73a0d654e6090147511f6e6b2ee312700" - dependencies: - camel-case "3.0.x" - clean-css "4.1.x" - commander "2.12.x" - he "1.1.x" - ncname "1.0.x" - param-case "2.1.x" - relateurl "0.2.x" - uglify-js "3.3.x" - -html-webpack-plugin@^2.22.0: - version "2.30.1" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-2.30.1.tgz#7f9c421b7ea91ec460f56527d78df484ee7537d5" - dependencies: - bluebird "^3.4.7" - html-minifier "^3.2.3" - loader-utils "^0.2.16" - lodash "^4.17.3" - pretty-error "^2.0.2" - toposort "^1.0.0" - -htmlparser2@~3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe" - dependencies: - domelementtype "1" - domhandler "2.1" - domutils "1.1" - readable-stream "1.0" - -http-deceiver@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" - -http-errors@1.6.2, http-errors@~1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" - dependencies: - depd "1.1.1" - inherits "2.0.3" - setprototypeof "1.0.3" - statuses ">= 1.3.1 < 2" - -http-parser-js@>=0.4.0: - version "0.4.9" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.9.tgz#ea1a04fb64adff0242e9974f297dd4c3cad271e1" - -http-proxy-middleware@~0.17.4: - version "0.17.4" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz#642e8848851d66f09d4f124912846dbaeb41b833" - dependencies: - http-proxy "^1.16.2" - is-glob "^3.1.0" - lodash "^4.17.2" - micromatch "^2.3.11" - -http-proxy@^1.16.2: - version "1.16.2" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" - dependencies: - eventemitter3 "1.x.x" - requires-port "1.x.x" - -http-proxy@~0.10: - version "0.10.4" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-0.10.4.tgz#14ba0ceaa2197f89fa30dea9e7b09e19cd93c22f" - dependencies: - colors "0.x.x" - optimist "0.6.x" - pkginfo "0.3.x" - utile "~0.2.1" - -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - -i@0.3.x: - version "0.3.6" - resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" - -iconv-lite@0.4.19, iconv-lite@^0.4.17: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - -iconv-lite@~0.2.11: - version "0.2.11" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8" - -icss-replace-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" - -ieee754@^1.1.4: - version "1.1.8" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" - -ignore@^3.3.3: - version "3.3.7" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" - -imagemin-pngquant@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/imagemin-pngquant/-/imagemin-pngquant-5.0.1.tgz#d8a329da553afa226b11ce62debe0b7e37b439e6" - dependencies: - exec-buffer "^3.0.0" - is-png "^1.0.0" - pngquant-bin "^3.0.0" - -import-local@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-0.1.1.tgz#b1179572aacdc11c6a91009fb430dbcab5f668a8" - dependencies: - pkg-dir "^2.0.0" - resolve-cwd "^2.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - -in-publish@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" - -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - dependencies: - repeating "^2.0.0" - -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - -indexof@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b" - -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - -ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - -inquirer@^3.0.6: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.0.4" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - -internal-ip@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-1.2.0.tgz#ae9fbf93b984878785d50a8de1b356956058cf5c" - dependencies: - meow "^3.3.0" - -interpret@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" - -invariant@^2.2.0, invariant@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" - dependencies: - loose-envify "^1.0.0" - -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - -ip-regex@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-1.0.3.tgz#dc589076f659f419c222039a33316f1c7387effd" - -ip@^1.1.0, ip@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" - -ipaddr.js@1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.5.2.tgz#d4b505bde9946987ccf0fc58d9010ff9607e3fa0" - -is-absolute-url@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" - -is-absolute@^0.1.5: - version "0.1.7" - resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-0.1.7.tgz#847491119fccb5fb436217cc737f7faad50f603f" - dependencies: - is-relative "^0.1.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - dependencies: - binary-extensions "^1.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - -is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - dependencies: - builtin-modules "^1.0.0" - -is-bzip2@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-bzip2/-/is-bzip2-1.0.0.tgz#5ee58eaa5a2e9c80e21407bedf23ae5ac091b3fc" - -is-callable@^1.1.1, is-callable@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" - -is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - -is-extglob@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - -is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - dependencies: - is-extglob "^1.0.0" - -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - dependencies: - is-extglob "^2.1.0" - -is-gzip@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-gzip/-/is-gzip-1.0.0.tgz#6ca8b07b99c77998025900e555ced8ed80879a83" - -is-my-json-valid@^2.12.4: - version "2.17.1" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - -is-natural-number@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-2.1.1.tgz#7d4c5728377ef386c3e194a9911bf57c6dc335e7" - -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - dependencies: - kind-of "^3.0.2" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - dependencies: - kind-of "^3.0.2" - -is-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - -is-path-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" - -is-path-in-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" - dependencies: - is-path-inside "^1.0.0" - -is-path-inside@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - dependencies: - path-is-inside "^1.0.1" - -is-plain-obj@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - -is-png@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-png/-/is-png-1.1.0.tgz#d574b12bf275c0350455570b0e5b57ab062077ce" - -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - -is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - -is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - -is-redirect@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" - -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - dependencies: - has "^1.0.1" - -is-relative@^0.1.0: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.1.3.tgz#905fee8ae86f45b3ec614bc3c15c869df0876e82" - -is-resolvable@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.1.tgz#acca1cd36dbe44b974b924321555a70ba03b1cf4" - -is-retry-allowed@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" - -is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - -is-svg@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" - dependencies: - html-comment-regex "^1.1.0" - -is-symbol@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" - -is-tar@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-tar/-/is-tar-1.0.0.tgz#2f6b2e1792c1f5bb36519acaa9d65c0d26fe853d" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - -is-url@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.2.tgz#498905a593bf47cc2d9e7f738372bbf7696c7f26" - -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - -is-valid-glob@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe" - -is-windows@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9" - -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - -is-zip@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-zip/-/is-zip-1.0.0.tgz#47b0a8ff4d38a76431ccfd99a8e15a4c86ba2325" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - dependencies: - isarray "1.0.0" - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - -jquery@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787" - -js-base64@^2.1.8, js-base64@^2.1.9: - version "2.4.0" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.0.tgz#9e566fee624751a1d720c966cd6226d29d4025aa" - -js-tokens@^3.0.0, js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - -js-yaml@^3.9.1: - version "3.10.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@~2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-2.0.5.tgz#a25ae6509999e97df278c6719da11bd0687743a8" - dependencies: - argparse "~ 0.1.11" - esprima "~ 1.0.2" - -js-yaml@~3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" - dependencies: - argparse "^1.0.7" - esprima "^2.6.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - -jsesc@^0.5.0, jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - -json-loader@^0.5.4: - version "0.5.7" - resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" - -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - -json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - -json3@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" - -json5@^0.5.0, json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -karma-chrome-launcher@^0.1.2: - version "0.1.12" - resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-0.1.12.tgz#0ac0e22e573650f6541312fdca795c3824ccf962" - dependencies: - which "^1.0.9" - -karma-coffee-preprocessor@^0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/karma-coffee-preprocessor/-/karma-coffee-preprocessor-0.1.3.tgz#98137a9e4981b0c9084f8856ef7d4f83d8783152" - dependencies: - coffee-script "~1.7" - -karma-firefox-launcher@^0.1.3: - version "0.1.7" - resolved "https://registry.yarnpkg.com/karma-firefox-launcher/-/karma-firefox-launcher-0.1.7.tgz#c05dd86533691e62f31952595098e8bd357d39f3" - -karma-html2js-preprocessor@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/karma-html2js-preprocessor/-/karma-html2js-preprocessor-0.1.0.tgz#2f7cf881f54a5d0b72154cc6ee1241c44292c7fe" - -karma-jasmine@^0.1.5: - version "0.1.6" - resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-0.1.6.tgz#30545057698ebdcbc63132d47be125b75b2fbc55" - -karma-mocha@^0.1.1: - version "0.1.10" - resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-0.1.10.tgz#29ed51d4b121af1373444ec555b20a905bf42b92" - -karma-phantomjs-launcher@^0.1.1: - version "0.1.4" - resolved "https://registry.yarnpkg.com/karma-phantomjs-launcher/-/karma-phantomjs-launcher-0.1.4.tgz#4ef96e4322ff63ae5d918e51c25b213723238f30" - dependencies: - phantomjs "~1.9" - -karma-requirejs@^0.2.1: - version "0.2.6" - resolved "https://registry.yarnpkg.com/karma-requirejs/-/karma-requirejs-0.2.6.tgz#1a770c64f901320a389c65b4944746326372def8" - -karma-script-launcher@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/karma-script-launcher/-/karma-script-launcher-0.1.0.tgz#b643e7c2faead1a52cdb2eeaadcf7a245f0d772a" - -karma@^0.10.9: - version "0.10.10" - resolved "https://registry.yarnpkg.com/karma/-/karma-0.10.10.tgz#137f4aad0fbe5854e73e8c1eb293c0e540825a49" - dependencies: - chokidar "~0.8.0" - coffee-script "~1.6" - colors "0.6.0-1" - connect "~2.8.4" - di "~0.0.1" - glob "~3.1.21" - graceful-fs "~1.2.1" - http-proxy "~0.10" - lodash "~1.1" - log4js "~0.6.3" - mime "~1.2" - minimatch "~0.2" - optimist "~0.3" - q "~0.9" - rimraf "~2.1" - socket.io "~0.9.13" - useragent "~2.0.4" - -kew@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" - -killable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.0.tgz#da8b84bd47de5395878f95d64d02f2449fe05e6b" - -kind-of@^3.0.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - dependencies: - is-buffer "^1.1.5" - -klaw@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - optionalDependencies: - graceful-fs "^4.1.9" - -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - -lazy-req@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac" - -lazystream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" - dependencies: - readable-stream "^2.0.5" - -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - dependencies: - invert-kv "^1.0.0" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - -loader-fs-cache@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz#56e0bf08bd9708b26a765b68509840c8dec9fdbc" - dependencies: - find-cache-dir "^0.1.1" - mkdirp "0.5.1" - -loader-runner@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" - -loader-utils@^0.2.15, loader-utils@^0.2.16, loader-utils@~0.2.2, loader-utils@~0.2.5, loader-utils@~0.2.6: - version "0.2.17" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - object-assign "^4.0.1" - -loader-utils@^1.0.2, loader-utils@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -lodash._arraycopy@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" - -lodash._arrayeach@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" - -lodash._baseassign@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" - dependencies: - lodash._basecopy "^3.0.0" - lodash.keys "^3.0.0" - -lodash._basecopy@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" - -lodash._basefor@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" - -lodash._basetostring@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" - -lodash._basevalues@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" - -lodash._bindcallback@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" - -lodash._createassigner@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" - dependencies: - lodash._bindcallback "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash.restparam "^3.0.0" - -lodash._createcompounder@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._createcompounder/-/lodash._createcompounder-3.0.0.tgz#5dd2cb55372d6e70e0e2392fb2304d6631091075" - dependencies: - lodash.deburr "^3.0.0" - lodash.words "^3.0.0" - -lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - -lodash._isiterateecall@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" - -lodash._reescape@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" - -lodash._reevaluate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" - -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - -lodash._root@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" - -lodash.assign@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" - dependencies: - lodash._baseassign "^3.0.0" - lodash._createassigner "^3.0.0" - lodash.keys "^3.0.0" - -lodash.assign@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" - -lodash.camelcase@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-3.0.1.tgz#932c8b87f8a4377897c67197533282f97aeac298" - dependencies: - lodash._createcompounder "^3.0.0" - -lodash.clonedeep@^4.3.2: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - -lodash.deburr@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.deburr/-/lodash.deburr-3.2.0.tgz#6da8f54334a366a7cf4c4c76ef8d80aa1b365ed5" - dependencies: - lodash._root "^3.0.0" - -lodash.escape@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" - dependencies: - lodash._root "^3.0.0" - -lodash.isarguments@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - -lodash.isarray@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" - -lodash.isequal@^4.0.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - -lodash.isplainobject@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" - dependencies: - lodash._basefor "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.keysin "^3.0.0" - -lodash.istypedarray@^3.0.0: - version "3.0.6" - resolved "https://registry.yarnpkg.com/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" - -lodash.keys@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" - dependencies: - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - -lodash.keysin@^3.0.0: - version "3.0.8" - resolved "https://registry.yarnpkg.com/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" - dependencies: - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - -lodash.merge@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" - dependencies: - lodash._arraycopy "^3.0.0" - lodash._arrayeach "^3.0.0" - lodash._createassigner "^3.0.0" - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - lodash.isplainobject "^3.0.0" - lodash.istypedarray "^3.0.0" - lodash.keys "^3.0.0" - lodash.keysin "^3.0.0" - lodash.toplainobject "^3.0.0" - -lodash.restparam@^3.0.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - -lodash.template@^3.0.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" - dependencies: - lodash._basecopy "^3.0.0" - lodash._basetostring "^3.0.0" - lodash._basevalues "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" - lodash.keys "^3.0.0" - lodash.restparam "^3.0.0" - lodash.templatesettings "^3.0.0" - -lodash.templatesettings@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" - -lodash.toplainobject@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" - dependencies: - lodash._basecopy "^3.0.0" - lodash.keysin "^3.0.0" - -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - -lodash.words@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.words/-/lodash.words-3.2.0.tgz#4e2a8649bc08745b17c695b1a3ce8fee596623b3" - dependencies: - lodash._root "^3.0.0" - -lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.4: - version "4.17.4" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" - -lodash@~0.9.2: - version "0.9.2" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-0.9.2.tgz#8f3499c5245d346d682e5b0d3b40767e09f1a92c" - -lodash@~1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.1.1.tgz#41a2b2e9a00e64d6d1999f143ff6b0755f6bbb24" - -lodash@~2.4.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.4.2.tgz#fadd834b9683073da179b3eae6d9c0d15053f73e" - -log4js@~0.6.3: - version "0.6.38" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-0.6.38.tgz#2c494116695d6fb25480943d3fc872e662a522fd" - dependencies: - readable-stream "~1.0.2" - semver "~4.3.3" - -logalot@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/logalot/-/logalot-2.1.0.tgz#5f8e8c90d304edf12530951a5554abb8c5e3f552" - dependencies: - figures "^1.3.5" - squeak "^1.0.0" - -loglevel@^1.4.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.0.tgz#ae0caa561111498c5ba13723d6fb631d24003934" - -longest@^1.0.0, longest@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - -loose-envify@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" - dependencies: - js-tokens "^3.0.0" - -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - -lower-case@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" - -lowercase-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" - -lpad-align@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/lpad-align/-/lpad-align-1.1.2.tgz#21f600ac1c3095c3c6e497ee67271ee08481fe9e" - dependencies: - get-stdin "^4.0.1" - indent-string "^2.1.0" - longest "^1.0.0" - meow "^3.3.0" - -lru-cache@2: - version "2.7.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - -lru-cache@2.2.x: - version "2.2.4" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d" - -lru-cache@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -macaddress@^0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" - -manifest-revision-webpack-plugin@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/manifest-revision-webpack-plugin/-/manifest-revision-webpack-plugin-0.3.0.tgz#5a5490fdacaf6faae918dde8ec8b22d2a1a3385a" - dependencies: - walk "^2.3.9" - -map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - -math-expression-evaluator@^1.2.14: - version "1.2.17" - resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac" - -md5.js@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - -mem@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - dependencies: - mimic-fn "^1.0.0" - -memory-fs@^0.4.0, memory-fs@~0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -meow@^3.1.0, meow@^3.3.0, meow@^3.5.0, meow@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - -merge-stream@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" - dependencies: - readable-stream "^2.0.1" - -methods@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/methods/-/methods-0.0.1.tgz#277c90f8bef39709645a8371c51c3b6c648e068c" - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - -micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -"mime-db@>= 1.30.0 < 2": - version "1.32.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.32.0.tgz#485b3848b01a3cda5f968b4882c0771e58e09414" - -mime-db@~1.30.0: - version "1.30.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" - -mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.7: - version "2.1.17" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" - dependencies: - mime-db "~1.30.0" - -mime@1.3.x: - version "1.3.6" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0" - -mime@1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" - -mime@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - -mime@~1.2, mime@~1.2.9: - version "1.2.11" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" - -mimic-fn@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" - -minimalistic-assert@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" - -minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - -minimatch@0.3: - version "0.3.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" - dependencies: - lru-cache "2" - sigmund "~1.0.0" - -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - dependencies: - brace-expansion "^1.1.7" - -minimatch@~0.2, minimatch@~0.2.11, minimatch@~0.2.12: - version "0.2.14" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" - dependencies: - lru-cache "2" - sigmund "~1.0.0" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - -minimist@~0.0.1: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - -mkdirp@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" - dependencies: - minimist "0.0.8" - -mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@0.x.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -mkdirp@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" - -moment@^2.20.1: - version "2.20.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - -multicast-dns-service-types@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" - -multicast-dns@^6.0.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.1.tgz#c5035defa9219d30640558a49298067352098060" - dependencies: - dns-packet "^1.0.1" - thunky "^0.1.0" - -multipipe@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" - dependencies: - duplexer2 "0.0.2" - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - -nan@^2.3.0, nan@^2.3.2: - version "2.8.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" - -nan@~0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-0.8.0.tgz#022a8fa5e9fe8420964ac1fb3dc94e17f449f5fd" - -nan@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-1.0.0.tgz#ae24f8850818d662fcab5acf7f3b95bfaa2ccf38" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - -ncname@1.0.x: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ncname/-/ncname-1.0.0.tgz#5b57ad18b1ca092864ef62b0b1ed8194f383b71c" - dependencies: - xml-char-classes "^1.0.0" - -ncp@0.4.x: - version "0.4.2" - resolved "https://registry.yarnpkg.com/ncp/-/ncp-0.4.2.tgz#abcc6cbd3ec2ed2a729ff6e7c1fa8f01784a8574" - -negotiator@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" - -ng-storage@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/ng-storage/-/ng-storage-0.3.2.tgz#42d65372e802bf5c49783229e6201b3331548b7e" - dependencies: - grunt "^0.4.2" - grunt-cli "^0.1.11" - grunt-contrib-uglify "^0.2.7" - grunt-karma "^0.7.2" - karma "^0.10.9" - karma-chrome-launcher "^0.1.2" - karma-coffee-preprocessor "^0.1.2" - karma-firefox-launcher "^0.1.3" - karma-html2js-preprocessor "^0.1.0" - karma-jasmine "^0.1.5" - karma-mocha "^0.1.1" - karma-phantomjs-launcher "^0.1.1" - karma-requirejs "^0.2.1" - karma-script-launcher "^0.1.0" - requirejs "^2.1.10" - -ngtemplate-loader@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/ngtemplate-loader/-/ngtemplate-loader-1.3.1.tgz#bfd05a1d9a120041698c06f61653f606b39c1060" - dependencies: - jsesc "^0.5.0" - loader-utils "~0.2.6" - -no-case@^2.2.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" - dependencies: - lower-case "^1.1.1" - -node-forge@0.6.33: - version "0.6.33" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.6.33.tgz#463811879f573d45155ad6a9f43dc296e8e85ebc" - -node-gyp@^3.3.1: - version "3.6.2" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.6.2.tgz#9bfbe54562286284838e750eac05295853fa1c60" - dependencies: - fstream "^1.0.0" - glob "^7.0.3" - graceful-fs "^4.1.2" - minimatch "^3.0.2" - mkdirp "^0.5.0" - nopt "2 || 3" - npmlog "0 || 1 || 2 || 3 || 4" - osenv "0" - request "2" - rimraf "2" - semver "~5.3.0" - tar "^2.0.0" - which "1" - -node-libs-browser@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^1.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.0" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.10.3" - vm-browserify "0.0.4" - -node-pre-gyp@^0.6.39: - version "0.6.39" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" - dependencies: - detect-libc "^1.0.2" - hawk "3.1.3" - mkdirp "^0.5.1" - nopt "^4.0.1" - npmlog "^4.0.2" - rc "^1.1.7" - request "2.81.0" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" - -node-sass@^3.10.0: - version "3.13.1" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-3.13.1.tgz#7240fbbff2396304b4223527ed3020589c004fc2" - dependencies: - async-foreach "^0.1.3" - chalk "^1.1.1" - cross-spawn "^3.0.0" - gaze "^1.0.0" - get-stdin "^4.0.1" - glob "^7.0.3" - in-publish "^2.0.0" - lodash.assign "^4.2.0" - lodash.clonedeep "^4.3.2" - meow "^3.7.0" - mkdirp "^0.5.1" - nan "^2.3.2" - node-gyp "^3.3.1" - npmlog "^4.0.0" - request "^2.61.0" - sass-graph "^2.1.1" - -node-status-codes@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-status-codes/-/node-status-codes-1.0.0.tgz#5ae5541d024645d32a58fcddc9ceecea7ae3ac2f" - -node-uuid@~1.4.7: - version "1.4.8" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" - -"nopt@2 || 3": - version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - dependencies: - abbrev "1" - -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - dependencies: - abbrev "1" - osenv "^0.1.4" - -nopt@~1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" - dependencies: - abbrev "1" - -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: - version "2.4.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" - dependencies: - hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.0.0, normalize-path@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - -normalize-url@^1.4.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" - dependencies: - object-assign "^4.0.1" - prepend-http "^1.0.0" - query-string "^4.1.0" - sort-keys "^1.0.0" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - dependencies: - path-key "^2.0.0" - -"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -nth-check@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" - dependencies: - boolbase "~1.0.0" - -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -oauth-sign@~0.8.0, oauth-sign@~0.8.1, oauth-sign@~0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - -object-assign@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-2.1.1.tgz#43c36e5d569ff8e4816c4efa8be02d26967c18aa" - -object-assign@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" - -object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -object-hash@^1.1.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.2.0.tgz#e96af0e96981996a1d47f88ead8f74f1ebc4422b" - -object-keys@^1.0.8: - version "1.0.11" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" - -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - -obuf@^1.0.0, obuf@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e" - -oclazyload@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/oclazyload/-/oclazyload-1.1.0.tgz#a9807322f190820a81c022f2ef1701d036d83e87" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" - -once@^1.3.0, once@^1.3.3, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - dependencies: - mimic-fn "^1.0.0" - -opn@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/opn/-/opn-5.1.0.tgz#72ce2306a17dbea58ff1041853352b4a8fc77519" - dependencies: - is-wsl "^1.1.0" - -optimist@0.6.x, optimist@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - -optimist@~0.3: - version "0.3.7" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.3.7.tgz#c90941ad59e4273328923074d2cf2e7cbc6ec0d9" - dependencies: - wordwrap "~0.0.2" - -optionator@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - -options@>=0.0.5: - version "0.0.6" - resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" - -ordered-read-streams@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b" - dependencies: - is-stream "^1.0.1" - readable-stream "^2.0.1" - -original@>=0.0.5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b" - dependencies: - url-parse "1.0.x" - -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - -os-filter-obj@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/os-filter-obj/-/os-filter-obj-1.0.3.tgz#5915330d90eced557d2d938a31c6dd214d9c63ad" - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - dependencies: - lcid "^1.0.0" - -os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - dependencies: - execa "^0.7.0" - lcid "^1.0.0" - mem "^1.1.0" - -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - -osenv@0, osenv@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - -p-limit@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - dependencies: - p-limit "^1.1.0" - -p-map@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" - -pako@~1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" - -param-case@2.1.x: - version "2.1.1" - resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" - dependencies: - no-case "^2.2.0" - -parse-asn1@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" - dependencies: - asn1.js "^4.0.0" - browserify-aes "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - -parse-json@^2.1.0, parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - dependencies: - error-ex "^1.2.0" - -parseurl@~1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" - -path-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - dependencies: - pinkie-promise "^2.0.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - -path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -path-is-inside@^1.0.1, path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - -path-key@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - dependencies: - pify "^2.0.0" - -pause@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" - -pbkdf2@^3.0.3: - version "3.0.14" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.14.tgz#a35e13c64799b06ce15320f459c230e68e73bade" - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - -phantomjs@~1.9: - version "1.9.20" - resolved "https://registry.yarnpkg.com/phantomjs/-/phantomjs-1.9.20.tgz#4424aca20e14d255c0b0889af6f6b8973da10e0d" - dependencies: - extract-zip "~1.5.0" - fs-extra "~0.26.4" - hasha "^2.2.0" - kew "~0.7.0" - progress "~1.1.8" - request "~2.67.0" - request-progress "~2.0.1" - which "~1.2.2" - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - -pkg-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" - dependencies: - find-up "^1.0.0" - -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - dependencies: - find-up "^2.1.0" - -pkginfo@0.3.x: - version "0.3.1" - resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" - -pluralize@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" - -pngquant-bin@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/pngquant-bin/-/pngquant-bin-3.1.1.tgz#d124d98a75a9487f40c1640b4dbfcbb2bd5a1fd1" - dependencies: - bin-build "^2.0.0" - bin-wrapper "^3.0.0" - logalot "^2.0.0" - -policyfile@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/policyfile/-/policyfile-0.0.4.tgz#d6b82ead98ae79ebe228e2daf5903311ec982e4d" - -portfinder@^1.0.9: - version "1.0.13" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" - dependencies: - async "^1.5.2" - debug "^2.2.0" - mkdirp "0.5.x" - -postcss-calc@^5.2.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" - dependencies: - postcss "^5.0.2" - postcss-message-helpers "^2.0.0" - reduce-css-calc "^1.2.6" - -postcss-colormin@^2.1.8: - version "2.2.2" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b" - dependencies: - colormin "^1.0.5" - postcss "^5.0.13" - postcss-value-parser "^3.2.3" - -postcss-convert-values@^2.3.4: - version "2.6.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d" - dependencies: - postcss "^5.0.11" - postcss-value-parser "^3.1.2" - -postcss-discard-comments@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" - dependencies: - postcss "^5.0.14" - -postcss-discard-duplicates@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932" - dependencies: - postcss "^5.0.4" - -postcss-discard-empty@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5" - dependencies: - postcss "^5.0.14" - -postcss-discard-overridden@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58" - dependencies: - postcss "^5.0.16" - -postcss-discard-unused@^2.2.1: - version "2.2.3" - resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433" - dependencies: - postcss "^5.0.14" - uniqs "^2.0.0" - -postcss-filter-plugins@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c" - dependencies: - postcss "^5.0.4" - uniqid "^4.0.0" - -postcss-loader@^0.13.0: - version "0.13.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-0.13.0.tgz#72fdaf0d29444df77d3751ce4e69dc40bc99ed85" - dependencies: - loader-utils "^0.2.15" - postcss "^5.2.0" - -postcss-merge-idents@^2.1.5: - version "2.1.7" - resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270" - dependencies: - has "^1.0.1" - postcss "^5.0.10" - postcss-value-parser "^3.1.1" - -postcss-merge-longhand@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658" - dependencies: - postcss "^5.0.4" - -postcss-merge-rules@^2.0.3: - version "2.1.2" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721" - dependencies: - browserslist "^1.5.2" - caniuse-api "^1.5.2" - postcss "^5.0.4" - postcss-selector-parser "^2.2.2" - vendors "^1.0.0" - -postcss-message-helpers@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" - -postcss-minify-font-values@^1.0.2: - version "1.0.5" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69" - dependencies: - object-assign "^4.0.1" - postcss "^5.0.4" - postcss-value-parser "^3.0.2" - -postcss-minify-gradients@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1" - dependencies: - postcss "^5.0.12" - postcss-value-parser "^3.3.0" - -postcss-minify-params@^1.0.4: - version "1.2.2" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3" - dependencies: - alphanum-sort "^1.0.1" - postcss "^5.0.2" - postcss-value-parser "^3.0.2" - uniqs "^2.0.0" - -postcss-minify-selectors@^2.0.4: - version "2.1.1" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf" - dependencies: - alphanum-sort "^1.0.2" - has "^1.0.1" - postcss "^5.0.14" - postcss-selector-parser "^2.0.0" - -postcss-modules-extract-imports@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" - dependencies: - postcss "^6.0.1" - -postcss-modules-local-by-default@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - -postcss-modules-scope@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - -postcss-modules-values@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" - dependencies: - icss-replace-symbols "^1.1.0" - postcss "^6.0.1" - -postcss-normalize-charset@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" - dependencies: - postcss "^5.0.5" - -postcss-normalize-url@^3.0.7: - version "3.0.8" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222" - dependencies: - is-absolute-url "^2.0.0" - normalize-url "^1.4.0" - postcss "^5.0.14" - postcss-value-parser "^3.2.3" - -postcss-ordered-values@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d" - dependencies: - postcss "^5.0.4" - postcss-value-parser "^3.0.1" - -postcss-reduce-idents@^2.2.2: - version "2.4.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3" - dependencies: - postcss "^5.0.4" - postcss-value-parser "^3.0.2" - -postcss-reduce-initial@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea" - dependencies: - postcss "^5.0.4" - -postcss-reduce-transforms@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1" - dependencies: - has "^1.0.1" - postcss "^5.0.8" - postcss-value-parser "^3.0.1" - -postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2: - version "2.2.3" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" - dependencies: - flatten "^1.0.2" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-svgo@^2.1.1: - version "2.1.6" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d" - dependencies: - is-svg "^2.0.0" - postcss "^5.0.14" - postcss-value-parser "^3.2.3" - svgo "^0.7.0" - -postcss-unique-selectors@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d" - dependencies: - alphanum-sort "^1.0.1" - postcss "^5.0.4" - uniqs "^2.0.0" - -postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" - -postcss-zindex@^2.0.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22" - dependencies: - has "^1.0.1" - postcss "^5.0.4" - uniqs "^2.0.0" - -postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.0, postcss@^5.2.16: - version "5.2.18" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5" - dependencies: - chalk "^1.1.3" - js-base64 "^2.1.9" - source-map "^0.5.6" - supports-color "^3.2.3" - -postcss@^6.0.1: - version "6.0.14" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.14.tgz#5534c72114739e75d0afcf017db853099f562885" - dependencies: - chalk "^2.3.0" - source-map "^0.6.1" - supports-color "^4.4.0" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - -prepend-http@^1.0.0, prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - -pretty-error@^2.0.2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" - dependencies: - renderkid "^2.0.1" - utila "~0.4" - -private@^0.1.6, private@^0.1.7, private@~0.1.5: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - -progress@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" - -progress@~1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" - -proxy-addr@~2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec" - dependencies: - forwarded "~0.1.2" - ipaddr.js "1.5.2" - -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - -public-encrypt@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - -punycode@^1.2.4, punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - -q@^1.1.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - -q@~0.9: - version "0.9.7" - resolved "https://registry.yarnpkg.com/q/-/q-0.9.7.tgz#4de2e6cb3b29088c9e4cbc03bf9d42fb96ce2f75" - -qs@0.6.5: - version "0.6.5" - resolved "https://registry.yarnpkg.com/qs/-/qs-0.6.5.tgz#294b268e4b0d4250f6dde19b3b8b34935dff14ef" - -qs@6.5.1, qs@~6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" - -qs@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-5.2.1.tgz#801fee030e0b9450d6385adc48a4cc55b44aedfc" - -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" - -query-string@^4.1.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" - dependencies: - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - -querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - -querystringify@0.0.x: - version "0.0.4" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-0.0.4.tgz#0cf7f84f9463ff0ae51c4c4b142d95be37724d9c" - -querystringify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" - -randomatic@^1.1.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79" - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.3.tgz#b96b7df587f01dd91726c418f30553b1418e3d62" - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -range-parser@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-0.0.4.tgz#c0427ffef51c10acba0782a46c9602e744ff620b" - -range-parser@^1.0.3, range-parser@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - -raw-body@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" - dependencies: - bytes "3.0.0" - http-errors "1.6.2" - iconv-lite "0.4.19" - unpipe "1.0.0" - -rc@^1.1.2, rc@^1.1.7: - version "1.2.2" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077" - dependencies: - deep-extend "~0.4.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -read-all-stream@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa" - dependencies: - pinkie-promise "^2.0.0" - readable-stream "^2.0.0" - -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - -readable-stream@1.0, "readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@~1.0.2: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.6, readable-stream@^2.2.9, readable-stream@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" - -readable-stream@~1.1.9: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@~2.0.0, readable-stream@~2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - -readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" - dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" - readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" - -recast@~0.11.12: - version "0.11.23" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" - dependencies: - ast-types "0.9.6" - esprima "~3.1.0" - private "~0.1.5" - source-map "~0.5.0" - -recursive-readdir@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-0.0.2.tgz#0bc47dc4838e646dccfba0507b5e57ffbff35f7c" - -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - -redis@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/redis/-/redis-0.7.3.tgz#ee57b7a44d25ec1594e44365d8165fa7d1d4811a" - -reduce-css-calc@^1.2.6: - version "1.3.0" - resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" - dependencies: - balanced-match "^0.4.2" - math-expression-evaluator "^1.2.14" - reduce-function-call "^1.0.1" - -reduce-function-call@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99" - dependencies: - balanced-match "^0.4.2" - -regenerate@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" - -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - -regenerator-transform@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" - dependencies: - babel-runtime "^6.18.0" - babel-types "^6.19.0" - private "^0.1.6" - -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - dependencies: - is-equal-shallow "^0.1.3" - -regexpu-core@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regexpu-core@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - -regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - dependencies: - jsesc "~0.5.0" - -relateurl@0.2.x: - version "0.2.7" - resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - -renderkid@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.1.tgz#898cabfc8bede4b7b91135a3ffd323e58c0db319" - dependencies: - css-select "^1.1.0" - dom-converter "~0.1" - htmlparser2 "~3.3.0" - strip-ansi "^3.0.0" - utila "~0.3" - -repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" - -repeat-string@^1.5.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - dependencies: - is-finite "^1.0.0" - -replace-ext@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" - -request-progress@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" - dependencies: - throttleit "^1.0.0" - -request@2, request@^2.61.0: - version "2.83.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - hawk "~6.0.2" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - stringstream "~0.0.5" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - -request@2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "^0.6.0" - uuid "^3.0.0" - -request@~2.67.0: - version "2.67.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.67.0.tgz#8af74780e2bf11ea0ae9aa965c11f11afd272742" - dependencies: - aws-sign2 "~0.6.0" - bl "~1.0.0" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~1.0.0-rc3" - har-validator "~2.0.2" - hawk "~3.1.0" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - node-uuid "~1.4.7" - oauth-sign "~0.8.0" - qs "~5.2.0" - stringstream "~0.0.4" - tough-cookie "~2.2.0" - tunnel-agent "~0.4.1" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - -require-uncached@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - -requirejs@^2.1.10: - version "2.3.5" - resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.5.tgz#617b9acbbcb336540ef4914d790323a8d4b861b0" - -requires-port@1.0.x, requires-port@1.x.x, requires-port@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - -resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - dependencies: - resolve-from "^3.0.0" - -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - -resolve@~0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-0.3.1.tgz#34c63447c664c70598d1c9b126fc43b2a24310a4" - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - -right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - dependencies: - align-text "^0.1.1" - -rimraf@2, rimraf@2.x.x, rimraf@^2.2.6, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - dependencies: - glob "^7.0.5" - -rimraf@~2.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.1.4.tgz#5a6eb62eeda068f51ede50f29b3e5cd22f3d9bb2" - optionalDependencies: - graceful-fs "~1" - -rimraf@~2.2.8: - version "2.2.8" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" - dependencies: - hash-base "^2.0.0" - inherits "^2.0.1" - -run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - dependencies: - is-promise "^2.1.0" - -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - -safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - -sass-graph@^2.1.1: - version "2.2.4" - resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" - dependencies: - glob "^7.0.0" - lodash "^4.0.0" - scss-tokenizer "^0.2.3" - yargs "^7.0.0" - -sass-loader@^4.0.2: - version "4.1.1" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-4.1.1.tgz#79ef9468cf0bf646c29529e1f2cba6bd6e51c7bc" - dependencies: - async "^2.0.1" - loader-utils "^0.2.15" - object-assign "^4.1.0" - -sax@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - -schema-utils@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf" - dependencies: - ajv "^5.0.0" - -scss-tokenizer@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" - dependencies: - js-base64 "^2.1.8" - source-map "^0.4.2" - -seek-bzip@^1.0.3: - version "1.0.5" - resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" - dependencies: - commander "~2.8.1" - -select-hose@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" - -selfsigned@^1.9.1: - version "1.10.1" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.1.tgz#bf8cb7b83256c4551e31347c6311778db99eec52" - dependencies: - node-forge "0.6.33" - -semver-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-1.0.0.tgz#92a4969065f9c70c694753d55248fc68f8f652c9" - -semver-truncate@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/semver-truncate/-/semver-truncate-1.1.2.tgz#57f41de69707a62709a7e0104ba2117109ea47e8" - dependencies: - semver "^5.3.0" - -"semver@2 || 3 || 4 || 5", semver@^5.3.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - -semver@^4.0.3, semver@~4.3.3: - version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - -semver@~5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - -send@0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/send/-/send-0.1.4.tgz#be70d8d1be01de61821af13780b50345a4f71abd" - dependencies: - debug "*" - fresh "0.2.0" - mime "~1.2.9" - range-parser "0.0.4" - -send@0.16.1: - version "0.16.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" - dependencies: - debug "2.6.9" - depd "~1.1.1" - destroy "~1.0.4" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.6.2" - mime "1.4.1" - ms "2.0.0" - on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.3.1" - -serve-index@^1.7.2: - version "1.9.1" - resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" - dependencies: - accepts "~1.3.4" - batch "0.6.1" - debug "2.6.9" - escape-html "~1.0.3" - http-errors "~1.6.2" - mime-types "~2.1.17" - parseurl "~1.3.2" - -serve-static@1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.1.tgz#4c57d53404a761d8f2e7c1e8a18a47dbf278a719" - dependencies: - encodeurl "~1.0.1" - escape-html "~1.0.3" - parseurl "~1.3.2" - send "0.16.1" - -set-blocking@^2.0.0, set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -set-immediate-shim@^1.0.0, set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - -setprototypeof@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" - -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.9" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.9.tgz#98f64880474b74f4a38b8da9d3c0f2d104633e7d" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - -sigmund@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" - -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -simple-is@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" - -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - -slice-ansi@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" - dependencies: - is-fullwidth-code-point "^2.0.0" - -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" - -sntp@2.x.x: - version "2.1.0" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" - dependencies: - hoek "4.x.x" - -socket.io-client@0.9.16: - version "0.9.16" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-0.9.16.tgz#4da7515c5e773041d1b423970415bcc430f35fc6" - dependencies: - active-x-obfuscator "0.0.1" - uglify-js "1.2.5" - ws "0.4.x" - xmlhttprequest "1.4.2" - -socket.io@~0.9.13: - version "0.9.19" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-0.9.19.tgz#490bb5fd0dc54cf002ee04e67fadfc43b848a38f" - dependencies: - base64id "0.1.0" - policyfile "0.0.4" - socket.io-client "0.9.16" - optionalDependencies: - redis "0.7.3" - -sockjs-client@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.4.tgz#5babe386b775e4cf14e7520911452654016c8b12" - dependencies: - debug "^2.6.6" - eventsource "0.1.6" - faye-websocket "~0.11.0" - inherits "^2.0.1" - json3 "^3.3.2" - url-parse "^1.1.8" - -sockjs@0.3.18: - version "0.3.18" - resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.18.tgz#d9b289316ca7df77595ef299e075f0f937eb4207" - dependencies: - faye-websocket "^0.10.0" - uuid "^2.0.2" - -sort-keys@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" - dependencies: - is-plain-obj "^1.0.0" - -source-list-map@^0.1.4: - version "0.1.8" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" - -source-list-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" - -source-map-support@^0.4.15: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - dependencies: - source-map "^0.5.6" - -source-map@0.1.34: - version "0.1.34" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.34.tgz#a7cfe89aec7b1682c3b198d0acfb47d7d090566b" - dependencies: - amdefine ">=0.0.4" - -source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - -source-map@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" - dependencies: - amdefine ">=0.0.4" - -source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - -sparkles@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" - -spdx-correct@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" - dependencies: - spdx-license-ids "^1.0.2" - -spdx-expression-parse@~1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" - -spdx-license-ids@^1.0.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" - -spdy-transport@^2.0.18: - version "2.0.20" - resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.0.20.tgz#735e72054c486b2354fe89e702256004a39ace4d" - dependencies: - debug "^2.6.8" - detect-node "^2.0.3" - hpack.js "^2.1.6" - obuf "^1.1.1" - readable-stream "^2.2.9" - safe-buffer "^5.0.1" - wbuf "^1.7.2" - -spdy@^3.4.1: - version "3.4.7" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc" - dependencies: - debug "^2.6.8" - handle-thing "^1.2.5" - http-deceiver "^1.2.7" - safe-buffer "^5.0.1" - select-hose "^2.0.0" - spdy-transport "^2.0.18" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - -squeak@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/squeak/-/squeak-1.3.0.tgz#33045037b64388b567674b84322a6521073916c3" - dependencies: - chalk "^1.0.0" - console-stream "^0.1.1" - lpad-align "^1.0.1" - -sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" - -stat-mode@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-0.2.2.tgz#e6c80b623123d7d80cf132ce538f346289072502" - -"statuses@>= 1.3.1 < 2": - version "1.4.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" - -statuses@~1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" - -stream-browserify@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-combiner2@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" - dependencies: - duplexer2 "~0.1.0" - readable-stream "^2.0.2" - -stream-http@^2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad" - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.2.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-shift@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" - -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - -string-width@^1.0.1, string-width@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string_decoder@^1.0.0, string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" - dependencies: - safe-buffer "~5.1.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - -stringstream@~0.0.4, stringstream@~0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - dependencies: - ansi-regex "^3.0.0" - -strip-bom-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee" - dependencies: - first-chunk-stream "^1.0.0" - strip-bom "^2.0.0" - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - dependencies: - is-utf8 "^0.2.0" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - -strip-dirs@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-1.1.1.tgz#960bbd1287844f3975a4558aa103a8255e2456a0" - dependencies: - chalk "^1.0.0" - get-stdin "^4.0.1" - is-absolute "^0.1.5" - is-natural-number "^2.0.0" - minimist "^1.1.0" - sum-up "^1.0.1" - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - dependencies: - get-stdin "^4.0.1" - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - -strip-outer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.0.tgz#aac0ba60d2e90c5d4f275fd8869fd9a2d310ffb8" - dependencies: - escape-string-regexp "^1.0.2" - -style-loader@^0.13.1: - version "0.13.2" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.13.2.tgz#74533384cf698c7104c7951150b49717adc2f3bb" - dependencies: - loader-utils "^1.0.2" - -sum-up@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" - dependencies: - chalk "^1.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - -supports-color@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" - dependencies: - has-flag "^1.0.0" - -supports-color@^4.0.0, supports-color@^4.2.1, supports-color@^4.4.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" - dependencies: - has-flag "^2.0.0" - -svgo@^0.7.0: - version "0.7.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" - dependencies: - coa "~1.0.1" - colors "~1.1.2" - csso "~2.3.1" - js-yaml "~3.7.0" - mkdirp "~0.5.1" - sax "~1.2.1" - whet.extend "~0.9.9" - -table@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" - dependencies: - ajv "^5.2.3" - ajv-keywords "^2.1.0" - chalk "^2.1.0" - lodash "^4.17.4" - slice-ansi "1.0.0" - string-width "^2.1.1" - -tapable@^0.2.7: - version "0.2.8" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" - -tar-pack@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" - dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" - -tar-stream@^1.1.1: - version "1.5.5" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.5.tgz#5cad84779f45c83b1f2508d96b09d88c7218af55" - dependencies: - bl "^1.0.0" - end-of-stream "^1.0.0" - readable-stream "^2.0.0" - xtend "^4.0.0" - -tar@^2.0.0, tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - -temp-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" - -tempfile@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-1.1.1.tgz#5bcc4eaecc4ab2c707d8bc11d99ccc9a2cb287f2" - dependencies: - os-tmpdir "^1.0.0" - uuid "^2.0.1" - -tempfile@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-2.0.0.tgz#6b0446856a9b1114d1856ffcbe509cccb0977265" - dependencies: - temp-dir "^1.0.0" - uuid "^3.0.1" - -text-table@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - -throttleit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" - -through2-filter@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec" - dependencies: - through2 "~2.0.0" - xtend "~4.0.0" - -through2@^0.6.0, through2@^0.6.1: - version "0.6.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" - dependencies: - readable-stream ">=1.0.33-1 <1.1.0-0" - xtend ">=4.0.0 <4.1.0-0" - -through2@^2.0.0, through2@~2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" - dependencies: - readable-stream "^2.1.5" - xtend "~4.0.1" - -through@^2.3.6, through@~2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - -thunky@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/thunky/-/thunky-0.1.0.tgz#bf30146824e2b6e67b0f2d7a4ac8beb26908684e" - -time-stamp@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" - -time-stamp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-2.0.0.tgz#95c6a44530e15ba8d6f4a3ecb8c3a3fac46da357" - -timed-out@^3.0.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-3.1.3.tgz#95860bfcc5c76c277f8f8326fd0f5b2e20eba217" - -timers-browserify@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.4.tgz#96ca53f4b794a5e7c0e1bd7cc88a372298fa01e6" - dependencies: - setimmediate "^1.0.4" - -tinycolor@0.x: - version "0.0.1" - resolved "https://registry.yarnpkg.com/tinycolor/-/tinycolor-0.0.1.tgz#320b5a52d83abb5978d81a3e887d4aefb15a6164" - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - dependencies: - os-tmpdir "~1.0.2" - -to-absolute-glob@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f" - dependencies: - extend-shallow "^2.0.1" - -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - -toposort@^1.0.0: - version "1.0.6" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.6.tgz#c31748e55d210effc00fdcdc7d6e68d7d7bb9cec" - -tough-cookie@~2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.2.2.tgz#c83a1830f4e5ef0b93ef2a3488e724f8de016ac7" - -tough-cookie@~2.3.0, tough-cookie@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" - dependencies: - punycode "^1.4.1" - -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - -trim-repeated@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" - dependencies: - escape-string-regexp "^1.0.2" - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - -tunnel-agent@^0.4.0, tunnel-agent@~0.4.1: - version "0.4.3" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - dependencies: - prelude-ls "~1.1.2" - -type-is@~1.6.15: - version "1.6.15" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" - dependencies: - media-typer "0.3.0" - mime-types "~2.1.15" - -typedarray@^0.0.6, typedarray@~0.0.5: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - -uglify-js@1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-1.2.5.tgz#b542c2c76f78efb34b200b20177634330ff702b6" - -uglify-js@3.3.x: - version "3.3.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.3.tgz#66f9b57f7dda913ad9f48a21b12e4e7377fdaf40" - dependencies: - commander "~2.12.1" - source-map "~0.6.1" - -uglify-js@^2.8.29: - version "2.8.29" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" - dependencies: - source-map "~0.5.1" - yargs "~3.10.0" - optionalDependencies: - uglify-to-browserify "~1.0.0" - -uglify-js@~2.4.0: - version "2.4.24" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.4.24.tgz#fad5755c1e1577658bb06ff9ab6e548c95bebd6e" - dependencies: - async "~0.2.6" - source-map "0.1.34" - uglify-to-browserify "~1.0.0" - yargs "~3.5.4" - -uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - -uglifyjs-webpack-plugin@^0.4.6: - version "0.4.6" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309" - dependencies: - source-map "^0.5.6" - uglify-js "^2.8.29" - webpack-sources "^1.0.1" - -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - -uid2@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.2.tgz#107fb155c82c1136620797ed4c88cf2b08f6aab8" - -underscore.string@~2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.2.1.tgz#d7c0fa2af5d5a1a67f4253daee98132e733f0f19" - -underscore.string@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" - -underscore.string@~2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b" - -underscore@~1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - -uniqid@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1" - dependencies: - macaddress "^0.2.8" - -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" - -unique-stream@^2.0.2: - version "2.2.1" - resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.2.1.tgz#5aa003cfbe94c5ff866c4e7d668bb1c4dbadb369" - dependencies: - json-stable-stringify "^1.0.0" - through2-filter "^2.0.0" - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - -unzip-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe" - -upper-case@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" - -url-loader@^0.5.7: - version "0.5.9" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.9.tgz#cc8fea82c7b906e7777019250869e569e995c295" - dependencies: - loader-utils "^1.0.2" - mime "1.3.x" - -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - dependencies: - prepend-http "^1.0.1" - -url-parse@1.0.x: - version "1.0.5" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b" - dependencies: - querystringify "0.0.x" - requires-port "1.0.x" - -url-parse@^1.1.8: - version "1.2.0" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986" - dependencies: - querystringify "~1.0.0" - requires-port "~1.0.0" - -url-regex@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/url-regex/-/url-regex-3.2.0.tgz#dbad1e0c9e29e105dd0b1f09f6862f7fdb482724" - dependencies: - ip-regex "^1.0.1" - -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -useragent@~2.0.4: - version "2.0.10" - resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.0.10.tgz#af2c1cc641159361e4d830866eb716ba4679de33" - dependencies: - lru-cache "2.2.x" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -util@0.10.3, util@^0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - dependencies: - inherits "2.0.1" - -utila@~0.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/utila/-/utila-0.3.3.tgz#d7e8e7d7e309107092b05f8d9688824d633a4226" - -utila@~0.4: - version "0.4.0" - resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" - -utile@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/utile/-/utile-0.2.1.tgz#930c88e99098d6220834c356cbd9a770522d90d7" - dependencies: - async "~0.2.9" - deep-equal "*" - i "0.3.x" - mkdirp "0.x.x" - ncp "0.4.x" - rimraf "2.x.x" - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - -uuid@^2.0.1, uuid@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" - -uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" - -vali-date@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6" - -validate-npm-package-license@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" - dependencies: - spdx-correct "~1.0.0" - spdx-expression-parse "~1.0.0" - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - -vendors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vinyl-assign@^1.0.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/vinyl-assign/-/vinyl-assign-1.2.1.tgz#4d198891b5515911d771a8cd9c5480a46a074a45" - dependencies: - object-assign "^4.0.1" - readable-stream "^2.0.0" - -vinyl-fs@^2.2.0: - version "2.4.4" - resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239" - dependencies: - duplexify "^3.2.0" - glob-stream "^5.3.2" - graceful-fs "^4.0.0" - gulp-sourcemaps "1.6.0" - is-valid-glob "^0.3.0" - lazystream "^1.0.0" - lodash.isequal "^4.0.0" - merge-stream "^1.0.0" - mkdirp "^0.5.0" - object-assign "^4.0.0" - readable-stream "^2.0.4" - strip-bom "^2.0.0" - strip-bom-stream "^1.0.0" - through2 "^2.0.0" - through2-filter "^2.0.0" - vali-date "^1.0.0" - vinyl "^1.0.0" - -vinyl@^0.4.3: - version "0.4.6" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847" - dependencies: - clone "^0.2.0" - clone-stats "^0.0.1" - -vinyl@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - -vinyl@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - -vm-browserify@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" - dependencies: - indexof "0.0.1" - -walk@^2.3.9: - version "2.3.9" - resolved "https://registry.yarnpkg.com/walk/-/walk-2.3.9.tgz#31b4db6678f2ae01c39ea9fb8725a9031e558a7b" - dependencies: - foreachasync "^3.0.0" - -ware@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ware/-/ware-1.3.0.tgz#d1b14f39d2e2cb4ab8c4098f756fe4b164e473d4" - dependencies: - wrap-fn "^0.1.0" - -watchpack@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac" - dependencies: - async "^2.1.2" - chokidar "^1.7.0" - graceful-fs "^4.1.2" - -wbuf@^1.1.0, wbuf@^1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.2.tgz#d697b99f1f59512df2751be42769c1580b5801fe" - dependencies: - minimalistic-assert "^1.0.0" - -webpack-dev-middleware@^1.11.0: - version "1.12.2" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz#f8fc1120ce3b4fc5680ceecb43d777966b21105e" - dependencies: - memory-fs "~0.4.1" - mime "^1.5.0" - path-is-absolute "^1.0.0" - range-parser "^1.0.3" - time-stamp "^2.0.0" - -webpack-dev-server@^2.2.0: - version "2.9.7" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.9.7.tgz#100ad6a14775478924d417ca6dcfb9d52a98faed" - dependencies: - ansi-html "0.0.7" - array-includes "^3.0.3" - bonjour "^3.5.0" - chokidar "^1.6.0" - compression "^1.5.2" - connect-history-api-fallback "^1.3.0" - debug "^3.1.0" - del "^3.0.0" - express "^4.16.2" - html-entities "^1.2.0" - http-proxy-middleware "~0.17.4" - import-local "^0.1.1" - internal-ip "1.2.0" - ip "^1.1.5" - killable "^1.0.0" - loglevel "^1.4.1" - opn "^5.1.0" - portfinder "^1.0.9" - selfsigned "^1.9.1" - serve-index "^1.7.2" - sockjs "0.3.18" - sockjs-client "1.1.4" - spdy "^3.4.1" - strip-ansi "^3.0.1" - supports-color "^4.2.1" - webpack-dev-middleware "^1.11.0" - yargs "^6.6.0" - -webpack-sources@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - -webpack@^3.5.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.10.0.tgz#5291b875078cf2abf42bdd23afe3f8f96c17d725" - dependencies: - acorn "^5.0.0" - acorn-dynamic-import "^2.0.0" - ajv "^5.1.5" - ajv-keywords "^2.0.0" - async "^2.1.2" - enhanced-resolve "^3.4.0" - escope "^3.6.0" - interpret "^1.0.0" - json-loader "^0.5.4" - json5 "^0.5.1" - loader-runner "^2.3.0" - loader-utils "^1.1.0" - memory-fs "~0.4.1" - mkdirp "~0.5.0" - node-libs-browser "^2.0.0" - source-map "^0.5.3" - supports-color "^4.2.1" - tapable "^0.2.7" - uglifyjs-webpack-plugin "^0.4.6" - watchpack "^1.4.0" - webpack-sources "^1.0.1" - yargs "^8.0.2" - -websocket-driver@>=0.5.1: - version "0.7.0" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" - dependencies: - http-parser-js ">=0.4.0" - websocket-extensions ">=0.1.1" - -websocket-extensions@>=0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" - -whet.extend@~0.9.9: - version "0.9.9" - resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" - -which-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - -which@1, which@^1.0.9, which@^1.2.9: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" - dependencies: - isexe "^2.0.0" - -which@~1.0.5: - version "1.0.9" - resolved "https://registry.yarnpkg.com/which/-/which-1.0.9.tgz#460c1da0f810103d0321a9b633af9e575e64486f" - -which@~1.2.2: - version "1.2.14" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" - dependencies: - isexe "^2.0.0" - -wide-align@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" - dependencies: - string-width "^1.0.2" - -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrap-fn@^0.1.0: - version "0.1.5" - resolved "https://registry.yarnpkg.com/wrap-fn/-/wrap-fn-0.1.5.tgz#f21b6e41016ff4a7e31720dbc63a09016bdf9845" - dependencies: - co "3.1.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -write@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - dependencies: - mkdirp "^0.5.1" - -ws@0.4.x: - version "0.4.32" - resolved "https://registry.yarnpkg.com/ws/-/ws-0.4.32.tgz#787a6154414f3c99ed83c5772153b20feb0cec32" - dependencies: - commander "~2.1.0" - nan "~1.0.0" - options ">=0.0.5" - tinycolor "0.x" - -xml-char-classes@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" - -xmlhttprequest@1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.4.2.tgz#01453a1d9bed1e8f172f6495bbf4c8c426321500" - -"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - -y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - -yargs-parser@^4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" - dependencies: - camelcase "^3.0.0" - -yargs-parser@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" - dependencies: - camelcase "^3.0.0" - -yargs-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" - dependencies: - camelcase "^4.1.0" - -yargs@^6.6.0: - version "6.6.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" - dependencies: - camelcase "^3.0.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^1.0.2" - which-module "^1.0.0" - y18n "^3.2.1" - yargs-parser "^4.2.0" - -yargs@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" - dependencies: - camelcase "^3.0.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^1.0.2" - which-module "^1.0.0" - y18n "^3.2.1" - yargs-parser "^5.0.0" - -yargs@^8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" - dependencies: - camelcase "^4.1.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - read-pkg-up "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^7.0.0" - -yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0" - -yargs@~3.5.4: - version "3.5.4" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.5.4.tgz#d8aff8f665e94c34bd259bdebd1bfaf0ddd35361" - dependencies: - camelcase "^1.0.2" - decamelize "^1.0.0" - window-size "0.1.0" - wordwrap "0.0.2" - -yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - dependencies: - fd-slicer "~1.0.1" - -yauzl@^2.2.1: - version "2.9.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f" - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.0.1" - -zeparser@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/zeparser/-/zeparser-0.0.5.tgz#03726561bc268f2e5444f54c665b7fd4a8c029e2" - -zlib-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/zlib-browserify/-/zlib-browserify-0.0.1.tgz#4fa6a45d00dbc15f318a4afa1d9afc0258e176cc" From ea8931ad35302146a1833ce4c2d1556fcb37ee92 Mon Sep 17 00:00:00 2001 From: Nabil Adouani Date: Tue, 14 May 2019 16:22:05 +0200 Subject: [PATCH 05/17] #190 Update dev dependencies --- www/package.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/www/package.json b/www/package.json index faa593832..a444e09ee 100755 --- a/www/package.json +++ b/www/package.json @@ -37,6 +37,7 @@ "font-awesome": "^4.7.0", "jquery": "^3.4.1", "lodash": "^4.17.11", + "js-url": "^2.3.0", "moment": "^2.24.0", "url": "^0.11.0" }, @@ -44,12 +45,12 @@ "node": ">=0.12.0" }, "devDependencies": { - "babel-eslint": "^8.2.1", - "babel-plugin-angularjs-annotate": "^0.5.3", "assets-webpack-plugin": "^3.4.0", "autoprefixer": "^6.5.0", "babel-core": "^6.26.3", + "babel-eslint": "^8.2.1", "babel-loader": "^6.2.5", + "babel-plugin-angularjs-annotate": "^0.5.3", "babel-preset-es2015": "^6.24.1", "babel-preset-es2017": "^6.24.1", "babel-preset-stage-1": "^6.24.1", @@ -70,8 +71,8 @@ "postcss-loader": "^0.13.0", "sass-loader": "^4.0.2", "style-loader": "^0.13.1", - "url-loader": "^0.5.7", + "url-loader": "^0.5.9", "webpack": "^3.5.0", "webpack-dev-server": "^2.2.0" } -} \ No newline at end of file +} From 7280dbc9c4cd885d290949518b2b6843d5a2cd42 Mon Sep 17 00:00:00 2001 From: To-om Date: Mon, 20 May 2019 16:58:52 +0200 Subject: [PATCH 06/17] Use scalafmt to format code --- .scalafmt.conf | 26 + .scalariform.conf | 30 - app/org/thp/cortex/Module.scala | 40 +- .../controllers/AnalyzerConfigCtrl.scala | 44 +- .../thp/cortex/controllers/AnalyzerCtrl.scala | 45 +- .../thp/cortex/controllers/AssetCtrl.scala | 16 +- .../cortex/controllers/AttachmentCtrl.scala | 45 +- .../controllers/AuthenticationCtrl.scala | 21 +- .../thp/cortex/controllers/DBListCtrl.scala | 28 +- app/org/thp/cortex/controllers/Home.scala | 9 +- app/org/thp/cortex/controllers/JobCtrl.scala | 116 +- app/org/thp/cortex/controllers/MispCtrl.scala | 25 +- .../cortex/controllers/OrganizationCtrl.scala | 42 +- .../controllers/ResponderConfigCtrl.scala | 44 +- .../cortex/controllers/ResponderCtrl.scala | 72 +- .../thp/cortex/controllers/StatusCtrl.scala | 41 +- .../thp/cortex/controllers/StreamCtrl.scala | 45 +- app/org/thp/cortex/controllers/UserCtrl.scala | 135 +- app/org/thp/cortex/models/Artifact.scala | 21 +- app/org/thp/cortex/models/Audit.scala | 82 +- app/org/thp/cortex/models/BaseConfig.scala | 84 +- app/org/thp/cortex/models/Errors.scala | 9 +- app/org/thp/cortex/models/Job.scala | 68 +- app/org/thp/cortex/models/JsonFormat.scala | 2 +- app/org/thp/cortex/models/Migration.scala | 67 +- app/org/thp/cortex/models/Organization.scala | 46 +- app/org/thp/cortex/models/Report.scala | 15 +- app/org/thp/cortex/models/Roles.scala | 23 +- .../cortex/models/TlpAttributeFormat.scala | 33 +- app/org/thp/cortex/models/User.scala | 40 +- app/org/thp/cortex/models/Worker.scala | 55 +- app/org/thp/cortex/models/WorkerConfig.scala | 27 +- .../thp/cortex/models/WorkerDefinition.scala | 72 +- .../cortex/services/AnalyzerConfigSrv.scala | 14 +- app/org/thp/cortex/services/AuditSrv.scala | 18 +- app/org/thp/cortex/services/CSRFFilter.scala | 29 +- .../thp/cortex/services/CortexAuthSrv.scala | 22 +- .../cortex/services/DockerJobRunnerSrv.scala | 84 +- .../thp/cortex/services/ErrorHandler.scala | 67 +- .../thp/cortex/services/JobRunnerSrv.scala | 126 +- app/org/thp/cortex/services/JobSrv.scala | 274 +- app/org/thp/cortex/services/KeyAuthSrv.scala | 24 +- .../thp/cortex/services/LocalAuthSrv.scala | 28 +- app/org/thp/cortex/services/MispSrv.scala | 357 +- app/org/thp/cortex/services/OAuth2Srv.scala | 124 +- .../thp/cortex/services/OrganizationSrv.scala | 26 +- .../cortex/services/ProcessJobRunnerSrv.scala | 15 +- .../cortex/services/ResponderConfigSrv.scala | 15 +- .../thp/cortex/services/StreamMessage.scala | 67 +- app/org/thp/cortex/services/StreamSrv.scala | 53 +- app/org/thp/cortex/services/UserSrv.scala | 82 +- .../thp/cortex/services/WorkerConfigSrv.scala | 64 +- app/org/thp/cortex/services/WorkerSrv.scala | 167 +- .../services/mappers/GroupUserMapper.scala | 47 +- .../services/mappers/MultiUserMapperSrv.scala | 12 +- .../services/mappers/SimpleUserMapper.scala | 33 +- app/org/thp/cortex/util/JsonConfig.scala | 25 +- package-lock.json | 4291 ----------------- project/plugins.sbt | 8 +- 59 files changed, 1726 insertions(+), 5814 deletions(-) create mode 100644 .scalafmt.conf delete mode 100644 .scalariform.conf delete mode 100644 package-lock.json diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 000000000..4885c26f6 --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,26 @@ +version = "2.0.0-RC7" +align = more # For pretty alignment. +assumeStandardLibraryStripMargin = true +style = defaultWithAlign +maxColumn = 150 + +align.openParenCallSite = false +align.openParenDefnSite = false +newlines.alwaysBeforeTopLevelStatements = true +rewrite.rules = [ + # ExpandImportSelectors + RedundantBraces + RedundantParens + SortModifiers + PreferCurlyFors + SortImports +] + +includeCurlyBraceInSelectChains = true +includeNoParensInSelectChains = true + +rewriteTokens { + "=>" : "⇒" + "<-" : "←" + "->": "→" +} diff --git a/.scalariform.conf b/.scalariform.conf deleted file mode 100644 index d86296aff..000000000 --- a/.scalariform.conf +++ /dev/null @@ -1,30 +0,0 @@ -#alignArguments=false -#alignParameters=false -alignSingleLineCaseStatements=true -alignSingleLineCaseStatements.maxArrowIndent=60 -#allowParamGroupsOnNewlines=false -compactControlReadability=true -#compactStringConcatenation=false -#danglingCloseParenthesis=Prevent -doubleIndentClassDeclaration=false -doubleIndentConstructorArguments=true -doubleIndentMethodDeclaration=true -#firstArgumentOnNewline=Force -#firstParameterOnNewline=Force -#formatXml=true -#indentLocalDefs=false -#indentPackageBlocks=true -#indentSpaces=2 -#indentWithTabs=false -#multilineScaladocCommentsStartOnFirstLine=false -#newlineAtEndOfFile=false -placeScaladocAsterisksBeneathSecondAsterisk=true -#preserveSpaceBeforeArguments=false -rewriteArrowSymbols=true -#singleCasePatternOnNewline=true -#spaceBeforeColon=false -#spaceBeforeContextColon=false -#spaceInsideBrackets=false -#spaceInsideParentheses=false -#spacesAroundMultiImports=true -#spacesWithinPatternBinders=true \ No newline at end of file diff --git a/app/org/thp/cortex/Module.scala b/app/org/thp/cortex/Module.scala index f025e9d6b..af4c4cf79 100644 --- a/app/org/thp/cortex/Module.scala +++ b/app/org/thp/cortex/Module.scala @@ -1,43 +1,47 @@ package org.thp.cortex +import java.lang.reflect.Modifier + import com.google.inject.AbstractModule -import net.codingwell.scalaguice.{ ScalaModule, ScalaMultibinder } +import net.codingwell.scalaguice.{ScalaModule, ScalaMultibinder} import play.api.libs.concurrent.AkkaGuiceSupport -import play.api.{ Configuration, Environment, Logger, Mode } +import play.api.{Configuration, Environment, Logger, Mode} import scala.collection.JavaConverters._ import com.google.inject.name.Names import org.reflections.Reflections import org.reflections.scanners.SubTypesScanner import org.reflections.util.ConfigurationBuilder -import org.thp.cortex.models.{ AuditedModel, Migration } +import org.thp.cortex.models.{AuditedModel, Migration} import org.thp.cortex.services._ import org.elastic4play.models.BaseModelDef import org.elastic4play.services.auth.MultiAuthSrv -import org.elastic4play.services.{ AuthSrv, MigrationOperations } -import org.thp.cortex.controllers.{ AssetCtrl, AssetCtrlDev, AssetCtrlProd } -import services.mappers.{ MultiUserMapperSrv, UserMapper } +import org.elastic4play.services.{UserSrv ⇒ EUserSrv, AuthSrv, MigrationOperations} +import org.thp.cortex.controllers.{AssetCtrl, AssetCtrlDev, AssetCtrlProd} +import services.mappers.{MultiUserMapperSrv, UserMapper} class Module(environment: Environment, configuration: Configuration) extends AbstractModule with ScalaModule with AkkaGuiceSupport { private lazy val logger = Logger(s"module") override def configure(): Unit = { - val modelBindings = ScalaMultibinder.newSetBinder[BaseModelDef](binder) + val modelBindings = ScalaMultibinder.newSetBinder[BaseModelDef](binder) val auditedModelBindings = ScalaMultibinder.newSetBinder[AuditedModel](binder) - val reflectionClasses = new Reflections(new ConfigurationBuilder() - .forPackages("org.elastic4play") - .addClassLoader(getClass.getClassLoader) - .addClassLoader(environment.getClass.getClassLoader) - .forPackages("org.thp.cortex") - .setExpandSuperTypes(false) - .setScanners(new SubTypesScanner(false))) + val reflectionClasses = new Reflections( + new ConfigurationBuilder() + .forPackages("org.elastic4play") + .addClassLoader(getClass.getClassLoader) + .addClassLoader(environment.getClass.getClassLoader) + .forPackages("org.thp.cortex") + .setExpandSuperTypes(false) + .setScanners(new SubTypesScanner(false)) + ) reflectionClasses .getSubTypesOf(classOf[BaseModelDef]) .asScala - .filterNot(c ⇒ java.lang.reflect.Modifier.isAbstract(c.getModifiers)) + .filterNot(c ⇒ Modifier.isAbstract(c.getModifiers)) .foreach { modelClass ⇒ logger.info(s"Loading model $modelClass") modelBindings.addBinding.to(modelClass) @@ -50,7 +54,7 @@ class Module(environment: Environment, configuration: Configuration) extends Abs reflectionClasses .getSubTypesOf(classOf[AuthSrv]) .asScala - .filterNot(c ⇒ java.lang.reflect.Modifier.isAbstract(c.getModifiers) || c.isMemberClass) + .filterNot(c ⇒ Modifier.isAbstract(c.getModifiers) || c.isMemberClass) .filterNot(c ⇒ c == classOf[MultiAuthSrv] || c == classOf[CortexAuthSrv]) .foreach { authSrvClass ⇒ logger.info(s"Loading authentication module $authSrvClass") @@ -61,7 +65,7 @@ class Module(environment: Environment, configuration: Configuration) extends Abs reflectionClasses .getSubTypesOf(classOf[UserMapper]) .asScala - .filterNot(c ⇒ java.lang.reflect.Modifier.isAbstract(c.getModifiers) || c.isMemberClass) + .filterNot(c ⇒ Modifier.isAbstract(c.getModifiers) || c.isMemberClass) .filterNot(c ⇒ c == classOf[MultiUserMapperSrv]) .foreach(mapperCls ⇒ ssoMapperBindings.addBinding.to(mapperCls)) @@ -70,7 +74,7 @@ class Module(environment: Environment, configuration: Configuration) extends Abs else bind[AssetCtrl].to[AssetCtrlDev] - bind[org.elastic4play.services.UserSrv].to[UserSrv] + bind[EUserSrv].to[UserSrv] bind[Int].annotatedWith(Names.named("databaseVersion")).toInstance(models.modelVersion) bind[UserMapper].to[MultiUserMapperSrv] diff --git a/app/org/thp/cortex/controllers/AnalyzerConfigCtrl.scala b/app/org/thp/cortex/controllers/AnalyzerConfigCtrl.scala index 0ffa714c7..80ce00d1d 100644 --- a/app/org/thp/cortex/controllers/AnalyzerConfigCtrl.scala +++ b/app/org/thp/cortex/controllers/AnalyzerConfigCtrl.scala @@ -1,48 +1,56 @@ package org.thp.cortex.controllers -import javax.inject.{ Inject, Singleton } -import scala.concurrent.{ ExecutionContext, Future } +import javax.inject.{Inject, Singleton} +import scala.concurrent.{ExecutionContext, Future} import play.api.libs.json.JsObject -import play.api.mvc.{ AbstractController, Action, AnyContent, ControllerComponents } +import play.api.mvc.{AbstractController, Action, AnyContent, ControllerComponents} -import org.thp.cortex.models.{ BaseConfig, Roles } -import org.thp.cortex.services.{ AnalyzerConfigSrv, UserSrv } +import org.thp.cortex.models.{BaseConfig, Roles} +import org.thp.cortex.services.{AnalyzerConfigSrv, UserSrv} import org.elastic4play.BadRequestError -import org.elastic4play.controllers.{ Authenticated, Fields, FieldsBodyParser, Renderer } +import org.elastic4play.controllers.{Authenticated, Fields, FieldsBodyParser, Renderer} @Singleton -class AnalyzerConfigCtrl @Inject() ( +class AnalyzerConfigCtrl @Inject()( analyzerConfigSrv: AnalyzerConfigSrv, userSrv: UserSrv, authenticated: Authenticated, fieldsBodyParser: FieldsBodyParser, renderer: Renderer, components: ControllerComponents, - implicit val ec: ExecutionContext) extends AbstractController(components) { + implicit val ec: ExecutionContext +) extends AbstractController(components) { def get(analyzerConfigName: String): Action[AnyContent] = authenticated(Roles.orgAdmin).async { request ⇒ - analyzerConfigSrv.getForUser(request.userId, analyzerConfigName) + analyzerConfigSrv + .getForUser(request.userId, analyzerConfigName) .map(renderer.toOutput(OK, _)) } def list(): Action[AnyContent] = authenticated(Roles.orgAdmin).async { request ⇒ - analyzerConfigSrv.listConfigForUser(request.userId) + analyzerConfigSrv + .listConfigForUser(request.userId) .map { bc ⇒ - renderer.toOutput(OK, bc.sortWith { - case (BaseConfig("global", _, _, _), _) ⇒ true - case (_, BaseConfig("global", _, _, _)) ⇒ false - case (BaseConfig(a, _, _, _), BaseConfig(b, _, _, _)) ⇒ a.compareTo(b) < 0 - }) + renderer.toOutput( + OK, + bc.sortWith { + case (BaseConfig("global", _, _, _), _) ⇒ true + case (_, BaseConfig("global", _, _, _)) ⇒ false + case (BaseConfig(a, _, _, _), BaseConfig(b, _, _, _)) ⇒ a.compareTo(b) < 0 + } + ) } } def update(analyzerConfigName: String): Action[Fields] = authenticated(Roles.orgAdmin).async(fieldsBodyParser) { implicit request ⇒ request.body.getValue("config").flatMap(_.asOpt[JsObject]) match { - case Some(config) ⇒ analyzerConfigSrv.updateOrCreate(request.userId, analyzerConfigName, config) - .map(renderer.toOutput(OK, _)) + case Some(config) ⇒ + analyzerConfigSrv + .updateOrCreate(request.userId, analyzerConfigName, config) + .map(renderer.toOutput(OK, _)) case None ⇒ Future.failed(BadRequestError("attribute config has invalid format")) } } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/controllers/AnalyzerCtrl.scala b/app/org/thp/cortex/controllers/AnalyzerCtrl.scala index a6ce328b8..b967755a9 100644 --- a/app/org/thp/cortex/controllers/AnalyzerCtrl.scala +++ b/app/org/thp/cortex/controllers/AnalyzerCtrl.scala @@ -1,21 +1,21 @@ package org.thp.cortex.controllers -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} -import play.api.libs.json.{ JsObject, JsString, Json } -import play.api.mvc.{ AbstractController, Action, AnyContent, ControllerComponents } +import play.api.libs.json.{JsObject, JsString, Json} +import play.api.mvc.{AbstractController, Action, AnyContent, ControllerComponents} import akka.stream.Materializer -import javax.inject.{ Inject, Singleton } -import org.thp.cortex.models.{ Roles, Worker } -import org.thp.cortex.services.{ UserSrv, WorkerSrv } +import javax.inject.{Inject, Singleton} +import org.thp.cortex.models.{Roles, Worker} +import org.thp.cortex.services.{UserSrv, WorkerSrv} -import org.elastic4play.controllers.{ Authenticated, Fields, FieldsBodyParser, Renderer } +import org.elastic4play.controllers.{Authenticated, Fields, FieldsBodyParser, Renderer} import org.elastic4play.services.JsonFormat.queryReads -import org.elastic4play.services.{ QueryDSL, QueryDef } +import org.elastic4play.services.{QueryDSL, QueryDef} @Singleton -class AnalyzerCtrl @Inject() ( +class AnalyzerCtrl @Inject()( workerSrv: WorkerSrv, userSrv: UserSrv, authenticated: Authenticated, @@ -23,29 +23,30 @@ class AnalyzerCtrl @Inject() ( renderer: Renderer, components: ControllerComponents, implicit val ec: ExecutionContext, - implicit val mat: Materializer) extends AbstractController(components) { + implicit val mat: Materializer +) extends AbstractController(components) { def find: Action[Fields] = authenticated(Roles.read).async(fieldsBodyParser) { request ⇒ - val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) - val range = request.body.getString("range") - val sort = request.body.getStrings("sort").getOrElse(Nil) - val isAdmin = request.roles.contains(Roles.orgAdmin) + val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) + val range = request.body.getString("range") + val sort = request.body.getStrings("sort").getOrElse(Nil) + val isAdmin = request.roles.contains(Roles.orgAdmin) val (analyzers, analyzerTotal) = workerSrv.findAnalyzersForUser(request.userId, query, range, sort) renderer.toOutput(OK, analyzers.map(analyzerJson(isAdmin)), analyzerTotal) } def get(analyzerId: String): Action[AnyContent] = authenticated(Roles.read).async { request ⇒ val isAdmin = request.roles.contains(Roles.orgAdmin) - workerSrv.getForUser(request.userId, analyzerId) + workerSrv + .getForUser(request.userId, analyzerId) .map(a ⇒ renderer.toOutput(OK, analyzerJson(isAdmin)(a))) } - private def analyzerJson(isAdmin: Boolean)(analyzer: Worker): JsObject = { + private def analyzerJson(isAdmin: Boolean)(analyzer: Worker): JsObject = if (isAdmin) analyzer.toJson + ("configuration" → Json.parse(analyzer.configuration())) + ("analyzerDefinitionId" → JsString(analyzer.workerDefinitionId())) else analyzer.toJson + ("analyzerDefinitionId" → JsString(analyzer.workerDefinitionId())) - } def listForType(dataType: String): Action[AnyContent] = authenticated(Roles.read).async { request ⇒ import org.elastic4play.services.QueryDSL._ @@ -55,9 +56,9 @@ class AnalyzerCtrl @Inject() ( def create(analyzerDefinitionId: String): Action[Fields] = authenticated(Roles.orgAdmin).async(fieldsBodyParser) { implicit request ⇒ for { - organizationId ← userSrv.getOrganizationId(request.userId) + organizationId ← userSrv.getOrganizationId(request.userId) workerDefinition ← Future.fromTry(workerSrv.getDefinition(analyzerDefinitionId)) - analyzer ← workerSrv.create(organizationId, workerDefinition, request.body) + analyzer ← workerSrv.create(organizationId, workerDefinition, request.body) } yield renderer.toOutput(CREATED, analyzerJson(isAdmin = false)(analyzer)) } @@ -74,14 +75,14 @@ class AnalyzerCtrl @Inject() ( def delete(analyzerId: String): Action[AnyContent] = authenticated(Roles.orgAdmin, Roles.superAdmin).async { implicit request ⇒ for { analyzer ← workerSrv.getForUser(request.userId, analyzerId) - _ ← workerSrv.delete(analyzer) + _ ← workerSrv.delete(analyzer) } yield NoContent } def update(analyzerId: String): Action[Fields] = authenticated(Roles.orgAdmin).async(fieldsBodyParser) { implicit request ⇒ for { - analyzer ← workerSrv.getForUser(request.userId, analyzerId) + analyzer ← workerSrv.getForUser(request.userId, analyzerId) updatedAnalyzer ← workerSrv.update(analyzer, request.body) } yield renderer.toOutput(OK, analyzerJson(isAdmin = true)(updatedAnalyzer)) } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/controllers/AssetCtrl.scala b/app/org/thp/cortex/controllers/AssetCtrl.scala index 98076e64f..b3d9e29aa 100644 --- a/app/org/thp/cortex/controllers/AssetCtrl.scala +++ b/app/org/thp/cortex/controllers/AssetCtrl.scala @@ -1,9 +1,9 @@ package org.thp.cortex.controllers -import javax.inject.{ Inject, Singleton } -import play.api.http.{ FileMimeTypes, HttpErrorHandler } -import play.api.mvc.{ Action, AnyContent } -import controllers.{ Assets, AssetsMetadata, ExternalAssets } +import javax.inject.{Inject, Singleton} +import play.api.http.{FileMimeTypes, HttpErrorHandler} +import play.api.mvc.{Action, AnyContent} +import controllers.{Assets, AssetsMetadata, ExternalAssets} import play.api.Environment import scala.concurrent.ExecutionContext @@ -13,11 +13,13 @@ trait AssetCtrl { } @Singleton -class AssetCtrlProd @Inject() (errorHandler: HttpErrorHandler, meta: AssetsMetadata) extends Assets(errorHandler, meta) with AssetCtrl { +class AssetCtrlProd @Inject()(errorHandler: HttpErrorHandler, meta: AssetsMetadata) extends Assets(errorHandler, meta) with AssetCtrl { def get(file: String): Action[AnyContent] = at("/www", file) } @Singleton -class AssetCtrlDev @Inject() (environment: Environment)(implicit ec: ExecutionContext, fileMimeTypes: FileMimeTypes) extends ExternalAssets(environment) with AssetCtrl { +class AssetCtrlDev @Inject()(environment: Environment)(implicit ec: ExecutionContext, fileMimeTypes: FileMimeTypes) + extends ExternalAssets(environment) + with AssetCtrl { def get(file: String): Action[AnyContent] = at("www/dist", file) -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/controllers/AttachmentCtrl.scala b/app/org/thp/cortex/controllers/AttachmentCtrl.scala index 5fb21beaf..a3b534ec2 100644 --- a/app/org/thp/cortex/controllers/AttachmentCtrl.scala +++ b/app/org/thp/cortex/controllers/AttachmentCtrl.scala @@ -2,12 +2,12 @@ package org.thp.cortex.controllers import java.net.URLEncoder import java.nio.file.Files -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import play.api.http.HttpEntity import play.api.libs.Files.DefaultTemporaryFileCreator import play.api.mvc._ -import play.api.{ Configuration, mvc } +import play.api.{mvc, Configuration} import akka.stream.scaladsl.FileIO import net.lingala.zip4j.core.ZipFile @@ -16,7 +16,7 @@ import net.lingala.zip4j.util.Zip4jConstants import org.thp.cortex.models.Roles import org.elastic4play.Timed -import org.elastic4play.controllers.{ Authenticated, Renderer } +import org.elastic4play.controllers.{Authenticated, Renderer} import org.elastic4play.models.AttachmentAttributeFormat import org.elastic4play.services.AttachmentSrv @@ -30,7 +30,8 @@ class AttachmentCtrl( attachmentSrv: AttachmentSrv, authenticated: Authenticated, components: ControllerComponents, - renderer: Renderer) extends AbstractController(components) { + renderer: Renderer +) extends AbstractController(components) { @Inject() def this( configuration: Configuration, @@ -38,14 +39,9 @@ class AttachmentCtrl( attachmentSrv: AttachmentSrv, authenticated: Authenticated, components: ControllerComponents, - renderer: Renderer) = - this( - configuration.get[String]("datastore.attachment.password"), - tempFileCreator, - attachmentSrv, - authenticated, - components, - renderer) + renderer: Renderer + ) = + this(configuration.get[String]("datastore.attachment.password"), tempFileCreator, attachmentSrv, authenticated, components, renderer) /** * Download an attachment, identified by its hash, in plain format @@ -60,12 +56,10 @@ class AttachmentCtrl( mvc.Results.BadRequest("File name is invalid") else Result( - header = ResponseHeader( - 200, - Map( - "Content-Disposition" → s"""attachment; filename="${URLEncoder.encode(name.getOrElse(hash), "utf-8")}"""", - "Content-Transfer-Encoding" → "binary")), - body = HttpEntity.Streamed(attachmentSrv.source(hash), None, None)) + header = ResponseHeader(200, Map("Content-Disposition" → s"""attachment; filename="${URLEncoder + .encode(name.getOrElse(hash), "utf-8")}"""", "Content-Transfer-Encoding" → "binary")), + body = HttpEntity.Streamed(attachmentSrv.source(hash), None, None) + ) } /** @@ -80,7 +74,7 @@ class AttachmentCtrl( else { val f = tempFileCreator.create("zip", hash).path Files.delete(f) - val zipFile = new ZipFile(f.toFile) + val zipFile = new ZipFile(f.toFile) val zipParams = new ZipParameters zipParams.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_FASTEST) zipParams.setEncryptFiles(true) @@ -94,11 +88,14 @@ class AttachmentCtrl( header = ResponseHeader( 200, Map( - "Content-Disposition" → s"""attachment; filename="${URLEncoder.encode(name.getOrElse(hash), "utf-8")}.zip"""", - "Content-Type" → "application/zip", + "Content-Disposition" → s"""attachment; filename="${URLEncoder.encode(name.getOrElse(hash), "utf-8")}.zip"""", + "Content-Type" → "application/zip", "Content-Transfer-Encoding" → "binary", - "Content-Length" → Files.size(f).toString)), - body = HttpEntity.Streamed(FileIO.fromPath(f), Some(Files.size(f)), Some("application/zip"))) + "Content-Length" → Files.size(f).toString + ) + ), + body = HttpEntity.Streamed(FileIO.fromPath(f), Some(Files.size(f)), Some("application/zip")) + ) } } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/controllers/AuthenticationCtrl.scala b/app/org/thp/cortex/controllers/AuthenticationCtrl.scala index 6eb37af00..d797e3619 100644 --- a/app/org/thp/cortex/controllers/AuthenticationCtrl.scala +++ b/app/org/thp/cortex/controllers/AuthenticationCtrl.scala @@ -1,21 +1,21 @@ package org.thp.cortex.controllers -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import play.api.mvc._ -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import org.thp.cortex.models.UserStatus import org.thp.cortex.services.UserSrv -import org.elastic4play.controllers.{ Authenticated, Fields, FieldsBodyParser, Renderer } +import org.elastic4play.controllers.{Authenticated, Fields, FieldsBodyParser, Renderer} import org.elastic4play.database.DBIndex import org.elastic4play.services.AuthSrv import org.elastic4play.services.JsonFormat.authContextWrites -import org.elastic4play.{ AuthorizationError, MissingAttributeError, OAuth2Redirect, Timed } +import org.elastic4play.{AuthorizationError, MissingAttributeError, OAuth2Redirect, Timed} @Singleton -class AuthenticationCtrl @Inject() ( +class AuthenticationCtrl @Inject()( authSrv: AuthSrv, userSrv: UserSrv, authenticated: Authenticated, @@ -23,7 +23,8 @@ class AuthenticationCtrl @Inject() ( renderer: Renderer, components: ControllerComponents, fieldsBodyParser: FieldsBodyParser, - implicit val ec: ExecutionContext) extends AbstractController(components) { + implicit val ec: ExecutionContext +) extends AbstractController(components) { @Timed def login: Action[Fields] = Action.async(fieldsBodyParser) { implicit request ⇒ @@ -31,8 +32,8 @@ class AuthenticationCtrl @Inject() ( case false ⇒ Future.successful(Results.Status(520)) case _ ⇒ for { - user ← request.body.getString("user").fold[Future[String]](Future.failed(MissingAttributeError("user")))(Future.successful) - password ← request.body.getString("password").fold[Future[String]](Future.failed(MissingAttributeError("password")))(Future.successful) + user ← request.body.getString("user").fold[Future[String]](Future.failed(MissingAttributeError("user")))(Future.successful) + password ← request.body.getString("password").fold[Future[String]](Future.failed(MissingAttributeError("password")))(Future.successful) authContext ← authSrv.authenticate(user, password) } yield authenticated.setSessingUser(renderer.toOutput(OK, authContext), authContext) } @@ -45,7 +46,7 @@ class AuthenticationCtrl @Inject() ( case _ ⇒ (for { authContext ← authSrv.authenticate() - user ← userSrv.get(authContext.userId) + user ← userSrv.get(authContext.userId) } yield { if (user.status() == UserStatus.Ok) authenticated.setSessingUser(Ok, authContext) @@ -63,4 +64,4 @@ class AuthenticationCtrl @Inject() ( def logout = Action { Ok.withNewSession } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/controllers/DBListCtrl.scala b/app/org/thp/cortex/controllers/DBListCtrl.scala index aa47fa631..44325e20e 100644 --- a/app/org/thp/cortex/controllers/DBListCtrl.scala +++ b/app/org/thp/cortex/controllers/DBListCtrl.scala @@ -1,26 +1,27 @@ package org.thp.cortex.controllers -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} -import play.api.libs.json.{ JsValue, Json } +import play.api.libs.json.{JsValue, Json} import play.api.mvc._ import org.thp.cortex.models.Roles -import org.elastic4play.controllers.{ Authenticated, Fields, FieldsBodyParser, Renderer } +import org.elastic4play.controllers.{Authenticated, Fields, FieldsBodyParser, Renderer} import org.elastic4play.services.DBLists import org.elastic4play.MissingAttributeError @Singleton -class DBListCtrl @Inject() ( +class DBListCtrl @Inject()( dblists: DBLists, authenticated: Authenticated, renderer: Renderer, components: ControllerComponents, fieldsBodyParser: FieldsBodyParser, - implicit val ec: ExecutionContext) extends AbstractController(components) { + implicit val ec: ExecutionContext +) extends AbstractController(components) { def list: Action[AnyContent] = authenticated(Roles.read).async { _ ⇒ dblists.listAll.map { listNames ⇒ @@ -30,7 +31,8 @@ class DBListCtrl @Inject() ( def listItems(listName: String): Action[AnyContent] = authenticated(Roles.read) { _ ⇒ val (src, _) = dblists(listName).getItems[JsValue] - val items = src.map { case (id, value) ⇒ s""""$id":$value""" } + val items = src + .map { case (id, value) ⇒ s""""$id":$value""" } .intersperse("{", ",", "}") Ok.chunked(items).as("application/json") } @@ -50,11 +52,13 @@ class DBListCtrl @Inject() ( } def updateItem(itemId: String): Action[Fields] = authenticated(Roles.superAdmin).async(fieldsBodyParser) { implicit request ⇒ - request.body.getValue("value") + request + .body + .getValue("value") .map { value ⇒ for { - item ← dblists.getItem(itemId) - _ ← dblists.deleteItem(item) + item ← dblists.getItem(itemId) + _ ← dblists.deleteItem(item) newItem ← dblists(item.dblist).addItem(value) } yield renderer.toOutput(OK, newItem.id) } @@ -62,8 +66,8 @@ class DBListCtrl @Inject() ( } def itemExists(listName: String): Action[Fields] = authenticated(Roles.read).async(fieldsBodyParser) { implicit request ⇒ - val itemKey = request.body.getString("key").getOrElse(throw MissingAttributeError("Parameter key is missing")) + val itemKey = request.body.getString("key").getOrElse(throw MissingAttributeError("Parameter key is missing")) val itemValue = request.body.getValue("value").getOrElse(throw MissingAttributeError("Parameter value is missing")) dblists(listName).exists(itemKey, itemValue).map(r ⇒ Ok(Json.obj("found" → r))) } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/controllers/Home.scala b/app/org/thp/cortex/controllers/Home.scala index 9f111ece4..5e4dcfec8 100644 --- a/app/org/thp/cortex/controllers/Home.scala +++ b/app/org/thp/cortex/controllers/Home.scala @@ -1,13 +1,14 @@ package org.thp.cortex.controllers import play.api.Configuration -import play.api.mvc.{ AbstractController, Action, AnyContent, ControllerComponents } +import play.api.mvc.{AbstractController, Action, AnyContent, ControllerComponents} -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} @Singleton -class Home @Inject() (configuration: Configuration, components: ControllerComponents) extends AbstractController(components) { +class Home @Inject()(configuration: Configuration, components: ControllerComponents) extends AbstractController(components) { + def redirect: Action[AnyContent] = Action { Redirect(configuration.get[String]("play.http.context").stripSuffix("/") + "/index.html") } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/controllers/JobCtrl.scala b/app/org/thp/cortex/controllers/JobCtrl.scala index 7e49eeb22..40e0b349a 100644 --- a/app/org/thp/cortex/controllers/JobCtrl.scala +++ b/app/org/thp/cortex/controllers/JobCtrl.scala @@ -1,30 +1,30 @@ package org.thp.cortex.controllers -import scala.concurrent.duration.{ Duration, FiniteDuration } -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.duration.{Duration, FiniteDuration} +import scala.concurrent.{ExecutionContext, Future} import play.api.http.Status -import play.api.libs.json.{ JsObject, JsString, JsValue, Json } -import play.api.mvc.{ AbstractController, Action, AnyContent, ControllerComponents } +import play.api.libs.json.{JsObject, JsString, JsValue, Json} +import play.api.mvc.{AbstractController, Action, AnyContent, ControllerComponents} -import akka.actor.{ ActorRef, ActorSystem } +import akka.actor.{ActorRef, ActorSystem} import akka.pattern.ask import akka.stream.Materializer import akka.stream.scaladsl.Sink import akka.util.Timeout -import javax.inject.{ Inject, Named, Singleton } -import org.thp.cortex.models.{ Job, JobStatus, Roles } -import org.thp.cortex.services.AuditActor.{ JobEnded, Register } +import javax.inject.{Inject, Named, Singleton} +import org.thp.cortex.models.{Job, JobStatus, Roles} +import org.thp.cortex.services.AuditActor.{JobEnded, Register} import org.thp.cortex.services.JobSrv -import org.elastic4play.controllers.{ Authenticated, Fields, FieldsBodyParser, Renderer } +import org.elastic4play.controllers.{Authenticated, Fields, FieldsBodyParser, Renderer} import org.elastic4play.models.JsonFormat.baseModelEntityWrites import org.elastic4play.services.JsonFormat.queryReads -import org.elastic4play.services.{ QueryDSL, QueryDef } +import org.elastic4play.services.{QueryDSL, QueryDef} import org.elastic4play.utils.RichFuture @Singleton -class JobCtrl @Inject() ( +class JobCtrl @Inject()( jobSrv: JobSrv, @Named("audit") auditActor: ActorRef, fieldsBodyParser: FieldsBodyParser, @@ -33,19 +33,22 @@ class JobCtrl @Inject() ( components: ControllerComponents, implicit val ec: ExecutionContext, implicit val mat: Materializer, - implicit val actorSystem: ActorSystem) extends AbstractController(components) with Status { - - def list(dataTypeFilter: Option[String], dataFilter: Option[String], workerFilter: Option[String], range: Option[String]): Action[AnyContent] = authenticated(Roles.read).async { implicit request ⇒ - val (jobs, jobTotal) = jobSrv.listForUser(request.userId, dataTypeFilter, dataFilter, workerFilter, range) - renderer.toOutput(OK, jobs, jobTotal) - } + implicit val actorSystem: ActorSystem +) extends AbstractController(components) + with Status { + + def list(dataTypeFilter: Option[String], dataFilter: Option[String], workerFilter: Option[String], range: Option[String]): Action[AnyContent] = + authenticated(Roles.read).async { implicit request ⇒ + val (jobs, jobTotal) = jobSrv.listForUser(request.userId, dataTypeFilter, dataFilter, workerFilter, range) + renderer.toOutput(OK, jobs, jobTotal) + } def find: Action[Fields] = authenticated(Roles.read).async(fieldsBodyParser) { implicit request ⇒ import QueryDSL._ - val deleteFilter = "status" ~!= "Deleted" - val query = request.body.getValue("query").fold[QueryDef](deleteFilter)(q ⇒ and(q.as[QueryDef], deleteFilter)) - val range = request.body.getString("range") - val sort = request.body.getStrings("sort").getOrElse(Nil) + val deleteFilter = "status" ~!= "Deleted" + val query = request.body.getValue("query").fold[QueryDef](deleteFilter)(q ⇒ and(q.as[QueryDef], deleteFilter)) + val range = request.body.getString("range") + val sort = request.body.getStrings("sort").getOrElse(Nil) val (jobs, total) = jobSrv.findForUser(request.userId, query, range, sort) renderer.toOutput(OK, jobs, total) @@ -58,7 +61,8 @@ class JobCtrl @Inject() ( } def delete(jobId: String): Action[AnyContent] = authenticated(Roles.analyze, Roles.orgAdmin).async { implicit request ⇒ - jobSrv.getForUser(request.userId, jobId) + jobSrv + .getForUser(request.userId, jobId) .flatMap(job ⇒ jobSrv.delete(job)) .map(_ ⇒ NoContent) } @@ -69,24 +73,25 @@ class JobCtrl @Inject() ( case Some(d) ⇒ fields.set("data", d.toString) case None ⇒ fields } - jobSrv.create(workerId, fieldsWithStringData) + jobSrv + .create(workerId, fieldsWithStringData) .map { job ⇒ renderer.toOutput(OK, job) } } def createAnalyzerJob(workerId: String): Action[Fields] = authenticated(Roles.analyze).async(fieldsBodyParser) { implicit request ⇒ - jobSrv.create(workerId, request.body) + jobSrv + .create(workerId, request.body) .map { job ⇒ renderer.toOutput(OK, job) } } - private def getJobWithReport(userId: String, jobId: String): Future[JsValue] = { + private def getJobWithReport(userId: String, jobId: String): Future[JsValue] = jobSrv.getForUser(userId, jobId).flatMap(getJobWithReport(userId, _)) - } - private def getJobWithReport(userId: String, job: Job): Future[JsValue] = { + private def getJobWithReport(userId: String, job: Job): Future[JsValue] = (job.status() match { case JobStatus.Success ⇒ for { @@ -96,56 +101,51 @@ class JobCtrl @Inject() ( .collect { case artifact if artifact.data().isDefined ⇒ Json.obj( - "data" → artifact.data(), + "data" → artifact.data(), "dataType" → artifact.dataType(), - "message" → artifact.message(), - "tags" → artifact.tags(), - "tlp" → artifact.tlp()) + "message" → artifact.message(), + "tags" → artifact.tags(), + "tlp" → artifact.tlp() + ) case artifact if artifact.attachment().isDefined ⇒ artifact.attachment().fold(JsObject.empty) { a ⇒ Json.obj( "attachment" → - Json.obj( - "contentType" → a.contentType, - "id" → a.id, - "name" → a.name, - "size" → a.size), + Json.obj("contentType" → a.contentType, "id" → a.id, "name" → a.name, "size" → a.size), "message" → artifact.message(), - "tags" → artifact.tags(), - "tlp" → artifact.tlp()) + "tags" → artifact.tags(), + "tlp" → artifact.tlp() + ) } } .runWith(Sink.seq) } yield Json.obj( - "summary" → Json.parse(report.summary()), - "full" → Json.parse(report.full()), - "success" → true, - "artifacts" → artifacts, - "operations" → Json.parse(report.operations())) + "summary" → Json.parse(report.summary()), + "full" → Json.parse(report.full()), + "success" → true, + "artifacts" → artifacts, + "operations" → Json.parse(report.operations()) + ) case JobStatus.Failure ⇒ val errorMessage = job.errorMessage().getOrElse("") - Future.successful(Json.obj( - "errorMessage" → errorMessage, - "input" → job.input(), - "success" → false)) + Future.successful(Json.obj("errorMessage" → errorMessage, "input" → job.input(), "success" → false)) case JobStatus.InProgress ⇒ Future.successful(JsString("Running")) case JobStatus.Waiting ⇒ Future.successful(JsString("Waiting")) case JobStatus.Deleted ⇒ Future.successful(JsString("Deleted")) - }) - .map { report ⇒ - Json.toJson(job).as[JsObject] + ("report" → report) - } - } + }).map { report ⇒ + Json.toJson(job).as[JsObject] + ("report" → report) + } def report(jobId: String): Action[AnyContent] = authenticated(Roles.read).async { implicit request ⇒ getJobWithReport(request.userId, jobId).map(Ok(_)) } def waitReport(jobId: String, atMost: String): Action[AnyContent] = authenticated(Roles.read).async { implicit request ⇒ - jobSrv.getForUser(request.userId, jobId) + jobSrv + .getForUser(request.userId, jobId) .flatMap { case job if job.status() == JobStatus.InProgress || job.status() == JobStatus.Waiting ⇒ - val duration = Duration(atMost).asInstanceOf[FiniteDuration] + val duration = Duration(atMost).asInstanceOf[FiniteDuration] implicit val timeout: Timeout = Timeout(duration) (auditActor ? Register(jobId, duration)) .mapTo[JobEnded] @@ -159,10 +159,10 @@ class JobCtrl @Inject() ( } def listArtifacts(jobId: String): Action[Fields] = authenticated(Roles.read).async(fieldsBodyParser) { implicit request ⇒ - val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) - val range = request.body.getString("range") - val sort = request.body.getStrings("sort").getOrElse(Nil) + val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) + val range = request.body.getString("range") + val sort = request.body.getStrings("sort").getOrElse(Nil) val (artifacts, total) = jobSrv.findArtifacts(request.userId, jobId, query, range, sort) renderer.toOutput(OK, artifacts, total) } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/controllers/MispCtrl.scala b/app/org/thp/cortex/controllers/MispCtrl.scala index 9ff6759ce..47009d559 100644 --- a/app/org/thp/cortex/controllers/MispCtrl.scala +++ b/app/org/thp/cortex/controllers/MispCtrl.scala @@ -1,23 +1,24 @@ package org.thp.cortex.controllers import javax.inject.Inject -import org.elastic4play.controllers.{ Authenticated, Fields, FieldsBodyParser, Renderer } +import org.elastic4play.controllers.{Authenticated, Fields, FieldsBodyParser, Renderer} import org.thp.cortex.models.Roles -import org.thp.cortex.services.{ WorkerSrv, MispSrv } +import org.thp.cortex.services.{MispSrv, WorkerSrv} import play.api.Logger -import play.api.libs.json.{ JsObject, JsValue } +import play.api.libs.json.{JsObject, JsValue} import play.api.mvc._ -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} -class MispCtrl @Inject() ( +class MispCtrl @Inject()( mispSrv: MispSrv, analyzerSrv: WorkerSrv, authenticated: Authenticated, fieldsBodyParser: FieldsBodyParser, renderer: Renderer, components: ControllerComponents, - implicit val ec: ExecutionContext) extends AbstractController(components) { + implicit val ec: ExecutionContext +) extends AbstractController(components) { private[MispCtrl] lazy val logger = Logger(getClass) @@ -27,20 +28,24 @@ class MispCtrl @Inject() ( } def query: Action[JsValue] = authenticated(Roles.analyze)(parse.json).async { implicit request ⇒ - (request.body \ "module").asOpt[String] + (request.body \ "module") + .asOpt[String] .fold(Future.successful(BadRequest("Module parameter is not present in request"))) { module ⇒ - request.body.as[JsObject].fields + request + .body + .as[JsObject] + .fields .collectFirst { case kv @ (k, _) if k != "module" ⇒ kv } .fold(Future.successful(BadRequest("Request doesn't contain data to analyze"))) { case (mispType, dataJson) ⇒ dataJson.asOpt[String].fold(Future.successful(BadRequest("Data has invalid type (expected string)"))) { data ⇒ - mispSrv.query(module, mispType, data) + mispSrv + .query(module, mispType, data) .map(Ok(_)) } } } } } - diff --git a/app/org/thp/cortex/controllers/OrganizationCtrl.scala b/app/org/thp/cortex/controllers/OrganizationCtrl.scala index 618b5aafd..a8d5127ec 100644 --- a/app/org/thp/cortex/controllers/OrganizationCtrl.scala +++ b/app/org/thp/cortex/controllers/OrganizationCtrl.scala @@ -1,24 +1,24 @@ package org.thp.cortex.controllers -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import play.api.Logger import play.api.http.Status import play.api.mvc._ import org.thp.cortex.models.Roles -import org.thp.cortex.services.{ OrganizationSrv, UserSrv } +import org.thp.cortex.services.{OrganizationSrv, UserSrv} -import org.elastic4play.{ BadRequestError, NotFoundError } -import org.elastic4play.controllers.{ Authenticated, Fields, FieldsBodyParser, Renderer } +import org.elastic4play.{BadRequestError, NotFoundError} +import org.elastic4play.controllers.{Authenticated, Fields, FieldsBodyParser, Renderer} import org.elastic4play.models.JsonFormat.baseModelEntityWrites -import org.elastic4play.services.JsonFormat.{ aggReads, queryReads } -import org.elastic4play.services.{ UserSrv ⇒ _, _ } +import org.elastic4play.services.JsonFormat.{aggReads, queryReads} +import org.elastic4play.services.{UserSrv ⇒ _, _} @Singleton -class OrganizationCtrl @Inject() ( +class OrganizationCtrl @Inject()( organizationSrv: OrganizationSrv, authSrv: AuthSrv, auxSrv: AuxSrv, @@ -27,12 +27,15 @@ class OrganizationCtrl @Inject() ( renderer: Renderer, fieldsBodyParser: FieldsBodyParser, components: ControllerComponents, - implicit val ec: ExecutionContext) extends AbstractController(components) with Status { + implicit val ec: ExecutionContext +) extends AbstractController(components) + with Status { private[OrganizationCtrl] lazy val logger = Logger(getClass) def create: Action[Fields] = authenticated(Roles.superAdmin).async(fieldsBodyParser) { implicit request ⇒ - organizationSrv.create(request.body) + organizationSrv + .create(request.body) .map(organization ⇒ renderer.toOutput(CREATED, organization)) } @@ -42,7 +45,7 @@ class OrganizationCtrl @Inject() ( userOrganizationId ← if (request.roles.contains(Roles.superAdmin)) Future.successful(organizationId) else userSrv.getOrganizationId(request.userId) if userOrganizationId == organizationId - organization ← organizationSrv.get(organizationId) + organization ← organizationSrv.get(organizationId) organizationWithStats ← auxSrv(organization, 0, withStats, removeUnaudited = false) } yield renderer.toOutput(OK, organizationWithStats)) .recoverWith { case _: NoSuchElementException ⇒ Future.failed(NotFoundError(s"organization $organizationId not found")) } @@ -61,23 +64,24 @@ class OrganizationCtrl @Inject() ( if (organizationId == "cortex") Future.failed(BadRequestError("Cortex organization can't be removed")) else - organizationSrv.delete(organizationId) + organizationSrv + .delete(organizationId) .map(_ ⇒ NoContent) } def find: Action[Fields] = authenticated(Roles.superAdmin).async(fieldsBodyParser) { implicit request ⇒ - val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) - val range = request.body.getString("range") - val sort = request.body.getStrings("sort").getOrElse(Nil) - val withStats = request.body.getBoolean("nstats").getOrElse(false) + val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) + val range = request.body.getString("range") + val sort = request.body.getStrings("sort").getOrElse(Nil) + val withStats = request.body.getBoolean("nstats").getOrElse(false) val (organizations, total) = organizationSrv.find(query, range, sort) - val organizationWithStats = auxSrv(organizations, 0, withStats, removeUnaudited = false) + val organizationWithStats = auxSrv(organizations, 0, withStats, removeUnaudited = false) renderer.toOutput(OK, organizationWithStats, total) } def stats(): Action[Fields] = authenticated(Roles.superAdmin).async(fieldsBodyParser) { implicit request ⇒ val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) - val aggs = request.body.getValue("stats").getOrElse(throw BadRequestError("Parameter \"stats\" is missing")).as[Seq[Agg]] + val aggs = request.body.getValue("stats").getOrElse(throw BadRequestError("Parameter \"stats\" is missing")).as[Seq[Agg]] organizationSrv.stats(query, aggs).map(s ⇒ Ok(s)) } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/controllers/ResponderConfigCtrl.scala b/app/org/thp/cortex/controllers/ResponderConfigCtrl.scala index 508661263..52705f5c4 100644 --- a/app/org/thp/cortex/controllers/ResponderConfigCtrl.scala +++ b/app/org/thp/cortex/controllers/ResponderConfigCtrl.scala @@ -1,48 +1,56 @@ package org.thp.cortex.controllers -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import play.api.libs.json.JsObject -import play.api.mvc.{ AbstractController, Action, AnyContent, ControllerComponents } +import play.api.mvc.{AbstractController, Action, AnyContent, ControllerComponents} -import javax.inject.{ Inject, Singleton } -import org.thp.cortex.models.{ BaseConfig, Roles } -import org.thp.cortex.services.{ ResponderConfigSrv, UserSrv } +import javax.inject.{Inject, Singleton} +import org.thp.cortex.models.{BaseConfig, Roles} +import org.thp.cortex.services.{ResponderConfigSrv, UserSrv} import org.elastic4play.BadRequestError -import org.elastic4play.controllers.{ Authenticated, Fields, FieldsBodyParser, Renderer } +import org.elastic4play.controllers.{Authenticated, Fields, FieldsBodyParser, Renderer} @Singleton -class ResponderConfigCtrl @Inject() ( +class ResponderConfigCtrl @Inject()( responderConfigSrv: ResponderConfigSrv, userSrv: UserSrv, authenticated: Authenticated, fieldsBodyParser: FieldsBodyParser, renderer: Renderer, components: ControllerComponents, - implicit val ec: ExecutionContext) extends AbstractController(components) { + implicit val ec: ExecutionContext +) extends AbstractController(components) { def get(analyzerConfigName: String): Action[AnyContent] = authenticated(Roles.orgAdmin).async { request ⇒ - responderConfigSrv.getForUser(request.userId, analyzerConfigName) + responderConfigSrv + .getForUser(request.userId, analyzerConfigName) .map(renderer.toOutput(OK, _)) } def list(): Action[AnyContent] = authenticated(Roles.orgAdmin).async { request ⇒ - responderConfigSrv.listConfigForUser(request.userId) + responderConfigSrv + .listConfigForUser(request.userId) .map { bc ⇒ - renderer.toOutput(OK, bc.sortWith { - case (BaseConfig("global", _, _, _), _) ⇒ true - case (_, BaseConfig("global", _, _, _)) ⇒ false - case (BaseConfig(a, _, _, _), BaseConfig(b, _, _, _)) ⇒ a.compareTo(b) < 0 - }) + renderer.toOutput( + OK, + bc.sortWith { + case (BaseConfig("global", _, _, _), _) ⇒ true + case (_, BaseConfig("global", _, _, _)) ⇒ false + case (BaseConfig(a, _, _, _), BaseConfig(b, _, _, _)) ⇒ a.compareTo(b) < 0 + } + ) } } def update(analyzerConfigName: String): Action[Fields] = authenticated(Roles.orgAdmin).async(fieldsBodyParser) { implicit request ⇒ request.body.getValue("config").flatMap(_.asOpt[JsObject]) match { - case Some(config) ⇒ responderConfigSrv.updateOrCreate(request.userId, analyzerConfigName, config) - .map(renderer.toOutput(OK, _)) + case Some(config) ⇒ + responderConfigSrv + .updateOrCreate(request.userId, analyzerConfigName, config) + .map(renderer.toOutput(OK, _)) case None ⇒ Future.failed(BadRequestError("attribute config has invalid format")) } } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/controllers/ResponderCtrl.scala b/app/org/thp/cortex/controllers/ResponderCtrl.scala index 9e5246445..694faa11b 100644 --- a/app/org/thp/cortex/controllers/ResponderCtrl.scala +++ b/app/org/thp/cortex/controllers/ResponderCtrl.scala @@ -1,22 +1,22 @@ package org.thp.cortex.controllers -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} -import play.api.libs.json.{ JsNumber, JsObject, Json } -import play.api.mvc.{ AbstractController, Action, AnyContent, ControllerComponents } +import play.api.libs.json.{JsNumber, JsObject, Json} +import play.api.mvc.{AbstractController, Action, AnyContent, ControllerComponents} import akka.stream.Materializer -import javax.inject.{ Inject, Singleton } -import org.thp.cortex.models.{ Roles, Worker, WorkerDefinition } -import org.thp.cortex.services.{ UserSrv, WorkerSrv } +import javax.inject.{Inject, Singleton} +import org.thp.cortex.models.{Roles, Worker, WorkerDefinition} +import org.thp.cortex.services.{UserSrv, WorkerSrv} -import org.elastic4play.controllers.{ Authenticated, Fields, FieldsBodyParser, Renderer } +import org.elastic4play.controllers.{Authenticated, Fields, FieldsBodyParser, Renderer} import org.elastic4play.models.JsonFormat.baseModelEntityWrites import org.elastic4play.services.JsonFormat.queryReads -import org.elastic4play.services.{ QueryDSL, QueryDef } +import org.elastic4play.services.{QueryDSL, QueryDef} @Singleton -class ResponderCtrl @Inject() ( +class ResponderCtrl @Inject()( workerSrv: WorkerSrv, userSrv: UserSrv, authenticated: Authenticated, @@ -24,51 +24,47 @@ class ResponderCtrl @Inject() ( renderer: Renderer, components: ControllerComponents, implicit val ec: ExecutionContext, - implicit val mat: Materializer) extends AbstractController(components) { + implicit val mat: Materializer +) extends AbstractController(components) { def find: Action[Fields] = authenticated(Roles.read).async(fieldsBodyParser) { request ⇒ - val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) - val range = request.body.getString("range") - val sort = request.body.getStrings("sort").getOrElse(Nil) - val isAdmin = request.roles.contains(Roles.orgAdmin) + val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) + val range = request.body.getString("range") + val sort = request.body.getStrings("sort").getOrElse(Nil) + val isAdmin = request.roles.contains(Roles.orgAdmin) val (responders, responderTotal) = workerSrv.findRespondersForUser(request.userId, query, range, sort) renderer.toOutput(OK, responders.map(responderJson(isAdmin)), responderTotal) } def get(responderId: String): Action[AnyContent] = authenticated(Roles.read).async { request ⇒ val isAdmin = request.roles.contains(Roles.orgAdmin) - workerSrv.getForUser(request.userId, responderId) + workerSrv + .getForUser(request.userId, responderId) .map(responder ⇒ renderer.toOutput(OK, responderJson(isAdmin)(responder))) } - private val emptyResponderDefinitionJson = Json.obj( - "version" → "0.0", - "description" → "unknown", - "dataTypeList" → Nil, - "author" → "unknown", - "url" → "unknown", - "license" → "unknown") + private val emptyResponderDefinitionJson = + Json.obj("version" → "0.0", "description" → "unknown", "dataTypeList" → Nil, "author" → "unknown", "url" → "unknown", "license" → "unknown") - private def responderJson(responder: Worker, responderDefinition: Option[WorkerDefinition]) = { + private def responderJson(responder: Worker, responderDefinition: Option[WorkerDefinition]) = responder.toJson ++ responderDefinition.fold(emptyResponderDefinitionJson) { ad ⇒ Json.obj( - "maxTlp" → (responder.config \ "max_tlp").asOpt[JsNumber], - "maxPap" → (responder.config \ "max_pap").asOpt[JsNumber], - "version" → ad.version, + "maxTlp" → (responder.config \ "max_tlp").asOpt[JsNumber], + "maxPap" → (responder.config \ "max_pap").asOpt[JsNumber], + "version" → ad.version, "description" → ad.description, - "author" → ad.author, - "url" → ad.url, - "license" → ad.license, - "baseConfig" → ad.baseConfiguration) + "author" → ad.author, + "url" → ad.url, + "license" → ad.license, + "baseConfig" → ad.baseConfiguration + ) } - } - private def responderJson(isAdmin: Boolean)(responder: Worker): JsObject = { + private def responderJson(isAdmin: Boolean)(responder: Worker): JsObject = if (isAdmin) responder.toJson + ("configuration" → Json.parse(responder.configuration())) else responder.toJson - } def listForType(dataType: String): Action[AnyContent] = authenticated(Roles.read).async { request ⇒ import org.elastic4play.services.QueryDSL._ @@ -78,9 +74,9 @@ class ResponderCtrl @Inject() ( def create(responderDefinitionId: String): Action[Fields] = authenticated(Roles.orgAdmin).async(fieldsBodyParser) { implicit request ⇒ for { - organizationId ← userSrv.getOrganizationId(request.userId) + organizationId ← userSrv.getOrganizationId(request.userId) workerDefinition ← Future.fromTry(workerSrv.getDefinition(responderDefinitionId)) - responder ← workerSrv.create(organizationId, workerDefinition, request.body) + responder ← workerSrv.create(organizationId, workerDefinition, request.body) } yield renderer.toOutput(CREATED, responderJson(responder, Some(workerDefinition))) } @@ -97,14 +93,14 @@ class ResponderCtrl @Inject() ( def delete(responderId: String): Action[AnyContent] = authenticated(Roles.orgAdmin, Roles.superAdmin).async { implicit request ⇒ for { responder ← workerSrv.getForUser(request.userId, responderId) - _ ← workerSrv.delete(responder) + _ ← workerSrv.delete(responder) } yield NoContent } def update(responderId: String): Action[Fields] = authenticated(Roles.orgAdmin).async(fieldsBodyParser) { implicit request ⇒ for { - responder ← workerSrv.getForUser(request.userId, responderId) + responder ← workerSrv.getForUser(request.userId, responderId) updatedResponder ← workerSrv.update(responder, request.body) } yield renderer.toOutput(OK, responderJson(isAdmin = true)(updatedResponder)) } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/controllers/StatusCtrl.scala b/app/org/thp/cortex/controllers/StatusCtrl.scala index 859ae2d5f..65f2b84b8 100644 --- a/app/org/thp/cortex/controllers/StatusCtrl.scala +++ b/app/org/thp/cortex/controllers/StatusCtrl.scala @@ -1,15 +1,16 @@ package org.thp.cortex.controllers -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import scala.concurrent.ExecutionContext import play.api.Configuration import play.api.http.Status -import play.api.libs.json.{ JsBoolean, JsString, Json } +import play.api.libs.json.{JsBoolean, JsString, Json} import play.api.libs.json.Json.toJsFieldJsValueWrapper -import play.api.mvc.{ AbstractController, Action, AnyContent, ControllerComponents } +import play.api.mvc.{AbstractController, Action, AnyContent, ControllerComponents} import com.sksamuel.elastic4s.http.ElasticDsl +import org.elasticsearch.client.Node import org.thp.cortex.models.Worker import org.elastic4play.database.DBIndex @@ -17,31 +18,41 @@ import org.elastic4play.services.AuthSrv import org.elastic4play.services.auth.MultiAuthSrv @Singleton -class StatusCtrl @Inject() ( +class StatusCtrl @Inject()( configuration: Configuration, authSrv: AuthSrv, dbIndex: DBIndex, components: ControllerComponents, - implicit val ec: ExecutionContext) extends AbstractController(components) with Status { + implicit val ec: ExecutionContext +) extends AbstractController(components) + with Status { private[controllers] def getVersion(c: Class[_]) = Option(c.getPackage.getImplementationVersion).getOrElse("SNAPSHOT") def get: Action[AnyContent] = Action { - Ok(Json.obj( + Ok( + Json.obj( "versions" → Json.obj( - "Cortex" → getVersion(classOf[Worker]), - "Elastic4Play" → getVersion(classOf[AuthSrv]), - "Play" → getVersion(classOf[AbstractController]), - "Elastic4s" → getVersion(classOf[ElasticDsl]), - "ElasticSearch client" → getVersion(classOf[org.elasticsearch.client.Node])), + "Cortex" → getVersion(classOf[Worker]), + "Elastic4Play" → getVersion(classOf[AuthSrv]), + "Play" → getVersion(classOf[AbstractController]), + "Elastic4s" → getVersion(classOf[ElasticDsl]), + "ElasticSearch client" → getVersion(classOf[Node]) + ), "config" → Json.obj( "authType" → (authSrv match { - case multiAuthSrv: MultiAuthSrv ⇒ multiAuthSrv.authProviders.map { a ⇒ JsString(a.name) } - case _ ⇒ JsString(authSrv.name) + case multiAuthSrv: MultiAuthSrv ⇒ + multiAuthSrv.authProviders.map { a ⇒ + JsString(a.name) + } + case _ ⇒ JsString(authSrv.name) }), "capabilities" → authSrv.capabilities.map(c ⇒ JsString(c.toString)), - "ssoAutoLogin" → JsBoolean(configuration.getOptional[Boolean]("auth.sso.autologin").getOrElse(false))))) - } + "ssoAutoLogin" → JsBoolean(configuration.getOptional[Boolean]("auth.sso.autologin").getOrElse(false)) + ) + ) + ) + } def health: Action[AnyContent] = TODO } diff --git a/app/org/thp/cortex/controllers/StreamCtrl.scala b/app/org/thp/cortex/controllers/StreamCtrl.scala index d6fd9bc03..e5aab089c 100644 --- a/app/org/thp/cortex/controllers/StreamCtrl.scala +++ b/app/org/thp/cortex/controllers/StreamCtrl.scala @@ -1,18 +1,18 @@ package org.thp.cortex.controllers -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import scala.collection.immutable -import scala.concurrent.{ ExecutionContext, Future } -import scala.concurrent.duration.{ DurationLong, FiniteDuration } +import scala.concurrent.{ExecutionContext, Future} +import scala.concurrent.duration.{DurationLong, FiniteDuration} import scala.util.Random -import play.api.{ Configuration, Logger } +import play.api.{Configuration, Logger} import play.api.http.Status import play.api.libs.json.Json -import play.api.mvc.{ AbstractController, Action, AnyContent, ControllerComponents } +import play.api.mvc.{AbstractController, Action, AnyContent, ControllerComponents} -import akka.actor.{ ActorSystem, Props } +import akka.actor.{ActorSystem, Props} import akka.util.Timeout import akka.pattern.ask import org.thp.cortex.models.Roles @@ -21,7 +21,7 @@ import org.thp.cortex.services.StreamActor.StreamMessages import org.elastic4play.Timed import org.elastic4play.controllers._ -import org.elastic4play.services.{ AuxSrv, EventSrv, MigrationSrv } +import org.elastic4play.services.{AuxSrv, EventSrv, MigrationSrv} @Singleton class StreamCtrl( @@ -36,7 +36,9 @@ class StreamCtrl( migrationSrv: MigrationSrv, components: ControllerComponents, implicit val system: ActorSystem, - implicit val ec: ExecutionContext) extends AbstractController(components) with Status { + implicit val ec: ExecutionContext +) extends AbstractController(components) + with Status { @Inject() def this( configuration: Configuration, @@ -47,7 +49,8 @@ class StreamCtrl( migrationSrv: MigrationSrv, components: ControllerComponents, system: ActorSystem, - ec: ExecutionContext) = + ec: ExecutionContext + ) = this( configuration.getMillis("stream.longpolling.cache").millis, configuration.getMillis("stream.longpolling.refresh").millis, @@ -60,7 +63,8 @@ class StreamCtrl( migrationSrv, components, system, - ec) + ec + ) private[StreamCtrl] lazy val logger = Logger(getClass) /** @@ -69,22 +73,14 @@ class StreamCtrl( @Timed("controllers.StreamCtrl.create") def create: Action[AnyContent] = authenticated(Roles.read) { val id = generateStreamId() - system.actorOf(Props( - classOf[StreamActor], - cacheExpiration, - refresh, - nextItemMaxWait, - globalMaxWait, - eventSrv, - auxSrv), s"stream-$id") + system.actorOf(Props(classOf[StreamActor], cacheExpiration, refresh, nextItemMaxWait, globalMaxWait, eventSrv, auxSrv), s"stream-$id") Ok(id) } val alphanumeric: immutable.IndexedSeq[Char] = ('a' to 'z') ++ ('A' to 'Z') ++ ('0' to '9') - private[controllers] def generateStreamId() = Seq.fill(10)(alphanumeric(Random.nextInt(alphanumeric.size))).mkString - private[controllers] def isValidStreamId(streamId: String): Boolean = { + private[controllers] def generateStreamId() = Seq.fill(10)(alphanumeric(Random.nextInt(alphanumeric.size))).mkString + private[controllers] def isValidStreamId(streamId: String): Boolean = streamId.length == 10 && streamId.forall(alphanumeric.contains) - } /** * Get events linked to the identified stream entry @@ -96,8 +92,7 @@ class StreamCtrl( if (!isValidStreamId(id)) { Future.successful(BadRequest("Invalid stream id")) - } - else { + } else { val futureStatus = authenticated.expirationStatus(request) match { case ExpirationError if !migrationSrv.isMigrating ⇒ authenticated.getFromApiKey(request).map(_ ⇒ OK) case _: ExpirationWarning ⇒ Future.successful(220) @@ -117,9 +112,9 @@ class StreamCtrl( def status = Action { implicit request ⇒ val status = authenticated.expirationStatus(request) match { case ExpirationWarning(duration) ⇒ Json.obj("remaining" → duration.toSeconds, "warning" → true) - case ExpirationError ⇒ Json.obj("remaining" → 0, "warning" → true) + case ExpirationError ⇒ Json.obj("remaining" → 0, "warning" → true) case ExpirationOk(duration) ⇒ Json.obj("remaining" → duration.toSeconds, "warning" → false) } Ok(status) } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/controllers/UserCtrl.scala b/app/org/thp/cortex/controllers/UserCtrl.scala index 3e2124bfb..5bd9033e0 100644 --- a/app/org/thp/cortex/controllers/UserCtrl.scala +++ b/app/org/thp/cortex/controllers/UserCtrl.scala @@ -1,26 +1,26 @@ package org.thp.cortex.controllers -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import scala.util.Try import play.api.Logger import play.api.http.Status -import play.api.libs.json.{ JsObject, Json } +import play.api.libs.json.{JsObject, Json} import play.api.mvc._ -import org.thp.cortex.models.{ OrganizationStatus, Roles } -import org.thp.cortex.services.{ OrganizationSrv, UserSrv } +import org.thp.cortex.models.{OrganizationStatus, Roles} +import org.thp.cortex.services.{OrganizationSrv, UserSrv} import org.elastic4play.models.JsonFormat.baseModelEntityWrites import org.elastic4play.services.JsonFormat.queryReads -import org.elastic4play.controllers.{ Authenticated, Fields, FieldsBodyParser, Renderer } -import org.elastic4play.services.{ AuthContext, AuthSrv, QueryDSL, QueryDef } +import org.elastic4play.controllers.{Authenticated, Fields, FieldsBodyParser, Renderer} +import org.elastic4play.services.{AuthContext, AuthSrv, QueryDSL, QueryDef} import org.elastic4play._ @Singleton -class UserCtrl @Inject() ( +class UserCtrl @Inject()( userSrv: UserSrv, authSrv: AuthSrv, organizationSrv: OrganizationSrv, @@ -28,7 +28,9 @@ class UserCtrl @Inject() ( renderer: Renderer, fieldsBodyParser: FieldsBodyParser, components: ControllerComponents, - implicit val ec: ExecutionContext) extends AbstractController(components) with Status { + implicit val ec: ExecutionContext +) extends AbstractController(components) + with Status { private[UserCtrl] lazy val logger = Logger(getClass) @@ -54,7 +56,7 @@ class UserCtrl @Inject() ( def get(userId: String): Action[AnyContent] = authenticated(Roles.read, Roles.superAdmin).async { implicit request ⇒ val isSuperAdmin = request.authContext.roles.contains(Roles.superAdmin) (for { - user ← userSrv.get(userId) + user ← userSrv.get(userId) organizationId ← userSrv.getOrganizationId(request.userId) if isSuperAdmin || organizationId == user.organization() } yield renderer.toOutput(OK, user)) @@ -67,17 +69,18 @@ class UserCtrl @Inject() ( def update(userId: String): Action[Fields] = authenticated().async(fieldsBodyParser) { implicit request ⇒ val fields = request.body - def superAdminChecks: Future[Unit] = { + def superAdminChecks: Future[Unit] = for { userOrganizationId ← fields.getString("organization").fold(userSrv.getOrganizationId(userId))(Future.successful) - organization ← organizationSrv.get(userOrganizationId) - _ ← if (organization.status() == OrganizationStatus.Active) Future.successful(()) else Future.failed(BadRequestError(s"Organization $userOrganizationId is locked")) + organization ← organizationSrv.get(userOrganizationId) + _ ← if (organization.status() == OrganizationStatus.Active) Future.successful(()) + else Future.failed(BadRequestError(s"Organization $userOrganizationId is locked")) // check roles and organization _ ← fields.getStrings("roles").map(_.flatMap(Roles.withName)).fold(Future.successful(())) { - case roles if userOrganizationId == "cortex" && roles == Seq(Roles.superAdmin) ⇒ Future.successful(()) + case roles if userOrganizationId == "cortex" && roles == Seq(Roles.superAdmin) ⇒ Future.successful(()) case roles if userOrganizationId != "cortex" && !roles.contains(Roles.superAdmin) ⇒ Future.successful(()) - case _ if userOrganizationId == "cortex" ⇒ Future.failed(BadRequestError("The organization \"cortex\" can contain only superadmin users")) - case _ ⇒ Future.failed(BadRequestError("The organization \"cortex\" alone can contain superadmin users")) + case _ if userOrganizationId == "cortex" ⇒ Future.failed(BadRequestError("The organization \"cortex\" can contain only superadmin users")) + case _ ⇒ Future.failed(BadRequestError("The organization \"cortex\" alone can contain superadmin users")) } // check status _ ← fields.getString("status").fold(Future.successful(())) { @@ -85,42 +88,40 @@ class UserCtrl @Inject() ( case _ ⇒ Future.failed(BadRequestError("You can't modify your status")) } } yield () - } - def orgAdminChecks: Future[Unit] = { + def orgAdminChecks: Future[Unit] = for { subjectUserOrganization ← userSrv.getOrganizationId(request.userId) - targetUserOrganization ← userSrv.getOrganizationId(userId) - _ ← if (subjectUserOrganization == targetUserOrganization) Future.successful(()) else Future.failed(NotFoundError(s"user $userId not found")) + targetUserOrganization ← userSrv.getOrganizationId(userId) + _ ← if (subjectUserOrganization == targetUserOrganization) Future.successful(()) else Future.failed(NotFoundError(s"user $userId not found")) // check roles _ ← fields.getStrings("roles").map(_.flatMap(Roles.withName)).fold(Future.successful(())) { case roles if !roles.contains(Roles.superAdmin) ⇒ Future.successful(()) case _ ⇒ Future.failed(AuthorizationError("You can't give superadmin right to an user")) } // check organization - _ ← if (fields.getString("organization").fold(true)(_ == targetUserOrganization)) Future.successful(()) else Future.failed(AuthorizationError("You can't move an user to another organization")) + _ ← if (fields.getString("organization").fold(true)(_ == targetUserOrganization)) Future.successful(()) + else Future.failed(AuthorizationError("You can't move an user to another organization")) } yield () - } - def userChecks: Future[Unit] = { + def userChecks: Future[Unit] = if (fields.contains("organization")) Future.failed(AuthorizationError("You can't change your organization")) else if (fields.contains("roles")) Future.failed(AuthorizationError("You can't change your role")) else if (fields.contains("status")) Future.failed(AuthorizationError("You can't change your status")) else Future.successful(()) - } - def authChecks: Future[Unit] = { - if (request.body.contains("password")) Future.failed(AuthorizationError("You must use dedicated API (setPassword, changePassword) to update password")) + def authChecks: Future[Unit] = + if (request.body.contains("password")) + Future.failed(AuthorizationError("You must use dedicated API (setPassword, changePassword) to update password")) else if (request.body.contains("key")) Future.failed(AuthorizationError("You must use dedicated API (renewKey, removeKey) to update key")) else Future.successful(()) - } for { _ ← if (userId == request.authContext.userId) userChecks else if (request.authContext.roles.contains(Roles.superAdmin)) superAdminChecks else if (request.authContext.roles.contains(Roles.orgAdmin)) orgAdminChecks else Future.failed(AuthorizationError("You are not permitted to change user settings")) - _ ← authChecks + _ ← authChecks user ← userSrv.update(userId, request.body) } yield renderer.toOutput(OK, user) } @@ -128,14 +129,17 @@ class UserCtrl @Inject() ( @Timed def setPassword(userId: String): Action[Fields] = authenticated(Roles.orgAdmin, Roles.superAdmin).async(fieldsBodyParser) { implicit request ⇒ val isSuperAdmin = request.authContext.roles.contains(Roles.superAdmin) - request.body.getString("password").fold(Future.failed[Result](MissingAttributeError("password"))) { password ⇒ - for { - targetOrganization ← userSrv.getOrganizationId(userId) - userOrganization ← userSrv.getOrganizationId(request.userId) - if targetOrganization == userOrganization || isSuperAdmin - _ ← authSrv.setPassword(userId, password) - } yield NoContent - } + request + .body + .getString("password") + .fold(Future.failed[Result](MissingAttributeError("password"))) { password ⇒ + for { + targetOrganization ← userSrv.getOrganizationId(userId) + userOrganization ← userSrv.getOrganizationId(request.userId) + if targetOrganization == userOrganization || isSuperAdmin + _ ← authSrv.setPassword(userId, password) + } yield NoContent + } .recoverWith { case _: NoSuchElementException ⇒ Future.failed(NotFoundError(s"user $userId not found")) } } @@ -144,11 +148,13 @@ class UserCtrl @Inject() ( if (userId == request.authContext.userId) { for { password ← request.body.getString("password").fold(Future.failed[String](MissingAttributeError("password")))(Future.successful) - currentPassword ← request.body.getString("currentPassword").fold(Future.failed[String](MissingAttributeError("currentPassword")))(Future.successful) + currentPassword ← request + .body + .getString("currentPassword") + .fold(Future.failed[String](MissingAttributeError("currentPassword")))(Future.successful) _ ← authSrv.changePassword(userId, currentPassword, password) } yield NoContent - } - else + } else Future.failed(AuthorizationError("You can't change password of another user")) } @@ -157,8 +163,9 @@ class UserCtrl @Inject() ( val isSuperAdmin = request.authContext.roles.contains(Roles.superAdmin) for { targetOrganization ← userSrv.getOrganizationId(userId) - userOrganization ← userSrv.getOrganizationId(request.userId) - _ ← if (targetOrganization == userOrganization || isSuperAdmin) Future.successful(()) else Future.failed(NotFoundError(s"user $userId not found")) + userOrganization ← userSrv.getOrganizationId(request.userId) + _ ← if (targetOrganization == userOrganization || isSuperAdmin) Future.successful(()) + else Future.failed(NotFoundError(s"user $userId not found")) _ ← if (userId != request.userId) Future.successful(()) else Future.failed(BadRequestError(s"You cannot disable your own account")) _ ← userSrv.delete(userId) } yield NoContent @@ -168,7 +175,7 @@ class UserCtrl @Inject() ( def currentUser: Action[AnyContent] = Action.async { implicit request ⇒ for { authContext ← authenticated.getContext(request) - user ← userSrv.get(authContext.userId) + user ← userSrv.get(authContext.userId) preferences = Try(Json.parse(user.preferences())) .getOrElse { logger.warn(s"User ${authContext.userId} has invalid preference format: ${user.preferences()}") @@ -180,34 +187,36 @@ class UserCtrl @Inject() ( @Timed def find: Action[Fields] = authenticated(Roles.superAdmin).async(fieldsBodyParser) { implicit request ⇒ - val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) - val range = request.body.getString("range") - val sort = request.body.getStrings("sort").getOrElse(Nil) + val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) + val range = request.body.getString("range") + val sort = request.body.getStrings("sort").getOrElse(Nil) val (users, total) = userSrv.find(query, range, sort) renderer.toOutput(OK, users, total) } - def findForOrganization(organizationId: String): Action[Fields] = authenticated(Roles.orgAdmin, Roles.superAdmin).async(fieldsBodyParser) { implicit request ⇒ - import org.elastic4play.services.QueryDSL._ - val isSuperAdmin = request.roles.contains(Roles.superAdmin) - val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) - val range = request.body.getString("range") - val sort = request.body.getStrings("sort").getOrElse(Nil) - val (users, total) = if (isSuperAdmin) userSrv.findForOrganization(organizationId, query, range, sort) - else userSrv.findForUser(request.userId, and("organization" ~= organizationId, query), range, sort) - renderer.toOutput(OK, users, total) + def findForOrganization(organizationId: String): Action[Fields] = authenticated(Roles.orgAdmin, Roles.superAdmin).async(fieldsBodyParser) { + implicit request ⇒ + import org.elastic4play.services.QueryDSL._ + val isSuperAdmin = request.roles.contains(Roles.superAdmin) + val query = request.body.getValue("query").fold[QueryDef](QueryDSL.any)(_.as[QueryDef]) + val range = request.body.getString("range") + val sort = request.body.getStrings("sort").getOrElse(Nil) + val (users, total) = + if (isSuperAdmin) userSrv.findForOrganization(organizationId, query, range, sort) + else userSrv.findForUser(request.userId, and("organization" ~= organizationId, query), range, sort) + renderer.toOutput(OK, users, total) } - private def checkUserOrganization(userId: String)(implicit authContext: AuthContext): Future[Unit] = { + private def checkUserOrganization(userId: String)(implicit authContext: AuthContext): Future[Unit] = if (authContext.roles.contains(Roles.superAdmin)) Future.successful(()) - else (for { - userOrganization1 ← userSrv.getOrganizationId(authContext.userId) - userOrganization2 ← userSrv.getOrganizationId(userId) - if userOrganization1 == userOrganization2 - } yield ()) - .recoverWith { case _ ⇒ Future.failed(NotFoundError(s"user $userId not found")) } - } + else + (for { + userOrganization1 ← userSrv.getOrganizationId(authContext.userId) + userOrganization2 ← userSrv.getOrganizationId(userId) + if userOrganization1 == userOrganization2 + } yield ()) + .recoverWith { case _ ⇒ Future.failed(NotFoundError(s"user $userId not found")) } @Timed def getKey(userId: String): Action[AnyContent] = authenticated().async { implicit request ⇒ @@ -236,4 +245,4 @@ class UserCtrl @Inject() ( key ← authSrv.renewKey(userId) } yield Ok(key) } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/models/Artifact.scala b/app/org/thp/cortex/models/Artifact.scala index b8a7b108d..8159dfcde 100644 --- a/app/org/thp/cortex/models/Artifact.scala +++ b/app/org/thp/cortex/models/Artifact.scala @@ -1,24 +1,23 @@ package org.thp.cortex.models -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import play.api.libs.json.JsObject -import org.elastic4play.models.{ AttributeDef, EntityDef, AttributeFormat ⇒ F, AttributeOption ⇒ O, ChildModelDef } +import org.elastic4play.models.{AttributeDef, EntityDef, AttributeFormat ⇒ F, AttributeOption ⇒ O, ChildModelDef} trait ArtifactAttributes { _: AttributeDef ⇒ - val dataType = attribute("dataType", F.stringFmt, "Type of the artifact", O.readonly) - val data = optionalAttribute("data", F.rawFmt, "Content of the artifact", O.readonly) + val dataType = attribute("dataType", F.stringFmt, "Type of the artifact", O.readonly) + val data = optionalAttribute("data", F.rawFmt, "Content of the artifact", O.readonly) val attachment = optionalAttribute("attachment", F.attachmentFmt, "Artifact file content", O.readonly) - val tlp = attribute("tlp", TlpAttributeFormat, "TLP level", 2L) - val tags = multiAttribute("tags", F.stringFmt, "Artifact tags") - val message = optionalAttribute("message", F.textFmt, "Message associated to the analysis") + val tlp = attribute("tlp", TlpAttributeFormat, "TLP level", 2L) + val tags = multiAttribute("tags", F.stringFmt, "Artifact tags") + val message = optionalAttribute("message", F.textFmt, "Message associated to the analysis") } @Singleton -class ArtifactModel @Inject() ( - reportModel: ReportModel) extends ChildModelDef[ArtifactModel, Artifact, ReportModel, Report](reportModel, "artifact", "Artifact", "/artifact") with ArtifactAttributes { - -} +class ArtifactModel @Inject()(reportModel: ReportModel) + extends ChildModelDef[ArtifactModel, Artifact, ReportModel, Report](reportModel, "artifact", "Artifact", "/artifact") + with ArtifactAttributes {} class Artifact(model: ArtifactModel, attributes: JsObject) extends EntityDef[ArtifactModel, Artifact](model, attributes) with ArtifactAttributes diff --git a/app/org/thp/cortex/models/Audit.scala b/app/org/thp/cortex/models/Audit.scala index 30bd40b8e..d43ca5f5a 100644 --- a/app/org/thp/cortex/models/Audit.scala +++ b/app/org/thp/cortex/models/Audit.scala @@ -1,14 +1,28 @@ package org.thp.cortex.models import java.util.Date -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import scala.collection.immutable import play.api.libs.json.JsObject -import play.api.{ Configuration, Logger } - -import org.elastic4play.models.{ Attribute, AttributeDef, AttributeFormat, BaseModelDef, EntityDef, EnumerationAttributeFormat, ListEnumerationAttributeFormat, ModelDef, MultiAttributeFormat, ObjectAttributeFormat, OptionalAttributeFormat, StringAttributeFormat, AttributeOption ⇒ O } +import play.api.{Configuration, Logger} + +import org.elastic4play.models.{ + Attribute, + AttributeDef, + AttributeFormat, + BaseModelDef, + EntityDef, + EnumerationAttributeFormat, + ListEnumerationAttributeFormat, + ModelDef, + MultiAttributeFormat, + ObjectAttributeFormat, + OptionalAttributeFormat, + StringAttributeFormat, + AttributeOption ⇒ O +} import org.elastic4play.services.AuditableAction import org.elastic4play.services.JsonFormat.auditableActionFormat @@ -16,9 +30,8 @@ trait AuditedModel { self: BaseModelDef ⇒ def attributes: Seq[Attribute[_]] lazy val auditedAttributes: Map[String, Attribute[_]] = - attributes - .collect { case a if !a.isUnaudited ⇒ a.attributeName → a } - .toMap + attributes.collect { case a if !a.isUnaudited ⇒ a.attributeName → a }.toMap + def selectAuditedAttributes(attrs: JsObject) = JsObject { attrs.fields.flatMap { case (attrName, value) ⇒ @@ -35,31 +48,27 @@ trait AuditAttributes { _: AttributeDef ⇒ def detailsAttributes: Seq[Attribute[_]] val operation: A[AuditableAction.Value] = attribute("operation", AttributeFormat.enumFmt(AuditableAction), "Operation", O.readonly) - val details: A[JsObject] = attribute("details", AttributeFormat.objectFmt(detailsAttributes), "Details", JsObject.empty, O.readonly) - val otherDetails: A[Option[String]] = optionalAttribute("otherDetails", AttributeFormat.textFmt, "Other details", O.readonly) - val objectType: A[String] = attribute("objectType", AttributeFormat.stringFmt, "Table affected by the operation", O.readonly) - val objectId: A[String] = attribute("objectId", AttributeFormat.stringFmt, "Object targeted by the operation", O.readonly) - val base: A[Boolean] = attribute("base", AttributeFormat.booleanFmt, "Indicates if this operation is the first done for a http query", O.readonly) - val startDate: A[Date] = attribute("startDate", AttributeFormat.dateFmt, "Date and time of the operation", new Date, O.readonly) - val rootId: A[String] = attribute("rootId", AttributeFormat.stringFmt, "Root element id (routing id)", O.readonly) - val requestId: A[String] = attribute("requestId", AttributeFormat.stringFmt, "Id of the request that do the operation", O.readonly) + val details: A[JsObject] = attribute("details", AttributeFormat.objectFmt(detailsAttributes), "Details", JsObject.empty, O.readonly) + val otherDetails: A[Option[String]] = optionalAttribute("otherDetails", AttributeFormat.textFmt, "Other details", O.readonly) + val objectType: A[String] = attribute("objectType", AttributeFormat.stringFmt, "Table affected by the operation", O.readonly) + val objectId: A[String] = attribute("objectId", AttributeFormat.stringFmt, "Object targeted by the operation", O.readonly) + val base: A[Boolean] = attribute("base", AttributeFormat.booleanFmt, "Indicates if this operation is the first done for a http query", O.readonly) + val startDate: A[Date] = attribute("startDate", AttributeFormat.dateFmt, "Date and time of the operation", new Date, O.readonly) + val rootId: A[String] = attribute("rootId", AttributeFormat.stringFmt, "Root element id (routing id)", O.readonly) + val requestId: A[String] = attribute("requestId", AttributeFormat.stringFmt, "Id of the request that do the operation", O.readonly) } @Singleton -class AuditModel( - auditName: String, - auditedModels: immutable.Set[AuditedModel]) extends ModelDef[AuditModel, Audit](auditName, "Audit", "/audit") with AuditAttributes { +class AuditModel(auditName: String, auditedModels: immutable.Set[AuditedModel]) + extends ModelDef[AuditModel, Audit](auditName, "Audit", "/audit") + with AuditAttributes { - @Inject() def this( - configuration: Configuration, - auditedModels: immutable.Set[AuditedModel]) = - this( - configuration.get[String]("audit.name"), - auditedModels) + @Inject() def this(configuration: Configuration, auditedModels: immutable.Set[AuditedModel]) = + this(configuration.get[String]("audit.name"), auditedModels) private[AuditModel] lazy val logger = Logger(getClass) - def mergeAttributeFormat(context: String, format1: AttributeFormat[_], format2: AttributeFormat[_]): Option[AttributeFormat[_]] = { + def mergeAttributeFormat(context: String, format1: AttributeFormat[_], format2: AttributeFormat[_]): Option[AttributeFormat[_]] = (format1, format2) match { case (OptionalAttributeFormat(f1), f2) ⇒ mergeAttributeFormat(context, f1, f2) case (f1, OptionalAttributeFormat(f2)) ⇒ mergeAttributeFormat(context, f1, f2) @@ -73,7 +82,6 @@ class AuditModel( None } - } def mergeAttributes(context: String, attributes: Seq[Attribute[_]]): Option[ObjectAttributeFormat] = { val mergeAttributes: Iterable[Option[Attribute[_]]] = attributes @@ -93,7 +101,9 @@ class AuditModel( } .map(format ⇒ Attribute("audit", _name, format, Nil, None, "")) .orElse { - logger.error(s"Mapping is not consistent on attribute $context:\n${_attributes.map(a ⇒ a.modelName + "/" + a.attributeName + ": " + a.format.name).mkString("\n")}") + logger.error( + s"Mapping is not consistent on attribute $context:\n${_attributes.map(a ⇒ a.modelName + "/" + a.attributeName + ": " + a.format.name).mkString("\n")}" + ) None } } @@ -103,18 +113,20 @@ class AuditModel( else Some(ObjectAttributeFormat(mergeAttributes.flatten.toSeq)) } - def detailsAttributes: Seq[Attribute[_]] = { - mergeAttributes("audit", auditedModels - .flatMap(_.attributes) - .filter(a ⇒ a.isModel && !a.isUnaudited) - .toSeq) - .map(_.subAttributes) + + def detailsAttributes: Seq[Attribute[_]] = + mergeAttributes( + "audit", + auditedModels + .flatMap(_.attributes) + .filter(a ⇒ a.isModel && !a.isUnaudited) + .toSeq + ).map(_.subAttributes) .getOrElse(Nil) - } override def apply(attributes: JsObject): Audit = new Audit(this, attributes) } class Audit(model: AuditModel, attributes: JsObject) extends EntityDef[AuditModel, Audit](model, attributes) with AuditAttributes { def detailsAttributes = Nil -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/models/BaseConfig.scala b/app/org/thp/cortex/models/BaseConfig.scala index 389ea2c25..1764b5cae 100644 --- a/app/org/thp/cortex/models/BaseConfig.scala +++ b/app/org/thp/cortex/models/BaseConfig.scala @@ -14,31 +14,73 @@ case class BaseConfig(name: String, workerNames: Seq[String], items: Seq[Configu object BaseConfig { implicit val writes: Writes[BaseConfig] = Writes[BaseConfig] { baseConfig ⇒ Json.obj( - "name" → baseConfig.name, - "workers" → baseConfig.workerNames, + "name" → baseConfig.name, + "workers" → baseConfig.workerNames, "configurationItems" → baseConfig.items, - "config" → baseConfig.config.fold(JsObject.empty)(_.jsonConfig)) + "config" → baseConfig.config.fold(JsObject.empty)(_.jsonConfig) + ) } + def global(tpe: WorkerType.Type, configuration: Configuration): BaseConfig = { val typedItems = tpe match { case WorkerType.responder ⇒ Nil - case WorkerType.analyzer ⇒ Seq( - ConfigurationDefinitionItem("auto_extract_artifacts", "extract artifacts from full report automatically", WorkerConfigItemType.boolean, multi = false, required = false, Some(JsFalse)), - ConfigurationDefinitionItem("jobCache", "maximum time, in minutes, previous result is used if similar job is requested", WorkerConfigItemType.number, multi = false, required = false, configuration.getOptional[Duration]("cache.job").map(d ⇒ JsNumber(d.toMinutes)))) + case WorkerType.analyzer ⇒ + Seq( + ConfigurationDefinitionItem( + "auto_extract_artifacts", + "extract artifacts from full report automatically", + WorkerConfigItemType.boolean, + multi = false, + required = false, + Some(JsFalse) + ), + ConfigurationDefinitionItem( + "jobCache", + "maximum time, in minutes, previous result is used if similar job is requested", + WorkerConfigItemType.number, + multi = false, + required = false, + configuration.getOptional[Duration]("cache.job").map(d ⇒ JsNumber(d.toMinutes)) + ) + ) } - BaseConfig("global", Nil, typedItems ++ Seq( - ConfigurationDefinitionItem("proxy_http", "url of http proxy", WorkerConfigItemType.string, multi = false, required = false, None), - ConfigurationDefinitionItem("proxy_https", "url of https proxy", WorkerConfigItemType.string, multi = false, required = false, None), - ConfigurationDefinitionItem("cacerts", "certificate authorities", WorkerConfigItemType.text, multi = false, required = false, None), - ConfigurationDefinitionItem("jobTimeout", "maximum allowed job execution time (in minutes)", WorkerConfigItemType.number, multi = false, required = false, configuration.getOptional[Duration]("job.timeout").map(d ⇒ JsNumber(d.toMinutes)))), - None) + BaseConfig( + "global", + Nil, + typedItems ++ Seq( + ConfigurationDefinitionItem("proxy_http", "url of http proxy", WorkerConfigItemType.string, multi = false, required = false, None), + ConfigurationDefinitionItem("proxy_https", "url of https proxy", WorkerConfigItemType.string, multi = false, required = false, None), + ConfigurationDefinitionItem("cacerts", "certificate authorities", WorkerConfigItemType.text, multi = false, required = false, None), + ConfigurationDefinitionItem( + "jobTimeout", + "maximum allowed job execution time (in minutes)", + WorkerConfigItemType.number, + multi = false, + required = false, + configuration.getOptional[Duration]("job.timeout").map(d ⇒ JsNumber(d.toMinutes)) + ) + ), + None + ) } - val tlp = BaseConfig("tlp", Nil, Seq( - ConfigurationDefinitionItem("check_tlp", "", WorkerConfigItemType.boolean, multi = false, required = false, None), - ConfigurationDefinitionItem("max_tlp", "", WorkerConfigItemType.number, multi = false, required = false, None)), - None) - val pap = BaseConfig("pap", Nil, Seq( - ConfigurationDefinitionItem("check_pap", "", WorkerConfigItemType.boolean, multi = false, required = false, None), - ConfigurationDefinitionItem("max_pap", "", WorkerConfigItemType.number, multi = false, required = false, None)), - None) -} \ No newline at end of file + + val tlp = BaseConfig( + "tlp", + Nil, + Seq( + ConfigurationDefinitionItem("check_tlp", "", WorkerConfigItemType.boolean, multi = false, required = false, None), + ConfigurationDefinitionItem("max_tlp", "", WorkerConfigItemType.number, multi = false, required = false, None) + ), + None + ) + + val pap = BaseConfig( + "pap", + Nil, + Seq( + ConfigurationDefinitionItem("check_pap", "", WorkerConfigItemType.boolean, multi = false, required = false, None), + ConfigurationDefinitionItem("max_pap", "", WorkerConfigItemType.number, multi = false, required = false, None) + ), + None + ) +} diff --git a/app/org/thp/cortex/models/Errors.scala b/app/org/thp/cortex/models/Errors.scala index 0b2ccdad2..302a7d4dd 100644 --- a/app/org/thp/cortex/models/Errors.scala +++ b/app/org/thp/cortex/models/Errors.scala @@ -2,7 +2,10 @@ package org.thp.cortex.models abstract class CortexError(message: String) extends Exception(message) -case class JobNotFoundError(jobId: String) extends CortexError(s"Job $jobId not found") +case class JobNotFoundError(jobId: String) extends CortexError(s"Job $jobId not found") case class WorkerNotFoundError(analyzerId: String) extends CortexError(s"Worker $analyzerId not found") -case class UnknownConfigurationItem(item: String) extends CortexError(s"Configuration item $item is not known") -case class RateLimitExceeded(analyzer: Worker) extends CortexError(s"Rate limit of ${analyzer.rate().getOrElse("(not set ?!)")} per ${analyzer.rateUnit().getOrElse("(not set ?!)")} reached for the analyzer ${analyzer.name()}. Job cannot be started") \ No newline at end of file +case class UnknownConfigurationItem(item: String) extends CortexError(s"Configuration item $item is not known") +case class RateLimitExceeded(analyzer: Worker) + extends CortexError( + s"Rate limit of ${analyzer.rate().getOrElse("(not set ?!)")} per ${analyzer.rateUnit().getOrElse("(not set ?!)")} reached for the analyzer ${analyzer.name()}. Job cannot be started" + ) diff --git a/app/org/thp/cortex/models/Job.scala b/app/org/thp/cortex/models/Job.scala index 9dd9a2978..4fa5deb91 100644 --- a/app/org/thp/cortex/models/Job.scala +++ b/app/org/thp/cortex/models/Job.scala @@ -2,45 +2,46 @@ package org.thp.cortex.models import scala.util.Try -import play.api.libs.json.{ JsObject, JsString, Json } +import play.api.libs.json.{JsObject, JsString, Json} -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import org.thp.cortex.models.JsonFormat.workerTypeFormat import org.elastic4play.models.JsonFormat.enumFormat -import org.elastic4play.models.{ AttributeDef, EntityDef, HiveEnumeration, ModelDef, AttributeFormat ⇒ F, AttributeOption ⇒ O } +import org.elastic4play.models.{AttributeDef, EntityDef, HiveEnumeration, ModelDef, AttributeFormat ⇒ F, AttributeOption ⇒ O} + object JobStatus extends Enumeration with HiveEnumeration { type Type = Value val Waiting, InProgress, Success, Failure, Deleted = Value - implicit val reads = enumFormat(this) + implicit val reads = enumFormat(this) } trait JobAttributes { _: AttributeDef ⇒ val workerDefinitionId = attribute("workerDefinitionId", F.stringFmt, "Worker definition id", O.readonly) - val workerId = attribute("workerId", F.stringFmt, "Worker id", O.readonly) - val workerName = attribute("workerName", F.stringFmt, "Worker name", O.readonly) - val organization = attribute("organization", F.stringFmt, "Organization ID", O.readonly) - val status = attribute("status", F.enumFmt(JobStatus), "Status of the job") - val startDate = optionalAttribute("startDate", F.dateFmt, "Analysis start date") - val endDate = optionalAttribute("endDate", F.dateFmt, "Analysis end date") - val dataType = attribute("dataType", F.stringFmt, "Type of the artifact", O.readonly) - val data = optionalAttribute("data", F.rawFmt, "Content of the artifact", O.readonly) - val attachment = optionalAttribute("attachment", F.attachmentFmt, "Artifact file content", O.readonly) - val tlp = attribute("tlp", TlpAttributeFormat, "TLP level", 2L) - val pap = attribute("pap", TlpAttributeFormat, "PAP level", 2L) - val message = optionalAttribute("message", F.textFmt, "Message associated to the analysis") - val errorMessage = optionalAttribute("message", F.textFmt, "Message returned by the worker when it fails") - val parameters = attribute("parameters", F.rawFmt, "Parameters for this job", "{}") - val input = optionalAttribute("input", F.rawFmt, "Data sent to worker") - val fromCache = optionalAttribute("fromCache", F.booleanFmt, "Indicates if cache is used", O.form) - val tpe = attribute("type", F.enumFmt(WorkerType), "", O.readonly) - val lbel = optionalAttribute("label", F.stringFmt, "Label of the job") - val cacheTag = optionalAttribute("cacheTag", F.stringFmt, "hash of job discriminant, used for cache", O.readonly) + val workerId = attribute("workerId", F.stringFmt, "Worker id", O.readonly) + val workerName = attribute("workerName", F.stringFmt, "Worker name", O.readonly) + val organization = attribute("organization", F.stringFmt, "Organization ID", O.readonly) + val status = attribute("status", F.enumFmt(JobStatus), "Status of the job") + val startDate = optionalAttribute("startDate", F.dateFmt, "Analysis start date") + val endDate = optionalAttribute("endDate", F.dateFmt, "Analysis end date") + val dataType = attribute("dataType", F.stringFmt, "Type of the artifact", O.readonly) + val data = optionalAttribute("data", F.rawFmt, "Content of the artifact", O.readonly) + val attachment = optionalAttribute("attachment", F.attachmentFmt, "Artifact file content", O.readonly) + val tlp = attribute("tlp", TlpAttributeFormat, "TLP level", 2L) + val pap = attribute("pap", TlpAttributeFormat, "PAP level", 2L) + val message = optionalAttribute("message", F.textFmt, "Message associated to the analysis") + val errorMessage = optionalAttribute("message", F.textFmt, "Message returned by the worker when it fails") + val parameters = attribute("parameters", F.rawFmt, "Parameters for this job", "{}") + val input = optionalAttribute("input", F.rawFmt, "Data sent to worker") + val fromCache = optionalAttribute("fromCache", F.booleanFmt, "Indicates if cache is used", O.form) + val tpe = attribute("type", F.enumFmt(WorkerType), "", O.readonly) + val lbel = optionalAttribute("label", F.stringFmt, "Label of the job") + val cacheTag = optionalAttribute("cacheTag", F.stringFmt, "hash of job discriminant, used for cache", O.readonly) } @Singleton -class JobModel @Inject() () extends ModelDef[JobModel, Job]("job", "Job", "/job") with JobAttributes with AuditedModel { +class JobModel @Inject()() extends ModelDef[JobModel, Job]("job", "Job", "/job") with JobAttributes with AuditedModel { override val removeAttribute: JsObject = Json.obj("status" → JobStatus.Deleted) @@ -51,16 +52,19 @@ class Job(model: JobModel, attributes: JsObject) extends EntityDef[JobModel, Job val params: JsObject = Try(Json.parse(parameters()).as[JsObject]).getOrElse(JsObject.empty) override def toJson: JsObject = { - val output = input().fold(super.toJson)(i ⇒ super.toJson + - ("input" → Json.parse(i))) + - ("parameters" → params) + - ("analyzerId" → JsString(workerId())) + - ("analyzerName" → JsString(workerName())) + + val output = input().fold(super.toJson)( + i ⇒ + super.toJson + + ("input" → Json.parse(i)) + ) + + ("parameters" → params) + + ("analyzerId" → JsString(workerId())) + + ("analyzerName" → JsString(workerName())) + ("analyzerDefinitionId" → JsString(workerDefinitionId())) + - ("date" → Json.toJson(createdAt)) + ("date" → Json.toJson(createdAt)) data() match { - case Some(d) if tpe() == WorkerType.responder ⇒ output + ("data" -> Json.parse(d)) + case Some(d) if tpe() == WorkerType.responder ⇒ output + ("data" → Json.parse(d)) case _ ⇒ output } } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/models/JsonFormat.scala b/app/org/thp/cortex/models/JsonFormat.scala index 34ba0e3fd..e455bed5f 100644 --- a/app/org/thp/cortex/models/JsonFormat.scala +++ b/app/org/thp/cortex/models/JsonFormat.scala @@ -11,6 +11,6 @@ object JsonFormat { case JsString(s) if Roles.isValid(s) ⇒ JsSuccess(Roles.withName(s).get) case _ ⇒ JsError(Seq(JsPath → Seq(JsonValidationError(s"error.expected.role(${Roles.roleNames}")))) } - implicit val roleFormat: Format[Role] = Format[Role](roleReads, roleWrites) + implicit val roleFormat: Format[Role] = Format[Role](roleReads, roleWrites) implicit val workerTypeFormat: Format[WorkerType.Value] = enumFormat(WorkerType) } diff --git a/app/org/thp/cortex/models/Migration.scala b/app/org/thp/cortex/models/Migration.scala index 2203a55d0..bad438b00 100644 --- a/app/org/thp/cortex/models/Migration.scala +++ b/app/org/thp/cortex/models/Migration.scala @@ -1,38 +1,32 @@ package org.thp.cortex.models -import javax.inject.{ Inject, Singleton } -import scala.concurrent.{ ExecutionContext, Future } +import javax.inject.{Inject, Singleton} +import scala.concurrent.{ExecutionContext, Future} import scala.util.Success import play.api.Logger -import play.api.libs.json.{ JsNull, JsNumber, JsString, JsValue, Json } +import play.api.libs.json.{JsNull, JsNumber, JsString, JsValue, Json} -import org.thp.cortex.services.{ OrganizationSrv, UserSrv, WorkerSrv } +import org.thp.cortex.services.{OrganizationSrv, UserSrv, WorkerSrv} import org.elastic4play.controllers.Fields import org.elastic4play.services.Operation._ -import org.elastic4play.services.{ DatabaseState, IndexType, MigrationOperations, Operation } +import org.elastic4play.services.{DatabaseState, IndexType, MigrationOperations, Operation} import org.elastic4play.utils.Hasher @Singleton -class Migration @Inject() ( - userSrv: UserSrv, - organizationSrv: OrganizationSrv, - workerSrv: WorkerSrv, - implicit val ec: ExecutionContext) extends MigrationOperations { +class Migration @Inject()(userSrv: UserSrv, organizationSrv: OrganizationSrv, workerSrv: WorkerSrv, implicit val ec: ExecutionContext) + extends MigrationOperations { - lazy val logger = Logger(getClass) + lazy val logger = Logger(getClass) def beginMigration(version: Int): Future[Unit] = Future.successful(()) - def endMigration(version: Int): Future[Unit] = { + def endMigration(version: Int): Future[Unit] = userSrv.inInitAuthContext { implicit authContext ⇒ - organizationSrv.create(Fields(Json.obj( - "name" → "cortex", - "description" → "Default organization", - "status" → "Active"))) + organizationSrv + .create(Fields(Json.obj("name" → "cortex", "description" → "Default organization", "status" → "Active"))) .transform(_ ⇒ Success(())) // ignore errors (already exist) } - } override def indexType(version: Int): IndexType.Value = if (version > 3) IndexType.indexWithoutMappingTypes else IndexType.indexWithMappingTypes @@ -40,31 +34,27 @@ class Migration @Inject() ( case DatabaseState(1) ⇒ val hasher = Hasher("MD5") Seq( - // add type to analyzer addAttribute("analyzer", "type" → JsString("analyzer")), - renameAttribute("job", "workerDefinitionId", "analyzerDefinitionId"), renameAttribute("job", "workerId", "analyzerId"), renameAttribute("job", "workerName", "analyzerName"), - addAttribute("job", "type" → JsString(WorkerType.analyzer.toString)), - + addAttribute("job", "type" → JsString(WorkerType.analyzer.toString)), addAttribute("report", "operations" → JsString("[]")), - renameEntity("analyzer", "worker"), renameAttribute("worker", "workerDefinitionId", "analyzerDefinitionId"), addAttribute("worker", "type" → JsString(WorkerType.analyzer.toString)), mapEntity("worker") { worker ⇒ val id = for { organizationId ← (worker \ "_parent").asOpt[String] - name ← (worker \ "name").asOpt[String] - tpe ← (worker \ "type").asOpt[String] + name ← (worker \ "name").asOpt[String] + tpe ← (worker \ "type").asOpt[String] } yield hasher.fromString(s"${organizationId}_${name}_$tpe").head.toString worker + ("_id" → JsString(id.getOrElse(""))) }, - renameEntity("analyzerConfig", "workerConfig"), - addAttribute("workerConfig", "type" → JsString(WorkerType.analyzer.toString))) + addAttribute("workerConfig", "type" → JsString(WorkerType.analyzer.toString)) + ) case DatabaseState(2) ⇒ Seq(mapEntity("worker") { worker ⇒ @@ -76,23 +66,24 @@ class Migration @Inject() ( worker } { definition ⇒ worker + - ("version" -> JsString(definition.version)) + - ("author" -> JsString(definition.author)) + - ("url" -> JsString(definition.url)) + - ("license" -> JsString(definition.license)) + - ("command" -> definition.command.fold[JsValue](JsNull)(c ⇒ JsString(c.toString))) + - ("dockerImage" -> definition.dockerImage.fold[JsValue](JsNull)(JsString.apply)) + - ("baseConfig" -> definition.baseConfiguration.fold[JsValue](JsNull)(JsString.apply)) + ("version" → JsString(definition.version)) + + ("author" → JsString(definition.author)) + + ("url" → JsString(definition.url)) + + ("license" → JsString(definition.license)) + + ("command" → definition.command.fold[JsValue](JsNull)(c ⇒ JsString(c.toString))) + + ("dockerImage" → definition.dockerImage.fold[JsValue](JsNull)(JsString.apply)) + + ("baseConfig" → definition.baseConfiguration.fold[JsValue](JsNull)(JsString.apply)) } }) - case DatabaseState(3) ⇒ Seq( - mapEntity("sequence") { seq => - val oldId = (seq \ "_id").as[String] + case DatabaseState(3) ⇒ + Seq( + mapEntity("sequence") { seq ⇒ + val oldId = (seq \ "_id").as[String] val counter = (seq \ "counter").as[JsNumber] seq - "counter" - "_routing" + - ("_id" -> JsString("sequence_" + oldId)) + - ("sequenceCounter" -> counter) + ("_id" → JsString("sequence_" + oldId)) + + ("sequenceCounter" → counter) } ) } diff --git a/app/org/thp/cortex/models/Organization.scala b/app/org/thp/cortex/models/Organization.scala index 5fcc70ec1..32a500e04 100644 --- a/app/org/thp/cortex/models/Organization.scala +++ b/app/org/thp/cortex/models/Organization.scala @@ -1,14 +1,14 @@ package org.thp.cortex.models -import javax.inject.{ Inject, Provider, Singleton } +import javax.inject.{Inject, Provider, Singleton} -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import play.api.Logger -import play.api.libs.json.{ JsNumber, JsObject, JsString, Json } +import play.api.libs.json.{JsNumber, JsObject, JsString, Json} import org.elastic4play.models.JsonFormat.enumFormat -import org.elastic4play.models.{ AttributeDef, BaseEntity, EntityDef, HiveEnumeration, ModelDef, AttributeFormat ⇒ F, AttributeOption ⇒ O } +import org.elastic4play.models.{AttributeDef, BaseEntity, EntityDef, HiveEnumeration, ModelDef, AttributeFormat ⇒ F, AttributeOption ⇒ O} import org.elastic4play.services.FindSrv object OrganizationStatus extends Enumeration with HiveEnumeration { @@ -18,22 +18,25 @@ object OrganizationStatus extends Enumeration with HiveEnumeration { } trait OrganizationAttributes { _: AttributeDef ⇒ - val name = attribute("name", F.stringFmt, "Organization name", O.form) - val _id = attribute("_id", F.stringFmt, "Organization name", O.model) + val name = attribute("name", F.stringFmt, "Organization name", O.form) + val _id = attribute("_id", F.stringFmt, "Organization name", O.model) val description = attribute("description", F.textFmt, "Organization description") - val status = attribute("status", F.enumFmt(OrganizationStatus), "Status of the organization", OrganizationStatus.Active) + val status = attribute("status", F.enumFmt(OrganizationStatus), "Status of the organization", OrganizationStatus.Active) } @Singleton -class OrganizationModel @Inject() ( +class OrganizationModel @Inject()( findSrv: FindSrv, userModelProvider: Provider[UserModel], workerModelProvider: Provider[WorkerModel], - implicit val ec: ExecutionContext) extends ModelDef[OrganizationModel, Organization]("organization", "Organization", "/organization") with OrganizationAttributes with AuditedModel { + implicit val ec: ExecutionContext +) extends ModelDef[OrganizationModel, Organization]("organization", "Organization", "/organization") + with OrganizationAttributes + with AuditedModel { - private lazy val logger = Logger(getClass) - lazy val userModel = userModelProvider.get - lazy val workerModel = workerModelProvider.get + private lazy val logger = Logger(getClass) + lazy val userModel = userModelProvider.get + lazy val workerModel = workerModelProvider.get override def removeAttribute = Json.obj("status" → "Locked") override def creationHook(parent: Option[BaseEntity], attrs: JsObject): Future[JsObject] = @@ -45,10 +48,7 @@ class OrganizationModel @Inject() ( private def buildUserStats(organization: Organization): Future[JsObject] = { import org.elastic4play.services.QueryDSL._ - findSrv( - userModel, - "organization" ~= organization.id, - groupByField("status", selectCount)) + findSrv(userModel, "organization" ~= organization.id, groupByField("status", selectCount)) .map { userStatsJson ⇒ val (userCount, userStats) = userStatsJson.value.foldLeft((0L, JsObject.empty)) { case ((total, s), (key, value)) ⇒ @@ -61,10 +61,7 @@ class OrganizationModel @Inject() ( private def buildWorkerStats(organization: Organization): Future[JsObject] = { import org.elastic4play.services.QueryDSL._ - findSrv( - workerModel, - withParent(organization), - groupByField("status", selectCount)) + findSrv(workerModel, withParent(organization), groupByField("status", selectCount)) .map { workerStatsJson ⇒ val (workerCount, workerStats) = workerStatsJson.value.foldLeft((0L, JsObject.empty)) { case ((total, s), (key, value)) ⇒ @@ -75,21 +72,22 @@ class OrganizationModel @Inject() ( } } - override def getStats(entity: BaseEntity): Future[JsObject] = { + override def getStats(entity: BaseEntity): Future[JsObject] = entity match { case organization: Organization ⇒ for { - userStats ← buildUserStats(organization) + userStats ← buildUserStats(organization) workerStats ← buildWorkerStats(organization) } yield userStats ++ workerStats case other ⇒ logger.warn(s"Request caseStats from a non-case entity ?! ${other.getClass}:$other") Future.successful(Json.obj()) } - } } -class Organization(model: OrganizationModel, attributes: JsObject) extends EntityDef[OrganizationModel, Organization](model, attributes) with OrganizationAttributes { +class Organization(model: OrganizationModel, attributes: JsObject) + extends EntityDef[OrganizationModel, Organization](model, attributes) + with OrganizationAttributes { override def toJson: JsObject = super.toJson + ("name" → JsString(id)) } diff --git a/app/org/thp/cortex/models/Report.scala b/app/org/thp/cortex/models/Report.scala index eff2f1f26..c1959e98a 100644 --- a/app/org/thp/cortex/models/Report.scala +++ b/app/org/thp/cortex/models/Report.scala @@ -1,21 +1,20 @@ package org.thp.cortex.models -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import play.api.libs.json.JsObject -import org.elastic4play.models.{ AttributeDef, EntityDef, AttributeFormat ⇒ F, AttributeOption ⇒ O, ChildModelDef } +import org.elastic4play.models.{AttributeDef, EntityDef, AttributeFormat ⇒ F, AttributeOption ⇒ O, ChildModelDef} trait ReportAttributes { _: AttributeDef ⇒ - val full = attribute("full", F.rawFmt, "Full content of the report", O.readonly) - val summary = attribute("summary", F.rawFmt, "Summary of the report", O.readonly) + val full = attribute("full", F.rawFmt, "Full content of the report", O.readonly) + val summary = attribute("summary", F.rawFmt, "Summary of the report", O.readonly) val operations = attribute("operations", F.rawFmt, "Update operations applied at the end of the job", "[]", O.unaudited) } @Singleton -class ReportModel @Inject() ( - jobModel: JobModel) extends ChildModelDef[ReportModel, Report, JobModel, Job](jobModel, "report", "Report", "/report") with ReportAttributes { - -} +class ReportModel @Inject()(jobModel: JobModel) + extends ChildModelDef[ReportModel, Report, JobModel, Job](jobModel, "report", "Report", "/report") + with ReportAttributes {} class Report(model: ReportModel, attributes: JsObject) extends EntityDef[ReportModel, Report](model, attributes) with ReportAttributes diff --git a/app/org/thp/cortex/models/Roles.scala b/app/org/thp/cortex/models/Roles.scala index 1e73e522a..0c906f2b4 100644 --- a/app/org/thp/cortex/models/Roles.scala +++ b/app/org/thp/cortex/models/Roles.scala @@ -1,27 +1,28 @@ package org.thp.cortex.models -import play.api.libs.json.{ JsString, JsValue } +import play.api.libs.json.{JsString, JsValue} import com.sksamuel.elastic4s.http.ElasticDsl.keywordField import com.sksamuel.elastic4s.mappings.KeywordField -import org.scalactic.{ Every, Good, One, Or } +import org.scalactic.{Every, Good, One, Or} -import org.elastic4play.{ AttributeError, InvalidFormatAttributeError } -import org.elastic4play.controllers.{ InputValue, JsonInputValue, StringInputValue } +import org.elastic4play.{AttributeError, InvalidFormatAttributeError} +import org.elastic4play.controllers.{InputValue, JsonInputValue, StringInputValue} import org.elastic4play.models.AttributeFormat import org.elastic4play.services.Role import org.thp.cortex.models.JsonFormat.roleFormat object Roles { - object read extends Role("read") - object analyze extends Role("analyze") - object orgAdmin extends Role("orgadmin") + object read extends Role("read") + object analyze extends Role("analyze") + object orgAdmin extends Role("orgadmin") object superAdmin extends Role("superadmin") val roles: List[Role] = read :: analyze :: orgAdmin :: superAdmin :: Nil - val roleNames: List[String] = roles.map(_.name) + val roleNames: List[String] = roles.map(_.name) def isValid(roleName: String): Boolean = roleNames.contains(roleName.toLowerCase()) + def withName(roleName: String): Option[Role] = { val lowerCaseRole = roleName.toLowerCase() roles.find(_.name == lowerCaseRole) @@ -35,7 +36,7 @@ object RoleAttributeFormat extends AttributeFormat[Role]("role") { case _ ⇒ formatError(JsonInputValue(value)) } - override def fromInputValue(subNames: Seq[String], value: InputValue): Role Or Every[AttributeError] = { + override def fromInputValue(subNames: Seq[String], value: InputValue): Role Or Every[AttributeError] = if (subNames.nonEmpty) formatError(value) else @@ -45,7 +46,5 @@ object RoleAttributeFormat extends AttributeFormat[Role]("role") { case _ ⇒ formatError(value) }).flatMap(v ⇒ Roles.withName(v).fold[Role Or Every[AttributeError]](formatError(value))(role ⇒ Good(role))) - } - override def elasticType(attributeName: String): KeywordField = keywordField(attributeName) -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/models/TlpAttributeFormat.scala b/app/org/thp/cortex/models/TlpAttributeFormat.scala index f35ff963a..7ba81d17c 100644 --- a/app/org/thp/cortex/models/TlpAttributeFormat.scala +++ b/app/org/thp/cortex/models/TlpAttributeFormat.scala @@ -1,12 +1,12 @@ package org.thp.cortex.models -import play.api.libs.json.{ JsNumber, JsValue } +import play.api.libs.json.{JsNumber, JsValue} -import org.scalactic.{ Every, Good, One, Or } +import org.scalactic.{Every, Good, One, Or} -import org.elastic4play.{ AttributeError, InvalidFormatAttributeError } -import org.elastic4play.controllers.{ InputValue, JsonInputValue, StringInputValue } -import org.elastic4play.models.{ Attribute, AttributeDefinition, NumberAttributeFormat } +import org.elastic4play.{AttributeError, InvalidFormatAttributeError} +import org.elastic4play.controllers.{InputValue, JsonInputValue, StringInputValue} +import org.elastic4play.models.{Attribute, AttributeDefinition, NumberAttributeFormat} import org.elastic4play.services.DBLists object TlpAttributeFormat extends NumberAttributeFormat { @@ -14,31 +14,32 @@ object TlpAttributeFormat extends NumberAttributeFormat { def isValidValue(value: Long): Boolean = 0 <= value && value <= 3 override def definition(dblists: DBLists, attribute: Attribute[Long]): Seq[AttributeDefinition] = - Seq(AttributeDefinition( - attribute.attributeName, - name, - attribute.description, - Seq(JsNumber(0), JsNumber(1), JsNumber(2), JsNumber(3)), - Seq("white", "green", "amber", "red"))) + Seq( + AttributeDefinition( + attribute.attributeName, + name, + attribute.description, + Seq(JsNumber(0), JsNumber(1), JsNumber(2), JsNumber(3)), + Seq("white", "green", "amber", "red") + ) + ) override def checkJson(subNames: Seq[String], value: JsValue): Or[JsValue, One[InvalidFormatAttributeError]] = value match { case JsNumber(v) if subNames.isEmpty && isValidValue(v.toLong) ⇒ Good(value) case _ ⇒ formatError(JsonInputValue(value)) } - override def fromInputValue(subNames: Seq[String], value: InputValue): Long Or Every[AttributeError] = { + override def fromInputValue(subNames: Seq[String], value: InputValue): Long Or Every[AttributeError] = value match { case StringInputValue(Seq(v)) if subNames.isEmpty ⇒ try { val longValue = v.toLong if (isValidValue(longValue)) Good(longValue) else formatError(value) - } - catch { + } catch { case _: Throwable ⇒ formatError(value) } case JsonInputValue(JsNumber(v)) ⇒ Good(v.longValue) case _ ⇒ formatError(value) } - } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/models/User.scala b/app/org/thp/cortex/models/User.scala index 6a374c968..1f7af2afb 100644 --- a/app/org/thp/cortex/models/User.scala +++ b/app/org/thp/cortex/models/User.scala @@ -2,27 +2,28 @@ package org.thp.cortex.models import scala.concurrent.Future -import play.api.libs.json.{ JsArray, JsBoolean, JsObject, JsString } +import play.api.libs.json.{JsArray, JsBoolean, JsObject, JsString} import org.elastic4play.models.JsonFormat.enumFormat -import org.elastic4play.models.{ AttributeDef, BaseEntity, EntityDef, HiveEnumeration, ModelDef, AttributeFormat ⇒ F, AttributeOption ⇒ O } +import org.elastic4play.models.{AttributeDef, BaseEntity, EntityDef, HiveEnumeration, ModelDef, AttributeFormat ⇒ F, AttributeOption ⇒ O} +import org.elastic4play.services.{User ⇒ EUser} object UserStatus extends Enumeration with HiveEnumeration { type Type = Value - val Ok, Locked = Value + val Ok, Locked = Value implicit val reads = enumFormat(this) } trait UserAttributes { _: AttributeDef ⇒ - val login = attribute("login", F.userFmt, "Login of the user", O.form) - val userId = attribute("_id", F.stringFmt, "User id (login)", O.model) - val key = optionalAttribute("key", F.stringFmt, "API key", O.sensitive, O.unaudited) - val userName = attribute("name", F.stringFmt, "Full name (Firstname Lastname)") - val roles = multiAttribute("roles", RoleAttributeFormat, "Comma separated role list (READ, WRITE and ADMIN)") - val status = attribute("status", F.enumFmt(UserStatus), "Status of the user", UserStatus.Ok) - val password = optionalAttribute("password", F.stringFmt, "Password", O.sensitive, O.unaudited) - val avatar = optionalAttribute("avatar", F.rawFmt, "Base64 representation of user avatar image", O.unaudited) - val preferences = attribute("preferences", F.rawFmt, "User preferences", "{}", O.sensitive, O.unaudited) + val login = attribute("login", F.userFmt, "Login of the user", O.form) + val userId = attribute("_id", F.stringFmt, "User id (login)", O.model) + val key = optionalAttribute("key", F.stringFmt, "API key", O.sensitive, O.unaudited) + val userName = attribute("name", F.stringFmt, "Full name (Firstname Lastname)") + val roles = multiAttribute("roles", RoleAttributeFormat, "Comma separated role list (READ, WRITE and ADMIN)") + val status = attribute("status", F.enumFmt(UserStatus), "Status of the user", UserStatus.Ok) + val password = optionalAttribute("password", F.stringFmt, "Password", O.sensitive, O.unaudited) + val avatar = optionalAttribute("avatar", F.rawFmt, "Base64 representation of user avatar image", O.unaudited) + val preferences = attribute("preferences", F.rawFmt, "User preferences", "{}", O.sensitive, O.unaudited) val organization = attribute("organization", F.stringFmt, "User organization") } @@ -35,12 +36,13 @@ class UserModel extends ModelDef[UserModel, User]("user", "User", "/user") with override def creationHook(parent: Option[BaseEntity], attrs: JsObject): Future[JsObject] = Future.successful(setUserId(attrs)) } -class User(model: UserModel, attributes: JsObject) extends EntityDef[UserModel, User](model, attributes) with UserAttributes with org.elastic4play.services.User { +class User(model: UserModel, attributes: JsObject) extends EntityDef[UserModel, User](model, attributes) with UserAttributes with EUser { override def getUserName = userName() - override def getRoles = roles() + override def getRoles = roles() - override def toJson: JsObject = super.toJson + - ("roles" → JsArray(roles().map(r ⇒ JsString(r.name.toLowerCase())))) + - ("hasKey" → JsBoolean(key().isDefined)) + - ("hasPassword" → JsBoolean(password().isDefined)) -} \ No newline at end of file + override def toJson: JsObject = + super.toJson + + ("roles" → JsArray(roles().map(r ⇒ JsString(r.name.toLowerCase())))) + + ("hasKey" → JsBoolean(key().isDefined)) + + ("hasPassword" → JsBoolean(password().isDefined)) +} diff --git a/app/org/thp/cortex/models/Worker.scala b/app/org/thp/cortex/models/Worker.scala index 715a8aa07..567087ab4 100644 --- a/app/org/thp/cortex/models/Worker.scala +++ b/app/org/thp/cortex/models/Worker.scala @@ -1,22 +1,22 @@ package org.thp.cortex.models -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import scala.concurrent.Future import scala.util.Try -import play.api.libs.json.{ JsObject, JsString, Json } +import play.api.libs.json.{JsObject, JsString, Json} import org.elastic4play.models.JsonFormat.enumFormat -import org.elastic4play.models.{ AttributeDef, BaseEntity, ChildModelDef, EntityDef, HiveEnumeration, AttributeFormat ⇒ F, AttributeOption ⇒ O } +import org.elastic4play.models.{AttributeDef, BaseEntity, ChildModelDef, EntityDef, HiveEnumeration, AttributeFormat ⇒ F, AttributeOption ⇒ O} import org.elastic4play.utils.Hasher import org.thp.cortex.models.JsonFormat.workerTypeFormat object RateUnit extends Enumeration with HiveEnumeration { type Type = Value - val Day = Value(1) - val Month = Value(30) + val Day = Value(1) + val Month = Value(30) implicit val reads = enumFormat(this) } @@ -26,34 +26,37 @@ object WorkerType extends Enumeration with HiveEnumeration { } trait WorkerAttributes { _: AttributeDef ⇒ - val workerId = attribute("_id", F.stringFmt, "Worker id", O.model) - val name = attribute("name", F.stringFmt, "Worker name") - val vers = attribute("version", F.stringFmt, "Worker version", O.readonly) + val workerId = attribute("_id", F.stringFmt, "Worker id", O.model) + val name = attribute("name", F.stringFmt, "Worker name") + val vers = attribute("version", F.stringFmt, "Worker version", O.readonly) val workerDefinitionId = attribute("workerDefinitionId", F.stringFmt, "Worker definition id", O.readonly) - val description = attribute("description", F.textFmt, "Worker description", O.readonly) - val author = attribute("author", F.textFmt, "Worker author", O.readonly) - val url = attribute("url", F.textFmt, "Worker url", O.readonly) - val license = attribute("license", F.textFmt, "Worker license", O.readonly) - val command = optionalAttribute("command", F.textFmt, "Worker command", O.readonly) - val dockerImage = optionalAttribute("dockerImage", F.textFmt, "Worker docker image", O.readonly) - val dataTypeList = multiAttribute("dataTypeList", F.stringFmt, "List of data type this worker can manage") - val configuration = attribute("configuration", F.rawFmt, "Configuration of the worker", O.sensitive) - val baseConfig = attribute("baseConfig", F.stringFmt, "Base configuration key", O.readonly) - val rate = optionalAttribute("rate", F.numberFmt, "Number ") - val rateUnit = optionalAttribute("rateUnit", F.enumFmt(RateUnit), "") - val jobCache = optionalAttribute("jobCache", F.numberFmt, "") - val jobTimeout = optionalAttribute("jobTimeout", F.numberFmt, "") - val tpe = attribute("type", F.enumFmt(WorkerType), "", O.readonly) + val description = attribute("description", F.textFmt, "Worker description", O.readonly) + val author = attribute("author", F.textFmt, "Worker author", O.readonly) + val url = attribute("url", F.textFmt, "Worker url", O.readonly) + val license = attribute("license", F.textFmt, "Worker license", O.readonly) + val command = optionalAttribute("command", F.textFmt, "Worker command", O.readonly) + val dockerImage = optionalAttribute("dockerImage", F.textFmt, "Worker docker image", O.readonly) + val dataTypeList = multiAttribute("dataTypeList", F.stringFmt, "List of data type this worker can manage") + val configuration = attribute("configuration", F.rawFmt, "Configuration of the worker", O.sensitive) + val baseConfig = attribute("baseConfig", F.stringFmt, "Base configuration key", O.readonly) + val rate = optionalAttribute("rate", F.numberFmt, "Number ") + val rateUnit = optionalAttribute("rateUnit", F.enumFmt(RateUnit), "") + val jobCache = optionalAttribute("jobCache", F.numberFmt, "") + val jobTimeout = optionalAttribute("jobTimeout", F.numberFmt, "") + val tpe = attribute("type", F.enumFmt(WorkerType), "", O.readonly) } @Singleton -class WorkerModel @Inject() (organizationModel: OrganizationModel) extends ChildModelDef[WorkerModel, Worker, OrganizationModel, Organization](organizationModel, "worker", "Worker", "/worker") with WorkerAttributes with AuditedModel { +class WorkerModel @Inject()(organizationModel: OrganizationModel) + extends ChildModelDef[WorkerModel, Worker, OrganizationModel, Organization](organizationModel, "worker", "Worker", "/worker") + with WorkerAttributes + with AuditedModel { override def creationHook(parent: Option[BaseEntity], attrs: JsObject): Future[JsObject] = { val hasher = Hasher("md5") val id = for { organizationId ← parent.map(_.id) - name ← (attrs \ "name").asOpt[String] - tpe ← (attrs \ "type").asOpt[String] + name ← (attrs \ "name").asOpt[String] + tpe ← (attrs \ "type").asOpt[String] } yield hasher.fromString(s"${organizationId}_${name}_$tpe").head.toString Future.successful(attrs + ("_id" → JsString(id.getOrElse("")))) } @@ -61,5 +64,5 @@ class WorkerModel @Inject() (organizationModel: OrganizationModel) extends Child class Worker(model: WorkerModel, attributes: JsObject) extends EntityDef[WorkerModel, Worker](model, attributes) with WorkerAttributes { def config: JsObject = Try(Json.parse(configuration()).as[JsObject]).getOrElse(JsObject.empty) - def organization = parentId.get + def organization = parentId.get } diff --git a/app/org/thp/cortex/models/WorkerConfig.scala b/app/org/thp/cortex/models/WorkerConfig.scala index 84d5a26f4..a98eedd61 100644 --- a/app/org/thp/cortex/models/WorkerConfig.scala +++ b/app/org/thp/cortex/models/WorkerConfig.scala @@ -1,25 +1,32 @@ package org.thp.cortex.models -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} -import play.api.libs.json.{ JsObject, Json } +import play.api.libs.json.{JsObject, Json} -import org.elastic4play.models.{ AttributeDef, ChildModelDef, EntityDef, AttributeFormat ⇒ F, AttributeOption ⇒ O } +import org.elastic4play.models.{AttributeDef, ChildModelDef, EntityDef, AttributeFormat ⇒ F, AttributeOption ⇒ O} import org.thp.cortex.models.JsonFormat.workerTypeFormat trait WorkerConfigAttributes { _: AttributeDef ⇒ - val name = attribute("name", F.stringFmt, "Worker name") + val name = attribute("name", F.stringFmt, "Worker name") val config = attribute("config", F.rawFmt, "Configuration of worker", O.sensitive) - val tpe = attribute("type", F.enumFmt(WorkerType), "", O.readonly) + val tpe = attribute("type", F.enumFmt(WorkerType), "", O.readonly) } @Singleton -class WorkerConfigModel @Inject() ( - organizationModel: OrganizationModel) extends ChildModelDef[WorkerConfigModel, WorkerConfig, OrganizationModel, Organization](organizationModel, "workerConfig", "WorkerConfig", "/worker/config") with WorkerConfigAttributes { -} +class WorkerConfigModel @Inject()(organizationModel: OrganizationModel) + extends ChildModelDef[WorkerConfigModel, WorkerConfig, OrganizationModel, Organization]( + organizationModel, + "workerConfig", + "WorkerConfig", + "/worker/config" + ) + with WorkerConfigAttributes {} -class WorkerConfig(model: WorkerConfigModel, attributes: JsObject) extends EntityDef[WorkerConfigModel, WorkerConfig](model, attributes) with WorkerConfigAttributes { +class WorkerConfig(model: WorkerConfigModel, attributes: JsObject) + extends EntityDef[WorkerConfigModel, WorkerConfig](model, attributes) + with WorkerConfigAttributes { def organization = parentId.get - def jsonConfig = Json.parse(config()).as[JsObject] + def jsonConfig = Json.parse(config()).as[JsObject] } diff --git a/app/org/thp/cortex/models/WorkerDefinition.scala b/app/org/thp/cortex/models/WorkerDefinition.scala index e209cfe11..2eb22fdb6 100644 --- a/app/org/thp/cortex/models/WorkerDefinition.scala +++ b/app/org/thp/cortex/models/WorkerDefinition.scala @@ -1,6 +1,6 @@ package org.thp.cortex.models -import java.nio.file.{ Path, Paths } +import java.nio.file.{Path, Paths} import play.api.Logger import play.api.libs.functional.syntax._ @@ -13,11 +13,11 @@ import org.scalactic._ import org.elastic4play.controllers.JsonInputValue import org.elastic4play.models.HiveEnumeration import org.elastic4play.models.JsonFormat.enumFormat -import org.elastic4play.{ AttributeError, InvalidFormatAttributeError, MissingAttributeError } +import org.elastic4play.{AttributeError, InvalidFormatAttributeError, MissingAttributeError} object WorkerConfigItemType extends Enumeration with HiveEnumeration { type Type = Value - val text, string, number, boolean = Value + val text, string, number, boolean = Value implicit val reads: Format[WorkerConfigItemType.Type] = enumFormat(this) } @@ -27,7 +27,8 @@ case class ConfigurationDefinitionItem( `type`: WorkerConfigItemType.Type, multi: Boolean, required: Boolean, - defaultValue: Option[JsValue]) { + defaultValue: Option[JsValue] +) { def isRequired: Boolean = required def isMulti: Boolean = multi @@ -43,8 +44,9 @@ case class ConfigurationDefinitionItem( } } - def read(config: JsObject): (String, JsValue) Or Every[AttributeError] = { - (config \ name).toOption + def read(config: JsObject): (String, JsValue) Or Every[AttributeError] = + (config \ name) + .toOption .orElse(defaultValue) .map { case JsArray(values) if isMulti ⇒ values.validatedBy(check).map(a ⇒ name → JsArray(a)) @@ -56,12 +58,10 @@ case class ConfigurationDefinitionItem( else if (isRequired) Bad(One(MissingAttributeError(name))) else Good(name → JsNull) } - } } object ConfigurationDefinitionItem { - implicit val reads: Reads[ConfigurationDefinitionItem] = ( - (JsPath \ "name").read[String] and + implicit val reads: Reads[ConfigurationDefinitionItem] = ((JsPath \ "name").read[String] and (JsPath \ "description").read[String] and (JsPath \ "type").read[WorkerConfigItemType.Type] and (JsPath \ "multi").readWithDefault[Boolean](false) and @@ -83,7 +83,8 @@ case class WorkerDefinition( baseConfiguration: Option[String], configurationItems: Seq[ConfigurationDefinitionItem], configuration: JsObject, - tpe: WorkerType.Type) { + tpe: WorkerType.Type +) { val id: String = (name + "_" + version).replaceAll("\\.", "_") def canProcessDataType(dataType: String): Boolean = dataTypeList.contains(dataType) @@ -92,20 +93,20 @@ case class WorkerDefinition( object WorkerDefinition { lazy val logger = Logger(getClass) - def singleReads(workerType: WorkerType.Type): Reads[WorkerDefinition] = ( - (JsPath \ "name").read[String] and - (JsPath \ "version").read[String] and - (JsPath \ "description").read[String] and - (JsPath \ "dataTypeList").read[Seq[String]].orElse(Reads.pure(Nil)) and - (JsPath \ "author").read[String] and - (JsPath \ "url").read[String] and - (JsPath \ "license").read[String] and - (JsPath \ "dockerImage").readNullable[String] and - (JsPath \ "command").readNullable[String].map(_.map(Paths.get(_))) and - (JsPath \ "baseConfig").readNullable[String] and - (JsPath \ "configurationItems").read[Seq[ConfigurationDefinitionItem]].orElse(Reads.pure(Nil)) and - (JsPath \ "config").read[JsObject].orElse(Reads.pure(JsObject.empty)) and - Reads.pure(workerType))(WorkerDefinition.apply _) + def singleReads(workerType: WorkerType.Type): Reads[WorkerDefinition] = + ((JsPath \ "name").read[String] and + (JsPath \ "version").read[String] and + (JsPath \ "description").read[String] and + (JsPath \ "dataTypeList").read[Seq[String]].orElse(Reads.pure(Nil)) and + (JsPath \ "author").read[String] and + (JsPath \ "url").read[String] and + (JsPath \ "license").read[String] and + (JsPath \ "dockerImage").readNullable[String] and + (JsPath \ "command").readNullable[String].map(_.map(Paths.get(_))) and + (JsPath \ "baseConfig").readNullable[String] and + (JsPath \ "configurationItems").read[Seq[ConfigurationDefinitionItem]].orElse(Reads.pure(Nil)) and + (JsPath \ "config").read[JsObject].orElse(Reads.pure(JsObject.empty)) and + Reads.pure(workerType))(WorkerDefinition.apply _) def reads(workerType: WorkerType.Type): Reads[List[WorkerDefinition]] = { val reads = singleReads(workerType) @@ -114,17 +115,18 @@ object WorkerDefinition { implicit val writes: Writes[WorkerDefinition] = Writes[WorkerDefinition] { workerDefinition ⇒ Json.obj( - "id" → workerDefinition.id, - "name" → workerDefinition.name, - "version" → workerDefinition.version, - "description" → workerDefinition.description, - "dataTypeList" → workerDefinition.dataTypeList, - "author" → workerDefinition.author, - "url" → workerDefinition.url, - "license" → workerDefinition.license, - "baseConfig" → workerDefinition.baseConfiguration, + "id" → workerDefinition.id, + "name" → workerDefinition.name, + "version" → workerDefinition.version, + "description" → workerDefinition.description, + "dataTypeList" → workerDefinition.dataTypeList, + "author" → workerDefinition.author, + "url" → workerDefinition.url, + "license" → workerDefinition.license, + "baseConfig" → workerDefinition.baseConfiguration, "configurationItems" → workerDefinition.configurationItems, - "dockerImage" → workerDefinition.dockerImage, - "command" → workerDefinition.command.map(_.getFileName.toString)) + "dockerImage" → workerDefinition.dockerImage, + "command" → workerDefinition.command.map(_.getFileName.toString) + ) } } diff --git a/app/org/thp/cortex/services/AnalyzerConfigSrv.scala b/app/org/thp/cortex/services/AnalyzerConfigSrv.scala index ca81b8385..0f59b4f5e 100644 --- a/app/org/thp/cortex/services/AnalyzerConfigSrv.scala +++ b/app/org/thp/cortex/services/AnalyzerConfigSrv.scala @@ -1,17 +1,17 @@ package org.thp.cortex.services -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import play.api.Configuration import akka.stream.Materializer -import javax.inject.{ Inject, Singleton } -import org.thp.cortex.models.{ BaseConfig, WorkerConfigModel, WorkerType } +import javax.inject.{Inject, Singleton} +import org.thp.cortex.models.{BaseConfig, WorkerConfigModel, WorkerType} -import org.elastic4play.services.{ CreateSrv, FindSrv, UpdateSrv } +import org.elastic4play.services.{CreateSrv, FindSrv, UpdateSrv} @Singleton -class AnalyzerConfigSrv @Inject() ( +class AnalyzerConfigSrv @Inject()( val configuration: Configuration, val workerConfigModel: WorkerConfigModel, val userSrv: UserSrv, @@ -21,9 +21,11 @@ class AnalyzerConfigSrv @Inject() ( val updateSrv: UpdateSrv, val findSrv: FindSrv, implicit val ec: ExecutionContext, - implicit val mat: Materializer) extends WorkerConfigSrv { + implicit val mat: Materializer +) extends WorkerConfigSrv { override val workerType: WorkerType.Type = WorkerType.analyzer + def definitions: Future[Map[String, BaseConfig]] = buildDefinitionMap(workerSrv.listAnalyzerDefinitions._1) } diff --git a/app/org/thp/cortex/services/AuditSrv.scala b/app/org/thp/cortex/services/AuditSrv.scala index a34eebacf..7dbb9c3e7 100644 --- a/app/org/thp/cortex/services/AuditSrv.scala +++ b/app/org/thp/cortex/services/AuditSrv.scala @@ -1,13 +1,13 @@ package org.thp.cortex.services -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import scala.concurrent.ExecutionContext import scala.concurrent.duration.FiniteDuration import play.api.Logger -import akka.actor.{ Actor, ActorRef } +import akka.actor.{Actor, ActorRef} import org.thp.cortex.models.JobStatus import org.elastic4play.models.BaseEntity @@ -18,16 +18,16 @@ object AuditActor { case class Unregister(jobId: String, actorRef: ActorRef) case class JobEnded(jobId: String, status: JobStatus.Type) } + @Singleton -class AuditActor @Inject() ( - eventSrv: EventSrv, - implicit val ec: ExecutionContext) extends Actor { +class AuditActor @Inject()(eventSrv: EventSrv, implicit val ec: ExecutionContext) extends Actor { import AuditActor._ + object EntityExtractor { def unapply(e: BaseEntity) = Some((e.model, e.id, e.routing)) } - var registration = Map.empty[String, Seq[ActorRef]] + var registration = Map.empty[String, Seq[ActorRef]] private[AuditActor] lazy val logger = Logger(getClass) override def preStart(): Unit = { @@ -56,7 +56,9 @@ class AuditActor @Inject() ( if (model.modelName == "job" && action == AuditableAction.Update) { logger.info(s"Job $id has be updated (${details \ "status"})") val status = (details \ "status").asOpt[JobStatus.Type].getOrElse(JobStatus.InProgress) - if (status != JobStatus.InProgress) registration.getOrElse(id, Nil).foreach { aref ⇒ aref ! JobEnded(id, status) } + if (status != JobStatus.InProgress) registration.getOrElse(id, Nil).foreach { aref ⇒ + aref ! JobEnded(id, status) + } } } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/services/CSRFFilter.scala b/app/org/thp/cortex/services/CSRFFilter.scala index 28610c3f7..4c78931a7 100644 --- a/app/org/thp/cortex/services/CSRFFilter.scala +++ b/app/org/thp/cortex/services/CSRFFilter.scala @@ -1,12 +1,13 @@ package org.thp.cortex.services -import javax.inject.{ Inject, Provider, Singleton } +import javax.inject.{Inject, Provider, Singleton} import play.api.Logger import play.api.http.SessionConfiguration import play.api.libs.crypto.CSRFTokenSigner +import play.filters.csrf.{CSRFFilter ⇒ PCSRFFilter} import play.api.mvc.RequestHeader -import play.filters.csrf.CSRF.{ ErrorHandler ⇒ CSRFErrorHandler, TokenProvider } +import play.filters.csrf.CSRF.{ErrorHandler ⇒ CSRFErrorHandler, TokenProvider} import play.filters.csrf.CSRFConfig import akka.stream.Materializer @@ -15,10 +16,10 @@ object CSRFFilter { private[CSRFFilter] lazy val logger = Logger(getClass) def shouldProtect(request: RequestHeader): Boolean = { - val isLogin = request.uri.startsWith("/api/login") - val isApi = request.uri.startsWith("/api") + val isLogin = request.uri.startsWith("/api/login") + val isApi = request.uri.startsWith("/api") val isInSession = request.session.data.nonEmpty - val check = !isLogin && isApi && isInSession + val check = !isLogin && isApi && isInSession logger.debug(s"[csrf] uri ${request.uri} (isLogin=$isLogin, isApi=$isApi, isInSession=$isInSession): ${if (check) "" else "don't"} check") check } @@ -26,15 +27,17 @@ object CSRFFilter { } @Singleton -class CSRFFilter @Inject() ( +class CSRFFilter @Inject()( config: Provider[CSRFConfig], tokenSignerProvider: Provider[CSRFTokenSigner], sessionConfiguration: SessionConfiguration, tokenProvider: TokenProvider, - errorHandler: CSRFErrorHandler)(mat: Materializer) - extends play.filters.csrf.CSRFFilter( - config.get.copy(shouldProtect = CSRFFilter.shouldProtect), - tokenSignerProvider.get, - sessionConfiguration, - tokenProvider, - errorHandler)(mat) \ No newline at end of file + errorHandler: CSRFErrorHandler +)(mat: Materializer) + extends PCSRFFilter( + config.get.copy(shouldProtect = CSRFFilter.shouldProtect), + tokenSignerProvider.get, + sessionConfiguration, + tokenProvider, + errorHandler + )(mat) diff --git a/app/org/thp/cortex/services/CortexAuthSrv.scala b/app/org/thp/cortex/services/CortexAuthSrv.scala index 50cb8d066..4533239a3 100644 --- a/app/org/thp/cortex/services/CortexAuthSrv.scala +++ b/app/org/thp/cortex/services/CortexAuthSrv.scala @@ -1,11 +1,11 @@ package org.thp.cortex.services -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import scala.collection.immutable import scala.concurrent.ExecutionContext -import play.api.{ Configuration, Logger } +import play.api.{Configuration, Logger} import org.elastic4play.services.AuthSrv import org.elastic4play.services.auth.MultiAuthSrv @@ -13,28 +13,28 @@ import org.elastic4play.services.auth.MultiAuthSrv object CortexAuthSrv { private[CortexAuthSrv] lazy val logger = Logger(getClass) - def getAuthSrv(authTypes: Seq[String], authModules: immutable.Set[AuthSrv]): Seq[AuthSrv] = { + def getAuthSrv(authTypes: Seq[String], authModules: immutable.Set[AuthSrv]): Seq[AuthSrv] = ("key" +: authTypes.filterNot(_ == "key")) .flatMap { authType ⇒ - authModules.find(_.name == authType) + authModules + .find(_.name == authType) .orElse { logger.error(s"Authentication module $authType not found") None } } - } } @Singleton -class CortexAuthSrv @Inject() ( +class CortexAuthSrv @Inject()( configuration: Configuration, authModules: immutable.Set[AuthSrv], userSrv: UserSrv, - override implicit val ec: ExecutionContext) extends MultiAuthSrv( - CortexAuthSrv.getAuthSrv( - configuration.getDeprecated[Option[Seq[String]]]("auth.provider", "auth.type").getOrElse(Seq("local")), - authModules), - ec) { + implicit override val ec: ExecutionContext +) extends MultiAuthSrv( + CortexAuthSrv.getAuthSrv(configuration.getDeprecated[Option[Seq[String]]]("auth.provider", "auth.type").getOrElse(Seq("local")), authModules), + ec + ) { // Uncomment the following lines if you want to prevent user with key to use password to authenticate // override def authenticate(username: String, password: String)(implicit request: RequestHeader): Future[AuthContext] = diff --git a/app/org/thp/cortex/services/DockerJobRunnerSrv.scala b/app/org/thp/cortex/services/DockerJobRunnerSrv.scala index 248e812db..93d0fb475 100644 --- a/app/org/thp/cortex/services/DockerJobRunnerSrv.scala +++ b/app/org/thp/cortex/services/DockerJobRunnerSrv.scala @@ -4,18 +4,18 @@ import java.nio.charset.StandardCharsets import java.nio.file._ import scala.concurrent.duration.FiniteDuration -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import scala.util.Try import play.api.libs.json.Json -import play.api.{ Configuration, Logger } +import play.api.{Configuration, Logger} import akka.actor.ActorSystem import com.spotify.docker.client.DockerClient.LogsParam import com.spotify.docker.client.messages.HostConfig.Bind -import com.spotify.docker.client.messages.{ ContainerConfig, HostConfig } -import com.spotify.docker.client.{ DefaultDockerClient, DockerClient } -import javax.inject.{ Inject, Singleton } +import com.spotify.docker.client.messages.{ContainerConfig, HostConfig} +import com.spotify.docker.client.{DefaultDockerClient, DockerClient} +import javax.inject.{Inject, Singleton} import org.thp.cortex.models._ import org.elastic4play.utils.RichFuture @@ -24,19 +24,21 @@ import org.elastic4play.utils.RichFuture class DockerJobRunnerSrv(client: DockerClient, autoUpdate: Boolean, implicit val system: ActorSystem) { @Inject() - def this(config: Configuration, system: ActorSystem) = this( - new DefaultDockerClient.Builder() - .apiVersion(config.getOptional[String]("docker.version").orNull) - .connectionPoolSize(config.getOptional[Int]("docker.connectionPoolSize").getOrElse(100)) - .connectTimeoutMillis(config.getOptional[Long]("docker.connectTimeoutMillis").getOrElse(5000)) - //.dockerCertificates() - .readTimeoutMillis(config.getOptional[Long]("docker.readTimeoutMillis").getOrElse(30000)) - //.registryAuthSupplier() - .uri(config.getOptional[String]("docker.uri").getOrElse("unix:///var/run/docker.sock")) - .useProxy(config.getOptional[Boolean]("docker.useProxy").getOrElse(false)) - .build(), - config.getOptional[Boolean]("docker.autoUpdate").getOrElse(true), - system: ActorSystem) + def this(config: Configuration, system: ActorSystem) = + this( + new DefaultDockerClient.Builder() + .apiVersion(config.getOptional[String]("docker.version").orNull) + .connectionPoolSize(config.getOptional[Int]("docker.connectionPoolSize").getOrElse(100)) + .connectTimeoutMillis(config.getOptional[Long]("docker.connectTimeoutMillis").getOrElse(5000)) + //.dockerCertificates() + .readTimeoutMillis(config.getOptional[Long]("docker.readTimeoutMillis").getOrElse(30000)) + //.registryAuthSupplier() + .uri(config.getOptional[String]("docker.uri").getOrElse("unix:///var/run/docker.sock")) + .useProxy(config.getOptional[Boolean]("docker.useProxy").getOrElse(false)) + .build(), + config.getOptional[Boolean]("docker.autoUpdate").getOrElse(true), + system: ActorSystem + ) lazy val logger = Logger(getClass) @@ -44,8 +46,7 @@ class DockerJobRunnerSrv(client: DockerClient, autoUpdate: Boolean, implicit val Try { logger.info(s"Docker is available:\n${client.info()}") true - } - .getOrElse { + }.getOrElse { logger.info(s"Docker is not available") false } @@ -54,11 +55,15 @@ class DockerJobRunnerSrv(client: DockerClient, autoUpdate: Boolean, implicit val import scala.collection.JavaConverters._ if (autoUpdate) client.pull(dockerImage) // ContainerConfig.builder().addVolume() - val hostConfig = HostConfig.builder() - .appendBinds(Bind.from(jobDirectory.toAbsolutePath.toString) - .to("/job") - .readOnly(false) - .build()) + val hostConfig = HostConfig + .builder() + .appendBinds( + Bind + .from(jobDirectory.toAbsolutePath.toString) + .to("/job") + .readOnly(false) + .build() + ) .build() val cacertsFile = jobDirectory.resolve("input").resolve("cacerts") val containerConfigBuilder = ContainerConfig @@ -67,34 +72,35 @@ class DockerJobRunnerSrv(client: DockerClient, autoUpdate: Boolean, implicit val .image(dockerImage) .cmd("/job") - val containerConfig = if (Files.exists(cacertsFile)) containerConfigBuilder.env(s"REQUESTS_CA_BUNDLE=/job/input/cacerts").build() - else containerConfigBuilder.build() + val containerConfig = + if (Files.exists(cacertsFile)) containerConfigBuilder.env(s"REQUESTS_CA_BUNDLE=/job/input/cacerts").build() + else containerConfigBuilder.build() val containerCreation = client.createContainer(containerConfig) // Option(containerCreation.warnings()).flatMap(_.asScala).foreach(logger.warn) - logger.info(s"Execute container ${containerCreation.id()}\n" + - s" timeout: ${timeout.fold("none")(_.toString)}\n" + - s" image : $dockerImage\n" + - s" volume : ${jobDirectory.toAbsolutePath}:/job" + - Option(containerConfig.env()).fold("")(_.asScala.map("\n env : " + _).mkString)) + logger.info( + s"Execute container ${containerCreation.id()}\n" + + s" timeout: ${timeout.fold("none")(_.toString)}\n" + + s" image : $dockerImage\n" + + s" volume : ${jobDirectory.toAbsolutePath}:/job" + + Option(containerConfig.env()).fold("")(_.asScala.map("\n env : " + _).mkString) + ) val execution = Future { client.startContainer(containerCreation.id()) client.waitContainer(containerCreation.id()) () - } - .andThen { + }.andThen { case r ⇒ if (!Files.exists(jobDirectory.resolve("output").resolve("output.json"))) { val message = r.fold(e ⇒ s"Docker creation error: ${e.getMessage}\n", _ ⇒ "") + Try(client.logs(containerCreation.id(), LogsParam.stdout(), LogsParam.stderr()).readFully()) - .recover { case e ⇒ s"Container logs can't be read (${e.getMessage}" } - val report = Json.obj( - "success" -> false, - "errorMessage" -> message) + .recover { case e ⇒ s"Container logs can't be read (${e.getMessage}" } + val report = Json.obj("success" → false, "errorMessage" → message) Files.write(jobDirectory.resolve("output").resolve("output.json"), report.toString.getBytes(StandardCharsets.UTF_8)) } } - timeout.fold(execution)(t ⇒ execution.withTimeout(t, client.stopContainer(containerCreation.id(), 3))) + timeout + .fold(execution)(t ⇒ execution.withTimeout(t, client.stopContainer(containerCreation.id(), 3))) .andThen { case _ ⇒ client.removeContainer(containerCreation.id(), DockerClient.RemoveContainerParam.forceKill()) } diff --git a/app/org/thp/cortex/services/ErrorHandler.scala b/app/org/thp/cortex/services/ErrorHandler.scala index 0757378b5..0d8c8fb72 100644 --- a/app/org/thp/cortex/services/ErrorHandler.scala +++ b/app/org/thp/cortex/services/ErrorHandler.scala @@ -4,13 +4,27 @@ import java.net.ConnectException import scala.concurrent.Future -import org.thp.cortex.models.{ JobNotFoundError, RateLimitExceeded, WorkerNotFoundError } +import org.thp.cortex.models.{JobNotFoundError, RateLimitExceeded, WorkerNotFoundError} import play.api.Logger -import play.api.http.{ HttpErrorHandler, Status, Writeable } -import play.api.libs.json.{ JsNull, JsValue, Json } -import play.api.mvc.{ RequestHeader, ResponseHeader, Result, Results } +import play.api.http.{HttpErrorHandler, Status, Writeable} +import play.api.libs.json.{JsNull, JsValue, Json} +import play.api.mvc.{RequestHeader, ResponseHeader, Result, Results} -import org.elastic4play.{ AttributeCheckingError, AuthenticationError, AuthorizationError, BadRequestError, CreateError, ErrorWithObject, GetError, IndexNotFoundException, InternalError, MultiError, NotFoundError, SearchError, UpdateError } +import org.elastic4play.{ + AttributeCheckingError, + AuthenticationError, + AuthorizationError, + BadRequestError, + CreateError, + ErrorWithObject, + GetError, + IndexNotFoundException, + InternalError, + MultiError, + NotFoundError, + SearchError, + UpdateError +} import org.elastic4play.JsonFormat.attributeCheckingExceptionWrites /** @@ -18,38 +32,43 @@ import org.elastic4play.JsonFormat.attributeCheckingExceptionWrites */ class ErrorHandler extends HttpErrorHandler { private[ErrorHandler] lazy val logger = Logger(getClass) + def onClientError(request: RequestHeader, statusCode: Int, message: String): Future[Result] = Future.successful { Results.Status(statusCode)(s"A client error occurred on ${request.method} ${request.uri} : $message") } - def toErrorResult(ex: Throwable): Option[(Int, JsValue)] = { + def toErrorResult(ex: Throwable): Option[(Int, JsValue)] = ex match { - case AuthenticationError(message) ⇒ Some(Status.UNAUTHORIZED → Json.obj("type" → "AuthenticationError", "message" → message)) - case AuthorizationError(message) ⇒ Some(Status.FORBIDDEN → Json.obj("type" → "AuthorizationError", "message" → message)) - case UpdateError(_, message, attributes) ⇒ Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "UpdateError", "message" → message, "object" → attributes)) - case rle: RateLimitExceeded ⇒ Some(Status.TOO_MANY_REQUESTS → Json.obj("type" → "RateLimitExceeded", "message" → rle.getMessage)) - case InternalError(message) ⇒ Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "InternalError", "message" → message)) - case nfe: NumberFormatException ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "NumberFormatException", "message" → ("Invalid format " + nfe.getMessage))) - case NotFoundError(message) ⇒ Some(Status.NOT_FOUND → Json.obj("type" → "NotFoundError", "message" → message)) - case BadRequestError(message) ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "BadRequest", "message" → message)) - case SearchError(message) ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "SearchError", "message" → s"$message")) - case ace: AttributeCheckingError ⇒ Some(Status.BAD_REQUEST → Json.toJson(ace)) - case iae: IllegalArgumentException ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "IllegalArgument", "message" → iae.getMessage)) - case _: ConnectException ⇒ Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "NoNodeAvailable", "message" → "ElasticSearch cluster is unreachable")) - case CreateError(_, message, attributes) ⇒ Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "CreateError", "message" → message, "object" → attributes)) - case ErrorWithObject(tpe, message, obj) ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → tpe, "message" → message, "object" → obj)) - case GetError(message) ⇒ Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "GetError", "message" → message)) + case AuthenticationError(message) ⇒ Some(Status.UNAUTHORIZED → Json.obj("type" → "AuthenticationError", "message" → message)) + case AuthorizationError(message) ⇒ Some(Status.FORBIDDEN → Json.obj("type" → "AuthorizationError", "message" → message)) + case UpdateError(_, message, attributes) ⇒ + Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "UpdateError", "message" → message, "object" → attributes)) + case rle: RateLimitExceeded ⇒ Some(Status.TOO_MANY_REQUESTS → Json.obj("type" → "RateLimitExceeded", "message" → rle.getMessage)) + case InternalError(message) ⇒ Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "InternalError", "message" → message)) + case nfe: NumberFormatException ⇒ + Some(Status.BAD_REQUEST → Json.obj("type" → "NumberFormatException", "message" → ("Invalid format " + nfe.getMessage))) + case NotFoundError(message) ⇒ Some(Status.NOT_FOUND → Json.obj("type" → "NotFoundError", "message" → message)) + case BadRequestError(message) ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "BadRequest", "message" → message)) + case SearchError(message) ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "SearchError", "message" → s"$message")) + case ace: AttributeCheckingError ⇒ Some(Status.BAD_REQUEST → Json.toJson(ace)) + case iae: IllegalArgumentException ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → "IllegalArgument", "message" → iae.getMessage)) + case _: ConnectException ⇒ + Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "NoNodeAvailable", "message" → "ElasticSearch cluster is unreachable")) + case CreateError(_, message, attributes) ⇒ + Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "CreateError", "message" → message, "object" → attributes)) + case ErrorWithObject(tpe, message, obj) ⇒ Some(Status.BAD_REQUEST → Json.obj("type" → tpe, "message" → message, "object" → obj)) + case GetError(message) ⇒ Some(Status.INTERNAL_SERVER_ERROR → Json.obj("type" → "GetError", "message" → message)) case MultiError(message, exceptions) ⇒ val suberrors = exceptions.map(e ⇒ toErrorResult(e)).collect { case Some((_, j)) ⇒ j } Some(Status.MULTI_STATUS → Json.obj("type" → "MultiError", "error" → message, "suberrors" → suberrors)) - case JobNotFoundError(jobId) ⇒ Some(Status.NOT_FOUND → Json.obj("type" → "JobNotFoundError", "message" → s"Job $jobId not found")) - case WorkerNotFoundError(analyzerId) ⇒ Some(Status.NOT_FOUND → Json.obj("type" → "AnalyzerNotFoundError", "message" → s"analyzer $analyzerId not found")) + case JobNotFoundError(jobId) ⇒ Some(Status.NOT_FOUND → Json.obj("type" → "JobNotFoundError", "message" → s"Job $jobId not found")) + case WorkerNotFoundError(analyzerId) ⇒ + Some(Status.NOT_FOUND → Json.obj("type" → "AnalyzerNotFoundError", "message" → s"analyzer $analyzerId not found")) case IndexNotFoundException ⇒ Some(520 → JsNull) case t: Throwable ⇒ Option(t.getCause).flatMap(toErrorResult) } - } def toResult[C](status: Int, c: C)(implicit writeable: Writeable[C]) = Result(header = ResponseHeader(status), body = writeable.toEntity(c)) diff --git a/app/org/thp/cortex/services/JobRunnerSrv.scala b/app/org/thp/cortex/services/JobRunnerSrv.scala index 76af9cc0d..8f6b692c4 100644 --- a/app/org/thp/cortex/services/JobRunnerSrv.scala +++ b/app/org/thp/cortex/services/JobRunnerSrv.scala @@ -7,11 +7,11 @@ import java.nio.file.attribute.BasicFileAttributes import java.util.Date import scala.concurrent.duration.DurationLong -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import scala.util.Failure import play.api.libs.json._ -import play.api.{ Configuration, Logger } +import play.api.{Configuration, Logger} import akka.actor.ActorSystem import akka.stream.Materializer @@ -20,11 +20,11 @@ import javax.inject.Inject import org.thp.cortex.models._ import org.elastic4play.BadRequestError -import org.elastic4play.controllers.{ Fields, FileInputValue } +import org.elastic4play.controllers.{Fields, FileInputValue} import org.elastic4play.database.ModifyConfig -import org.elastic4play.services.{ AttachmentSrv, AuthContext, CreateSrv, UpdateSrv } +import org.elastic4play.services.{AttachmentSrv, AuthContext, CreateSrv, UpdateSrv} -class JobRunnerSrv @Inject() ( +class JobRunnerSrv @Inject()( config: Configuration, reportModel: ReportModel, artifactModel: ArtifactModel, @@ -36,10 +36,11 @@ class JobRunnerSrv @Inject() ( attachmentSrv: AttachmentSrv, akkaSystem: ActorSystem, implicit val ec: ExecutionContext, - implicit val mat: Materializer) { + implicit val mat: Materializer +) { - val logger = Logger(getClass) - lazy val analyzerExecutionContext: ExecutionContext = akkaSystem.dispatchers.lookup("analyzer") + val logger = Logger(getClass) + lazy val analyzerExecutionContext: ExecutionContext = akkaSystem.dispatchers.lookup("analyzer") lazy val responderExecutionContext: ExecutionContext = akkaSystem.dispatchers.lookup("responder") private val runners: Seq[String] = config @@ -52,15 +53,19 @@ class JobRunnerSrv @Inject() ( Seq("", "2", "3").foreach { pythonVersion ⇒ val cortexUtilsVersion = processJobRunnerSrv.checkCortexUtilsVersion(pythonVersion) cortexUtilsVersion.fold(logger.warn(s"The package cortexutils for python$pythonVersion hasn't been found")) { - case (major, minor, patch) if major >= 2 ⇒ logger.info(s"The package cortexutils for python$pythonVersion has valid version: $major.$minor.$patch") - case (major, minor, patch) ⇒ logger.error(s"The package cortexutils for python$pythonVersion has invalid version: $major.$minor.$patch. Cortex 2 requires cortexutils >= 2.0") + case (major, minor, patch) if major >= 2 ⇒ + logger.info(s"The package cortexutils for python$pythonVersion has valid version: $major.$minor.$patch") + case (major, minor, patch) ⇒ + logger.error( + s"The package cortexutils for python$pythonVersion has invalid version: $major.$minor.$patch. Cortex 2 requires cortexutils >= 2.0" + ) } } "process" } lazy val processRunnerIsEnable: Boolean = runners.contains("process") - lazy val dockerRunnerIsEnable: Boolean = runners.contains("docker") + lazy val dockerRunnerIsEnable: Boolean = runners.contains("docker") private object deleteVisitor extends SimpleFileVisitor[Path] { override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = { @@ -74,24 +79,27 @@ class JobRunnerSrv @Inject() ( } } - private def delete(directory: Path): Unit = try { - if (Files.exists(directory)) - Files.walkFileTree(directory, deleteVisitor) - () - } - catch { - case t: Throwable ⇒ logger.warn(s"Fail to remove temporary files ($directory) : $t") - } + private def delete(directory: Path): Unit = + try { + if (Files.exists(directory)) + Files.walkFileTree(directory, deleteVisitor) + () + } catch { + case t: Throwable ⇒ logger.warn(s"Fail to remove temporary files ($directory) : $t") + } private def prepareJobFolder(worker: Worker, job: Job): Future[Path] = { - val jobFolder = Files.createTempDirectory(Paths.get(System.getProperty("java.io.tmpdir")), s"cortex-job-${job.id}-") + val jobFolder = Files.createTempDirectory(Paths.get(System.getProperty("java.io.tmpdir")), s"cortex-job-${job.id}-") val inputJobFolder = Files.createDirectories(jobFolder.resolve("input")) Files.createDirectories(jobFolder.resolve("output")) - job.attachment() + job + .attachment() .map { attachment ⇒ val attachmentFile = Files.createTempFile(inputJobFolder, "attachment", "") - attachmentSrv.source(attachment.id).runWith(FileIO.toPath(attachmentFile)) + attachmentSrv + .source(attachment.id) + .runWith(FileIO.toPath(attachmentFile)) .flatMap { case ioresult if ioresult.status.isSuccess ⇒ Future.successful(Some(attachmentFile)) case ioresult ⇒ Future.failed(ioresult.getError) @@ -100,19 +108,21 @@ class JobRunnerSrv @Inject() ( .getOrElse(Future.successful(None)) .map { case Some(file) ⇒ - Json.obj( - "file" → file.getFileName.toString, - "filename" → job.attachment().get.name, - "contentType" → job.attachment().get.contentType) + Json.obj("file" → file.getFileName.toString, "filename" → job.attachment().get.name, "contentType" → job.attachment().get.contentType) case None if job.data().nonEmpty && job.tpe() == WorkerType.responder ⇒ Json.obj("data" → Json.parse(job.data().get)) case None if job.data().nonEmpty && job.tpe() == WorkerType.analyzer ⇒ Json.obj("data" → job.data().get) } .map { artifact ⇒ - val proxy_http = (worker.config \ "proxy_http").asOpt[String].fold(JsObject.empty) { proxy ⇒ Json.obj("proxy" → Json.obj("http" → proxy)) } - val proxy_https = (worker.config \ "proxy_https").asOpt[String].fold(JsObject.empty) { proxy ⇒ Json.obj("proxy" → Json.obj("https" → proxy)) } - val config = workerSrv.getDefinition(worker.workerDefinitionId()) + val proxy_http = (worker.config \ "proxy_http").asOpt[String].fold(JsObject.empty) { proxy ⇒ + Json.obj("proxy" → Json.obj("http" → proxy)) + } + val proxy_https = (worker.config \ "proxy_https").asOpt[String].fold(JsObject.empty) { proxy ⇒ + Json.obj("proxy" → Json.obj("https" → proxy)) + } + val config = workerSrv + .getDefinition(worker.workerDefinitionId()) .fold(_ ⇒ JsObject.empty, _.configuration) .deepMerge(worker.config) .deepMerge(proxy_http) @@ -122,12 +132,12 @@ class JobRunnerSrv @Inject() ( Files.write(cacertsFile, cacerts.getBytes) } artifact + - ("dataType" → JsString(job.dataType())) + - ("tlp" → JsNumber(job.tlp())) + - ("pap" → JsNumber(job.pap())) + - ("message" → JsString(job.message().getOrElse(""))) + + ("dataType" → JsString(job.dataType())) + + ("tlp" → JsNumber(job.tlp())) + + ("pap" → JsNumber(job.pap())) + + ("message" → JsString(job.message().getOrElse(""))) + ("parameters" → job.params) + - ("config" -> config) + ("config" → config) } .map { input ⇒ Files.write(inputJobFolder.resolve("input.json"), input.toString.getBytes(StandardCharsets.UTF_8)) @@ -143,17 +153,18 @@ class JobRunnerSrv @Inject() ( private def extractReport(jobFolder: Path, job: Job)(implicit authContext: AuthContext) = { val outputFile = jobFolder.resolve("output").resolve("output.json") if (Files.exists(outputFile)) { - val is = Files.newInputStream(outputFile) + val is = Files.newInputStream(outputFile) val report = Json.parse(is) is.close() val success = (report \ "success").asOpt[Boolean].getOrElse(false) if (success) { - val fullReport = (report \ "full").as[JsObject].toString + val fullReport = (report \ "full").as[JsObject].toString val summaryReport = (report \ "summary").asOpt[JsObject].getOrElse(JsObject.empty).toString - val artifacts = (report \ "artifacts").asOpt[Seq[JsObject]].getOrElse(Nil) - val operations = (report \ "operations").asOpt[Seq[JsObject]].getOrElse(Nil) - val reportFields = Fields.empty + val artifacts = (report \ "artifacts").asOpt[Seq[JsObject]].getOrElse(Nil) + val operations = (report \ "operations").asOpt[Seq[JsObject]].getOrElse(Nil) + val reportFields = Fields + .empty .set("full", fullReport) .set("summary", summaryReport) .set("operations", JsArray(operations).toString) @@ -171,7 +182,7 @@ class JobRunnerSrv @Inject() ( path = jobFolder.resolve("output").resolve(file) if Files.exists(path) && path.getParent == jobFolder.resolve("output") contentType = (artifact \ "contentType").asOpt[String].getOrElse("application/octet-stream") - fiv = FileInputValue(name, path, contentType) + fiv = FileInputValue(name, path, contentType) } yield Fields(artifact - "filename" - "file" - "contentType").set("attachment", fiv) case _ ⇒ Some(Fields(artifact)) } @@ -182,19 +193,15 @@ class JobRunnerSrv @Inject() ( case Failure(e) ⇒ endJob(job, JobStatus.Failure, Some(s"Report creation failure: $e")) case _ ⇒ endJob(job, JobStatus.Success) } + } else { + endJob(job, JobStatus.Failure, (report \ "errorMessage").asOpt[String], (report \ "input").asOpt[JsValue].map(_.toString)) } - else { - endJob(job, JobStatus.Failure, - (report \ "errorMessage").asOpt[String], - (report \ "input").asOpt[JsValue].map(_.toString)) - } - } - else { + } else { endJob(job, JobStatus.Failure, Some(s"no output")) } } - def run(worker: Worker, job: Job)(implicit authContext: AuthContext): Future[Job] = { + def run(worker: Worker, job: Job)(implicit authContext: AuthContext): Future[Job] = prepareJobFolder(worker, job).flatMap { jobFolder ⇒ val executionContext = worker.tpe() match { case WorkerType.analyzer ⇒ analyzerExecutionContext @@ -205,15 +212,16 @@ class JobRunnerSrv @Inject() ( j ← runners .foldLeft[Option[Future[Unit]]](None) { case (None, "docker") ⇒ - worker.dockerImage() + worker + .dockerImage() .map(dockerImage ⇒ dockerJobRunnerSrv.run(jobFolder, dockerImage, job, worker.jobTimeout().map(_.minutes))(executionContext)) .orElse { logger.warn(s"worker ${worker.id} can't be run with docker (doesn't have image)") None } case (None, "process") ⇒ - - worker.command() + worker + .command() .map(command ⇒ processJobRunnerSrv.run(jobFolder, command, job, worker.jobTimeout().map(_.minutes))(executionContext)) .orElse { logger.warn(s"worker ${worker.id} can't be run with process (doesn't have image)") @@ -231,27 +239,31 @@ class JobRunnerSrv @Inject() ( .transformWith { r ⇒ r.fold( error ⇒ endJob(job, JobStatus.Failure, Option(error.getMessage), Some(readFile(jobFolder.resolve("input").resolve("input.json")))), - _ ⇒ extractReport(jobFolder, job)) + _ ⇒ extractReport(jobFolder, job) + ) } .andThen { case _ ⇒ delete(jobFolder) } } - } private def readFile(input: Path): String = new String(Files.readAllBytes(input), StandardCharsets.UTF_8) private def startJob(job: Job)(implicit authContext: AuthContext): Future[Job] = { - val fields = Fields.empty + val fields = Fields + .empty .set("status", JobStatus.InProgress.toString) .set("startDate", Json.toJson(new Date)) updateSrv(job, fields, ModifyConfig(retryOnConflict = 0)) } - private def endJob(job: Job, status: JobStatus.Type, errorMessage: Option[String] = None, input: Option[String] = None)(implicit authContext: AuthContext): Future[Job] = { - val fields = Fields.empty + private def endJob(job: Job, status: JobStatus.Type, errorMessage: Option[String] = None, input: Option[String] = None)( + implicit authContext: AuthContext + ): Future[Job] = { + val fields = Fields + .empty .set("status", status.toString) .set("endDate", Json.toJson(new Date)) .set("input", input.map(JsString.apply)) .set("message", errorMessage.map(JsString.apply)) updateSrv(job, fields, ModifyConfig.default) } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/services/JobSrv.scala b/app/org/thp/cortex/services/JobSrv.scala index 7d6074c5e..49ca1a275 100644 --- a/app/org/thp/cortex/services/JobSrv.scala +++ b/app/org/thp/cortex/services/JobSrv.scala @@ -3,18 +3,18 @@ package org.thp.cortex.services import java.util.Date import scala.concurrent.duration._ -import scala.concurrent.{ ExecutionContext, Future } -import scala.util.{ Failure, Success } +import scala.concurrent.{ExecutionContext, Future} +import scala.util.{Failure, Success} import play.api.libs.json._ -import play.api.{ Configuration, Logger } +import play.api.{Configuration, Logger} import akka.NotUsed import akka.stream.Materializer -import akka.stream.scaladsl.{ Sink, Source } -import javax.inject.{ Inject, Singleton } +import akka.stream.scaladsl.{Sink, Source} +import javax.inject.{Inject, Singleton} import org.scalactic.Accumulation._ -import org.scalactic.{ Bad, Good, One, Or } +import org.scalactic.{Bad, Good, One, Or} import org.thp.cortex.models._ import org.elastic4play._ @@ -36,7 +36,8 @@ class JobSrv( deleteSrv: DeleteSrv, attachmentSrv: AttachmentSrv, implicit val ec: ExecutionContext, - implicit val mat: Materializer) { + implicit val mat: Materializer +) { @Inject() def this( configuration: Configuration, @@ -51,20 +52,23 @@ class JobSrv( deleteSrv: DeleteSrv, attachmentSrv: AttachmentSrv, ec: ExecutionContext, - mat: Materializer) = this( - configuration.getOptional[Duration]("cache.job").getOrElse(Duration.Zero), - jobModel, - reportModel, - artifactModel, - workerSrv, - userSrv, - jobRunnerSrv, - createSrv, - findSrv, - deleteSrv, - attachmentSrv, - ec, - mat) + mat: Materializer + ) = + this( + configuration.getOptional[Duration]("cache.job").getOrElse(Duration.Zero), + jobModel, + reportModel, + artifactModel, + workerSrv, + userSrv, + jobRunnerSrv, + createSrv, + findSrv, + deleteSrv, + attachmentSrv, + ec, + mat + ) private lazy val logger = Logger(getClass) @@ -77,7 +81,7 @@ class JobSrv( ._1 .runForeach { job ⇒ (for { - worker ← workerSrv.get(job.workerId()) + worker ← workerSrv.get(job.workerId()) updatedJob ← jobRunnerSrv.run(worker, job) } yield updatedJob) .onComplete { @@ -89,38 +93,64 @@ class JobSrv( } private def withUserFilter[A](userId: String)(x: String ⇒ (Source[A, NotUsed], Future[Long])): (Source[A, NotUsed], Future[Long]) = { - val a = userSrv.getOrganizationId(userId).map(x) + val a = userSrv.getOrganizationId(userId).map(x) val aSource = Source.fromFutureSource(a.map(_._1)).mapMaterializedValue(_ ⇒ NotUsed) - val aTotal = a.flatMap(_._2) + val aTotal = a.flatMap(_._2) aSource → aTotal } - def listForUser(userId: String, dataTypeFilter: Option[String], dataFilter: Option[String], analyzerFilter: Option[String], range: Option[String]): (Source[Job, NotUsed], Future[Long]) = { + def listForUser( + userId: String, + dataTypeFilter: Option[String], + dataFilter: Option[String], + analyzerFilter: Option[String], + range: Option[String] + ): (Source[Job, NotUsed], Future[Long]) = { import org.elastic4play.services.QueryDSL._ - findForUser(userId, and( - dataTypeFilter.map("dataType" like _).toList ::: - dataFilter.map("data" like _).toList ::: - analyzerFilter.map(af ⇒ or("workerId" like af, "workerName" like af)).toList), range, Nil) + findForUser( + userId, + and( + dataTypeFilter.map("dataType" like _).toList ::: + dataFilter.map("data" like _).toList ::: + analyzerFilter.map(af ⇒ or("workerId" like af, "workerName" like af)).toList + ), + range, + Nil + ) } - def findArtifacts(userId: String, jobId: String, queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Artifact, NotUsed], Future[Long]) = { + def findArtifacts( + userId: String, + jobId: String, + queryDef: QueryDef, + range: Option[String], + sortBy: Seq[String] + ): (Source[Artifact, NotUsed], Future[Long]) = { import org.elastic4play.services.QueryDSL._ withUserFilter(userId) { organizationId ⇒ - findSrv[ArtifactModel, Artifact](artifactModel, and(queryDef, parent("report", parent("job", and(withId(jobId), "organization" ~= organizationId)))), range, sortBy) + findSrv[ArtifactModel, Artifact]( + artifactModel, + and(queryDef, parent("report", parent("job", and(withId(jobId), "organization" ~= organizationId)))), + range, + sortBy + ) } } - def find(queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Job, NotUsed], Future[Long]) = { + def find(queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Job, NotUsed], Future[Long]) = findSrv[JobModel, Job](jobModel, queryDef, range, sortBy) - } - def findForUser(userId: String, queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Job, NotUsed], Future[Long]) = { + def findForUser(userId: String, queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Job, NotUsed], Future[Long]) = withUserFilter(userId) { organizationId ⇒ findForOrganization(organizationId, queryDef, range, sortBy) } - } - def findForOrganization(organizationId: String, queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Job, NotUsed], Future[Long]) = { + def findForOrganization( + organizationId: String, + queryDef: QueryDef, + range: Option[String], + sortBy: Seq[String] + ): (Source[Job, NotUsed], Future[Long]) = { import org.elastic4play.services.QueryDSL._ find(and("organization" ~= organizationId, queryDef), range, sortBy) } @@ -131,8 +161,7 @@ class JobSrv( import org.elastic4play.services.QueryDSL._ withUserFilter(userId) { organizationId ⇒ findForOrganization(organizationId, withId(jobId), Some("0-1"), Nil) - } - ._1 + }._1 .runWith(Sink.headOption) .flatMap { case Some(j) ⇒ Future.successful(j) @@ -151,27 +180,26 @@ class JobSrv( case Some(iv) ⇒ Bad(One(InvalidFormatAttributeError("data", "string/attachment", iv))) case None ⇒ Bad(One(MissingAttributeError("data"))) } - val tlp = (attributes \ "tlp").asOpt[Long].getOrElse(2L) - val pap = (attributes \ "pap").asOpt[Long].getOrElse(2L) - val message = (attributes \ "message").asOpt[String].getOrElse("") + val tlp = (attributes \ "tlp").asOpt[Long].getOrElse(2L) + val pap = (attributes \ "pap").asOpt[Long].getOrElse(2L) + val message = (attributes \ "message").asOpt[String].getOrElse("") val parameters = (attributes \ "parameters").asOpt[JsObject].getOrElse(JsObject.empty) - val label = (attributes \ "label").asOpt[String] - val force = fields.getBoolean("force").getOrElse(false) + val label = (attributes \ "label").asOpt[String] + val force = fields.getBoolean("force").getOrElse(false) withGood(dataType, dataFiv) { case (dt, Right(fiv)) ⇒ dt → attachmentSrv.save(fiv).map(Right.apply) case (dt, Left(data)) ⇒ dt → Future.successful(Left(data)) - } - .fold( - typeDataAttachment ⇒ typeDataAttachment._2.flatMap( - da ⇒ create(worker, typeDataAttachment._1, da, tlp, pap, message, parameters, label, force)), - errors ⇒ { - val attributeError = AttributeCheckingError("job", errors) - logger.error("legacy job create fails", attributeError) - Future.failed(attributeError) - }) + }.fold( + typeDataAttachment ⇒ typeDataAttachment._2.flatMap(da ⇒ create(worker, typeDataAttachment._1, da, tlp, pap, message, parameters, label, force)), + errors ⇒ { + val attributeError = AttributeCheckingError("job", errors) + logger.error("legacy job create fails", attributeError) + Future.failed(attributeError) + } + ) } - def create(workerId: String, fields: Fields)(implicit authContext: AuthContext): Future[Job] = { + def create(workerId: String, fields: Fields)(implicit authContext: AuthContext): Future[Job] = workerSrv.getForUser(authContext.userId, workerId).flatMap { worker ⇒ /* In Cortex 1, fields looks like: @@ -214,25 +242,29 @@ class JobSrv( case (_, None, None) ⇒ Bad(One(MissingAttributeError("data/attachment"))) } - val tlp = fields.getLong("tlp").getOrElse(2L) - val pap = fields.getLong("pap").getOrElse(2L) + val tlp = fields.getLong("tlp").getOrElse(2L) + val pap = fields.getLong("pap").getOrElse(2L) val message = fields.getString("message").getOrElse("") - val force = fields.getBoolean("force").getOrElse(false) - val parameters = fields.getValue("parameters").collect { - case obj: JsObject ⇒ obj - } + val force = fields.getBoolean("force").getOrElse(false) + val parameters = fields + .getValue("parameters") + .collect { + case obj: JsObject ⇒ obj + } .getOrElse(JsObject.empty) withGood(dataType, dataFiv) { case (dt, Right(fiv)) ⇒ dt → attachmentSrv.save(fiv).map(Right.apply) case (dt, Left(data)) ⇒ dt → Future.successful(Left(data)) - } - .fold( - typeDataAttachment ⇒ typeDataAttachment._2.flatMap(da ⇒ create(worker, typeDataAttachment._1, da, tlp, pap, message, parameters, fields.getString("label"), force)), - errors ⇒ Future.failed(AttributeCheckingError("job", errors))) + }.fold( + typeDataAttachment ⇒ + typeDataAttachment + ._2 + .flatMap(da ⇒ create(worker, typeDataAttachment._1, da, tlp, pap, message, parameters, fields.getString("label"), force)), + errors ⇒ Future.failed(AttributeCheckingError("job", errors)) + ) } } - } def create( worker: Worker, @@ -243,48 +275,53 @@ class JobSrv( message: String, parameters: JsObject, label: Option[String], - force: Boolean)(implicit authContext: AuthContext): Future[Job] = { + force: Boolean + )(implicit authContext: AuthContext): Future[Job] = { val previousJob = findSimilarJob(worker, dataType, dataAttachment, tlp, parameters, force) previousJob.flatMap { case Right(job) ⇒ Future.successful(job) - case Left(cacheTag) ⇒ isUnderRateLimit(worker).flatMap { - case true ⇒ - val fields = Fields(Json.obj( - "workerDefinitionId" → worker.workerDefinitionId(), - "workerId" → worker.id, - "workerName" → worker.name(), - "organization" → worker.parentId, - "status" → JobStatus.Waiting, - "dataType" → dataType, - "tlp" → tlp, - "pap" → pap, - "message" → message, - "parameters" → parameters.toString, - "type" → worker.tpe(), - "cacheTag" → cacheTag)) - .set("label", label.map(JsString.apply)) - val fieldWithData = dataAttachment match { - case Left(data) ⇒ fields.set("data", data) - case Right(attachment) ⇒ fields.set("attachment", AttachmentInputValue(attachment)) - } - createSrv[JobModel, Job](jobModel, fieldWithData).andThen { - case Success(job) ⇒ - jobRunnerSrv.run(worker, job) - .onComplete { - case Success(j) ⇒ logger.info(s"Job ${job.id} has finished with status ${j.status()}") - case Failure(e) ⇒ logger.error(s"Job ${job.id} has failed", e) - } - } - case false ⇒ - Future.failed(RateLimitExceeded(worker)) + case Left(cacheTag) ⇒ + isUnderRateLimit(worker).flatMap { + case true ⇒ + val fields = Fields( + Json.obj( + "workerDefinitionId" → worker.workerDefinitionId(), + "workerId" → worker.id, + "workerName" → worker.name(), + "organization" → worker.parentId, + "status" → JobStatus.Waiting, + "dataType" → dataType, + "tlp" → tlp, + "pap" → pap, + "message" → message, + "parameters" → parameters.toString, + "type" → worker.tpe(), + "cacheTag" → cacheTag + ) + ).set("label", label.map(JsString.apply)) + val fieldWithData = dataAttachment match { + case Left(data) ⇒ fields.set("data", data) + case Right(attachment) ⇒ fields.set("attachment", AttachmentInputValue(attachment)) + } + createSrv[JobModel, Job](jobModel, fieldWithData).andThen { + case Success(job) ⇒ + jobRunnerSrv + .run(worker, job) + .onComplete { + case Success(j) ⇒ logger.info(s"Job ${job.id} has finished with status ${j.status()}") + case Failure(e) ⇒ logger.error(s"Job ${job.id} has failed", e) + } + } + case false ⇒ + Future.failed(RateLimitExceeded(worker)) - } + } } } - private def isUnderRateLimit(worker: Worker): Future[Boolean] = { + private def isUnderRateLimit(worker: Worker): Future[Boolean] = (for { - rate ← worker.rate() + rate ← worker.rate() rateUnit ← worker.rateUnit() } yield { import org.elastic4play.services.QueryDSL._ @@ -295,28 +332,36 @@ class JobSrv( logger.info(s"$count analysis found (limit is $rate)") count < rate } - }) - .getOrElse(Future.successful(true)) - } + }).getOrElse(Future.successful(true)) - def findSimilarJob(worker: Worker, dataType: String, dataAttachment: Either[String, Attachment], tlp: Long, parameters: JsObject, force: Boolean): Future[Either[String, Job]] = { - val cacheTag = Hasher("MD5").fromString(s"${worker.id}|$dataType|$tlp|${dataAttachment.fold(data ⇒ data, attachment ⇒ attachment.id)}|$parameters").head.toString() + def findSimilarJob( + worker: Worker, + dataType: String, + dataAttachment: Either[String, Attachment], + tlp: Long, + parameters: JsObject, + force: Boolean + ): Future[Either[String, Job]] = { + val cacheTag = Hasher("MD5") + .fromString(s"${worker.id}|$dataType|$tlp|${dataAttachment.fold(data ⇒ data, attachment ⇒ attachment.id)}|$parameters") + .head + .toString() lazy val cache = worker.jobCache().fold(jobCache)(_.minutes) if (force || cache.length == 0 || worker.tpe() == WorkerType.responder) { logger.info("Job cache is disabled") Future.successful(Left(cacheTag)) - } - else { + } else { import org.elastic4play.services.QueryDSL._ - logger.info(s"Looking for similar job in the last ${cache.toMinutes} minutes (worker=${worker.id}, dataType=$dataType, data=$dataAttachment, tlp=$tlp, parameters=$parameters)") + logger.info( + s"Looking for similar job in the last ${cache.toMinutes} minutes (worker=${worker.id}, dataType=$dataType, data=$dataAttachment, tlp=$tlp, parameters=$parameters)" + ) val now = new Date().getTime - find(and( - "cacheTag" ~= cacheTag, - "status" ~!= JobStatus.Failure, - "status" ~!= JobStatus.Deleted, - "startDate" ~>= (now - cache.toMillis)), Some("0-1"), Seq("-createdAt")) - ._1 + find( + and("cacheTag" ~= cacheTag, "status" ~!= JobStatus.Failure, "status" ~!= JobStatus.Deleted, "startDate" ~>= (now - cache.toMillis)), + Some("0-1"), + Seq("-createdAt") + )._1 .map(j ⇒ new Job(jobModel, j.attributes + ("fromCache" → JsBoolean(true)))) .runWith(Sink.headOption) .map(_.toRight(cacheTag)) @@ -327,8 +372,9 @@ class JobSrv( def getReport(job: Job): Future[Report] = { import org.elastic4play.services.QueryDSL._ - findSrv[ReportModel, Report](reportModel, withParent(job), Some("0-1"), Nil)._1 + findSrv[ReportModel, Report](reportModel, withParent(job), Some("0-1"), Nil) + ._1 .runWith(Sink.headOption) .map(_.getOrElse(throw NotFoundError(s"Job ${job.id} has no report"))) } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/services/KeyAuthSrv.scala b/app/org/thp/cortex/services/KeyAuthSrv.scala index 3114e17ec..4a6ce0c9d 100644 --- a/app/org/thp/cortex/services/KeyAuthSrv.scala +++ b/app/org/thp/cortex/services/KeyAuthSrv.scala @@ -1,9 +1,9 @@ package org.thp.cortex.services import java.util.Base64 -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import scala.util.Random import play.api.libs.json.JsArray @@ -13,17 +13,14 @@ import akka.stream.Materializer import akka.stream.scaladsl.Sink import org.elastic4play.controllers.Fields -import org.elastic4play.services.{ AuthCapability, AuthContext, AuthSrv } -import org.elastic4play.{ AuthenticationError, BadRequestError } +import org.elastic4play.services.{AuthCapability, AuthContext, AuthSrv} +import org.elastic4play.{AuthenticationError, BadRequestError} @Singleton -class KeyAuthSrv @Inject() ( - userSrv: UserSrv, - implicit val ec: ExecutionContext, - implicit val mat: Materializer) extends AuthSrv { +class KeyAuthSrv @Inject()(userSrv: UserSrv, implicit val ec: ExecutionContext, implicit val mat: Materializer) extends AuthSrv { override val name = "key" - protected final def generateKey(): String = { + final protected def generateKey(): String = { val bytes = Array.ofDim[Byte](24) Random.nextBytes(bytes) Base64.getEncoder.encodeToString(bytes) @@ -34,7 +31,8 @@ class KeyAuthSrv @Inject() ( override def authenticate(key: String)(implicit request: RequestHeader): Future[AuthContext] = { import org.elastic4play.services.QueryDSL._ // key attribute is sensitive so it is not possible to search on that field - userSrv.find("status" ~= "Ok", Some("all"), Nil) + userSrv + .find("status" ~= "Ok", Some("all"), Nil) ._1 .filter(_.key().contains(key)) .runWith(Sink.headOption) @@ -49,11 +47,9 @@ class KeyAuthSrv @Inject() ( userSrv.update(username, Fields.empty.set("key", newKey)).map(_ ⇒ newKey) } - override def getKey(username: String)(implicit authContext: AuthContext): Future[String] = { + override def getKey(username: String)(implicit authContext: AuthContext): Future[String] = userSrv.get(username).map(_.key().getOrElse(throw BadRequestError(s"User $username hasn't key"))) - } - override def removeKey(username: String)(implicit authContext: AuthContext): Future[Unit] = { + override def removeKey(username: String)(implicit authContext: AuthContext): Future[Unit] = userSrv.update(username, Fields.empty.set("key", JsArray())).map(_ ⇒ ()) - } } diff --git a/app/org/thp/cortex/services/LocalAuthSrv.scala b/app/org/thp/cortex/services/LocalAuthSrv.scala index 9a7c4d9bc..d1b19a7f5 100644 --- a/app/org/thp/cortex/services/LocalAuthSrv.scala +++ b/app/org/thp/cortex/services/LocalAuthSrv.scala @@ -1,8 +1,8 @@ package org.thp.cortex.services -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import scala.util.Random import play.api.mvc.RequestHeader @@ -11,45 +11,39 @@ import akka.stream.Materializer import org.thp.cortex.models.User import org.elastic4play.controllers.Fields -import org.elastic4play.services.{ AuthCapability, AuthContext, AuthSrv } +import org.elastic4play.services.{AuthCapability, AuthContext, AuthSrv} import org.elastic4play.utils.Hasher -import org.elastic4play.{ AuthenticationError, AuthorizationError } +import org.elastic4play.{AuthenticationError, AuthorizationError} @Singleton -class LocalAuthSrv @Inject() ( - userSrv: UserSrv, - implicit val ec: ExecutionContext, - implicit val mat: Materializer) extends AuthSrv { +class LocalAuthSrv @Inject()(userSrv: UserSrv, implicit val ec: ExecutionContext, implicit val mat: Materializer) extends AuthSrv { - val name = "local" + val name = "local" override val capabilities = Set(AuthCapability.changePassword, AuthCapability.setPassword) - private[services] def doAuthenticate(user: User, password: String): Boolean = { + private[services] def doAuthenticate(user: User, password: String): Boolean = user.password().map(_.split(",", 2)).fold(false) { case Array(seed, pwd) ⇒ val hash = Hasher("SHA-256").fromString(seed + password).head.toString hash == pwd case _ ⇒ false } - } - override def authenticate(username: String, password: String)(implicit request: RequestHeader): Future[AuthContext] = { + override def authenticate(username: String, password: String)(implicit request: RequestHeader): Future[AuthContext] = userSrv.get(username).flatMap { user ⇒ if (doAuthenticate(user, password)) userSrv.getFromUser(request, user, name) else Future.failed(AuthenticationError("Authentication failure")) } - } - override def changePassword(username: String, oldPassword: String, newPassword: String)(implicit authContext: AuthContext): Future[Unit] = { + override def changePassword(username: String, oldPassword: String, newPassword: String)(implicit authContext: AuthContext): Future[Unit] = userSrv.get(username).flatMap { user ⇒ if (doAuthenticate(user, oldPassword)) setPassword(username, newPassword) else Future.failed(AuthorizationError("Authentication failure")) } - } override def setPassword(username: String, newPassword: String)(implicit authContext: AuthContext): Future[Unit] = { - val seed = Random.nextString(10).replace(',', '!') + val seed = Random.nextString(10).replace(',', '!') val newHash = seed + "," + Hasher("SHA-256").fromString(seed + newPassword).head.toString userSrv.update(username, Fields.empty.set("password", newHash)).map(_ ⇒ ()) } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/services/MispSrv.scala b/app/org/thp/cortex/services/MispSrv.scala index b0b170a06..1f33ac5d6 100644 --- a/app/org/thp/cortex/services/MispSrv.scala +++ b/app/org/thp/cortex/services/MispSrv.scala @@ -1,18 +1,18 @@ package org.thp.cortex.services import scala.concurrent.duration._ -import scala.concurrent.{ Await, ExecutionContext, Future } +import scala.concurrent.{Await, ExecutionContext, Future} import play.api.Logger -import play.api.libs.json.{ Json, _ } +import play.api.libs.json.{Json, _} import akka.NotUsed import akka.actor.ActorRef import akka.pattern.ask import akka.stream.Materializer -import akka.stream.scaladsl.{ Sink, Source } +import akka.stream.scaladsl.{Sink, Source} import akka.util.Timeout -import javax.inject.{ Inject, Named, Singleton } +import javax.inject.{Inject, Named, Singleton} import org.apache.commons.codec.binary.Base64 import org.thp.cortex.models._ import org.thp.cortex.services.AuditActor.Register @@ -21,13 +21,14 @@ import org.elastic4play.NotFoundError import org.elastic4play.services._ @Singleton -class MispSrv @Inject() ( +class MispSrv @Inject()( workerSrv: WorkerSrv, attachmentSrv: AttachmentSrv, jobSrv: JobSrv, @Named("audit") auditActor: ActorRef, implicit val ec: ExecutionContext, - implicit val mat: Materializer) { + implicit val mat: Materializer +) { private[MispSrv] lazy val logger = Logger(getClass) @@ -37,17 +38,17 @@ class MispSrv @Inject() ( val mispAnalyzers = analyzers .map { analyzer ⇒ Json.obj( - "name" → analyzer.name(), - "type" → "cortex", - "mispattributes" → Json.obj( - "input" → analyzer.dataTypeList().flatMap(dataType2mispType).distinct, - "output" → Json.arr()), + "name" → analyzer.name(), + "type" → "cortex", + "mispattributes" → Json.obj("input" → analyzer.dataTypeList().flatMap(dataType2mispType).distinct, "output" → Json.arr()), "meta" → Json.obj( "module-type" → Json.arr("cortex"), "description" → analyzer.description(), - "author" → analyzer.author(), - "version" → analyzer.vers(), - "config" → Json.arr())) + "author" → analyzer.author(), + "version" → analyzer.vers(), + "config" → Json.arr() + ) + ) } mispAnalyzers → analyzerCount } @@ -56,32 +57,33 @@ class MispSrv @Inject() ( import org.elastic4play.services.QueryDSL._ val artifact: Either[String, Attachment] = toArtifact(mispType, data) - val duration = 20.minutes // TODO configurable + val duration = 20.minutes // TODO configurable for { analyzer ← workerSrv.findAnalyzersForUser(authContext.userId, "name" ~= module, Some("0-1"), Nil)._1.runWith(Sink.headOption) - job ← analyzer.map(jobSrv.create(_, mispType2dataType(mispType), artifact, 0, 0, "", JsObject.empty, None, force = false)) + job ← analyzer + .map(jobSrv.create(_, mispType2dataType(mispType), artifact, 0, 0, "", JsObject.empty, None, force = false)) .getOrElse(Future.failed(NotFoundError(s"Module $module not found"))) - _ ← auditActor.ask(Register(job.id, duration))(Timeout(duration)) + _ ← auditActor.ask(Register(job.id, duration))(Timeout(duration)) updatedJob ← jobSrv.getForUser(authContext.userId, job.id) mispOutput ← toMispOutput(authContext.userId, updatedJob) } yield mispOutput } - private def toMispOutput(userId: String, job: Job): Future[JsObject] = { + private def toMispOutput(userId: String, job: Job): Future[JsObject] = job.status() match { case JobStatus.Success ⇒ for { report ← jobSrv.getReport(job) - artifacts ← jobSrv.findArtifacts(userId, job.id, QueryDSL.any, Some("all"), Nil)._1 - .map { artifact ⇒ toMispOutput(artifact) } + artifacts ← jobSrv + .findArtifacts(userId, job.id, QueryDSL.any, Some("all"), Nil) + ._1 + .map { artifact ⇒ + toMispOutput(artifact) + } .runWith(Sink.seq) - reportJson = Json.obj( - "full" → report.full(), - "summary" → report.summary()) - cortexAttribute = Json.obj( - "types" → Json.arr("cortex"), - "values" → Json.arr(reportJson.toString)) + reportJson = Json.obj("full" → report.full(), "summary" → report.summary()) + cortexAttribute = Json.obj("types" → Json.arr("cortex"), "values" → Json.arr(reportJson.toString)) } yield Json.obj("results" → (artifacts :+ cortexAttribute)) case JobStatus.Waiting ⇒ Future.successful(Json.obj("error" → "This job hasn't finished yet")) case JobStatus.Deleted ⇒ Future.successful(Json.obj("error" → "This job has been deleted")) @@ -90,35 +92,34 @@ class MispSrv @Inject() ( Future.successful(Json.obj("error" → message)) case JobStatus.InProgress ⇒ Future.successful(Json.obj("error" → "This job hasn't finished yet")) } - } - private def toArtifact(mispType: String, data: String): Either[String, Attachment] = { + private def toArtifact(mispType: String, data: String): Either[String, Attachment] = mispType2dataType(mispType) match { case "file" if mispType == "malware-sample" ⇒ ??? // TODO case "file" ⇒ - val FAttachment = attachmentSrv.save("noname", "application/octet-stream", Base64.decodeBase64(data)).map { a ⇒ a } + val FAttachment = attachmentSrv.save("noname", "application/octet-stream", Base64.decodeBase64(data)).map { a ⇒ + a + } Right(Await.result(FAttachment, 10.seconds)) case _ ⇒ Left(data) } - } - private def toMispOutput(artifact: Artifact): JsObject = { + private def toMispOutput(artifact: Artifact): JsObject = (artifact.data(), artifact.attachment()) match { - case (Some(data), None) ⇒ Json.obj( - "types" → dataType2mispType(artifact.dataType()), - "values" → Json.arr(data)) + case (Some(data), None) ⇒ Json.obj("types" → dataType2mispType(artifact.dataType()), "values" → Json.arr(data)) //case (None, Some(_)) ⇒ ??? case _ ⇒ ??? } - } - private def mispType2dataType(mispType: String): String = typeLookup.getOrElse(mispType, { - logger.warn(s"Misp type $mispType not recognized") - "other" - }) + private def mispType2dataType(mispType: String): String = + typeLookup.getOrElse(mispType, { + logger.warn(s"Misp type $mispType not recognized") + "other" + }) private def dataType2mispType(dataType: String): Seq[String] = { - val mispTypes = typeLookup.filter(_._2 == dataType) + val mispTypes = typeLookup + .filter(_._2 == dataType) .keys .toSeq .distinct @@ -126,145 +127,145 @@ class MispSrv @Inject() ( if (mispTypes.isEmpty) { logger.warn(s"Data type $dataType not recognized") Seq("other") - } - else mispTypes + } else mispTypes } private val typeLookup = Map( - "md5" → "hash", - "sha1" → "hash", - "sha256" → "hash", - "filename" → "filename", - "pdb" → "other", - "filename|md5" → "other", - "filename|sha1" → "other", - "filename|sha256" → "other", - "ip-src" → "ip", - "ip-dst" → "ip", - "hostname" → "fqdn", - "domain" → "domain", - "domain|ip" → "other", - "email-src" → "mail", - "email-dst" → "mail", - "email-subject" → "mail_subject", - "email-attachment" → "other", - "float" → "other", - "url" → "url", - "http-method" → "other", - "user-agent" → "user-agent", - "regkey" → "registry", - "regkey|value" → "registry", - "AS" → "other", - "snort" → "other", - "pattern-in-file" → "other", - "pattern-in-traffic" → "other", - "pattern-in-memory" → "other", - "yara" → "other", - "sigma" → "other", - "vulnerability" → "other", - "attachment" → "file", - "malware-sample" → "file", - "link" → "other", - "comment" → "other", - "text" → "other", - "hex" → "other", - "other" → "other", - "named" → "other", - "mutex" → "other", - "target-user" → "other", - "target-email" → "mail", - "target-machine" → "fqdn", - "target-org" → "other", - "target-location" → "other", - "target-external" → "other", - "btc" → "other", - "iban" → "other", - "bic" → "other", - "bank-account-nr" → "other", - "aba-rtn" → "other", - "bin" → "other", - "cc-number" → "other", - "prtn" → "other", - "threat-actor" → "other", - "campaign-name" → "other", - "campaign-id" → "other", - "malware-type" → "other", - "uri" → "uri_path", - "authentihash" → "other", - "ssdeep" → "hash", - "imphash" → "hash", - "pehash" → "hash", - "impfuzzy" → "hash", - "sha224" → "hash", - "sha384" → "hash", - "sha512" → "hash", - "sha512/224" → "hash", - "sha512/256" → "hash", - "tlsh" → "other", - "filename|authentihash" → "other", - "filename|ssdeep" → "other", - "filename|imphash" → "other", - "filename|impfuzzy" → "other", - "filename|pehash" → "other", - "filename|sha224" → "other", - "filename|sha384" → "other", - "filename|sha512" → "other", - "filename|sha512/224" → "other", - "filename|sha512/256" → "other", - "filename|tlsh" → "other", - "windows-scheduled-task" → "other", - "windows-service-name" → "other", - "windows-service-displayname" → "other", - "whois-registrant-email" → "mail", - "whois-registrant-phone" → "other", - "whois-registrant-name" → "other", - "whois-registrar" → "other", - "whois-creation-date" → "other", - "x509-fingerprint-sha1" → "other", - "dns-soa-email" → "other", - "size-in-bytes" → "other", - "counter" → "other", - "datetime" → "other", - "cpe" → "other", - "port" → "other", - "ip-dst|port" → "other", - "ip-src|port" → "other", - "hostname|port" → "other", - "email-dst-display-name" → "other", - "email-src-display-name" → "other", - "email-header" → "other", - "email-reply-to" → "other", - "email-x-mailer" → "other", - "email-mime-boundary" → "other", - "email-thread-index" → "other", - "email-message-id" → "other", - "github-username" → "other", - "github-repository" → "other", - "github-organisation" → "other", - "jabber-id" → "other", - "twitter-id" → "other", - "first-name" → "other", - "middle-name" → "other", - "last-name" → "other", - "date-of-birth" → "other", - "place-of-birth" → "other", - "gender" → "other", - "passport-number" → "other", - "passport-country" → "other", - "passport-expiration" → "other", - "redress-number" → "other", - "nationality" → "other", - "visa-number" → "other", - "issue-date-of-the-visa" → "other", - "primary-residence" → "other", - "country-of-residence" → "other", - "special-service-request" → "other", - "frequent-flyer-number" → "other", - "travel-details" → "other", - "payment-details" → "other", - "place-port-of-original-embarkation" → "other", - "place-port-of-clearance" → "other", + "md5" → "hash", + "sha1" → "hash", + "sha256" → "hash", + "filename" → "filename", + "pdb" → "other", + "filename|md5" → "other", + "filename|sha1" → "other", + "filename|sha256" → "other", + "ip-src" → "ip", + "ip-dst" → "ip", + "hostname" → "fqdn", + "domain" → "domain", + "domain|ip" → "other", + "email-src" → "mail", + "email-dst" → "mail", + "email-subject" → "mail_subject", + "email-attachment" → "other", + "float" → "other", + "url" → "url", + "http-method" → "other", + "user-agent" → "user-agent", + "regkey" → "registry", + "regkey|value" → "registry", + "AS" → "other", + "snort" → "other", + "pattern-in-file" → "other", + "pattern-in-traffic" → "other", + "pattern-in-memory" → "other", + "yara" → "other", + "sigma" → "other", + "vulnerability" → "other", + "attachment" → "file", + "malware-sample" → "file", + "link" → "other", + "comment" → "other", + "text" → "other", + "hex" → "other", + "other" → "other", + "named" → "other", + "mutex" → "other", + "target-user" → "other", + "target-email" → "mail", + "target-machine" → "fqdn", + "target-org" → "other", + "target-location" → "other", + "target-external" → "other", + "btc" → "other", + "iban" → "other", + "bic" → "other", + "bank-account-nr" → "other", + "aba-rtn" → "other", + "bin" → "other", + "cc-number" → "other", + "prtn" → "other", + "threat-actor" → "other", + "campaign-name" → "other", + "campaign-id" → "other", + "malware-type" → "other", + "uri" → "uri_path", + "authentihash" → "other", + "ssdeep" → "hash", + "imphash" → "hash", + "pehash" → "hash", + "impfuzzy" → "hash", + "sha224" → "hash", + "sha384" → "hash", + "sha512" → "hash", + "sha512/224" → "hash", + "sha512/256" → "hash", + "tlsh" → "other", + "filename|authentihash" → "other", + "filename|ssdeep" → "other", + "filename|imphash" → "other", + "filename|impfuzzy" → "other", + "filename|pehash" → "other", + "filename|sha224" → "other", + "filename|sha384" → "other", + "filename|sha512" → "other", + "filename|sha512/224" → "other", + "filename|sha512/256" → "other", + "filename|tlsh" → "other", + "windows-scheduled-task" → "other", + "windows-service-name" → "other", + "windows-service-displayname" → "other", + "whois-registrant-email" → "mail", + "whois-registrant-phone" → "other", + "whois-registrant-name" → "other", + "whois-registrar" → "other", + "whois-creation-date" → "other", + "x509-fingerprint-sha1" → "other", + "dns-soa-email" → "other", + "size-in-bytes" → "other", + "counter" → "other", + "datetime" → "other", + "cpe" → "other", + "port" → "other", + "ip-dst|port" → "other", + "ip-src|port" → "other", + "hostname|port" → "other", + "email-dst-display-name" → "other", + "email-src-display-name" → "other", + "email-header" → "other", + "email-reply-to" → "other", + "email-x-mailer" → "other", + "email-mime-boundary" → "other", + "email-thread-index" → "other", + "email-message-id" → "other", + "github-username" → "other", + "github-repository" → "other", + "github-organisation" → "other", + "jabber-id" → "other", + "twitter-id" → "other", + "first-name" → "other", + "middle-name" → "other", + "last-name" → "other", + "date-of-birth" → "other", + "place-of-birth" → "other", + "gender" → "other", + "passport-number" → "other", + "passport-country" → "other", + "passport-expiration" → "other", + "redress-number" → "other", + "nationality" → "other", + "visa-number" → "other", + "issue-date-of-the-visa" → "other", + "primary-residence" → "other", + "country-of-residence" → "other", + "special-service-request" → "other", + "frequent-flyer-number" → "other", + "travel-details" → "other", + "payment-details" → "other", + "place-port-of-original-embarkation" → "other", + "place-port-of-clearance" → "other", "place-port-of-onward-foreign-destination" → "other", - "passenger-name-record-locator-number" → "other", - "mobile-application-id" → "other") -} \ No newline at end of file + "passenger-name-record-locator-number" → "other", + "mobile-application-id" → "other" + ) +} diff --git a/app/org/thp/cortex/services/OAuth2Srv.scala b/app/org/thp/cortex/services/OAuth2Srv.scala index a8f7be1c1..62099d471 100644 --- a/app/org/thp/cortex/services/OAuth2Srv.scala +++ b/app/org/thp/cortex/services/OAuth2Srv.scala @@ -1,19 +1,19 @@ package org.thp.cortex.services -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import play.api.http.Status -import play.api.libs.json.{ JsObject, JsValue } +import play.api.libs.json.{JsObject, JsValue} import play.api.libs.ws.WSClient import play.api.mvc.RequestHeader -import play.api.{ Configuration, Logger } +import play.api.{Configuration, Logger} import akka.stream.Materializer -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import org.thp.cortex.services.mappers.UserMapper -import org.elastic4play.services.{ AuthContext, AuthSrv } -import org.elastic4play.{ AuthenticationError, AuthorizationError, OAuth2Redirect } +import org.elastic4play.services.{AuthContext, AuthSrv} +import org.elastic4play.{AuthenticationError, AuthorizationError, OAuth2Redirect} case class OAuth2Config( clientId: String, @@ -25,23 +25,24 @@ case class OAuth2Config( tokenUrl: String, userUrl: String, scope: String, - autocreate: Boolean) + autocreate: Boolean +) object OAuth2Config { - def apply(configuration: Configuration): Option[OAuth2Config] = { + + def apply(configuration: Configuration): Option[OAuth2Config] = for { - clientId ← configuration.getOptional[String]("auth.oauth2.clientId") - clientSecret ← configuration.getOptional[String]("auth.oauth2.clientSecret") - redirectUri ← configuration.getOptional[String]("auth.oauth2.redirectUri") - responseType ← configuration.getOptional[String]("auth.oauth2.responseType") - grantType ← configuration.getOptional[String]("auth.oauth2.grantType") + clientId ← configuration.getOptional[String]("auth.oauth2.clientId") + clientSecret ← configuration.getOptional[String]("auth.oauth2.clientSecret") + redirectUri ← configuration.getOptional[String]("auth.oauth2.redirectUri") + responseType ← configuration.getOptional[String]("auth.oauth2.responseType") + grantType ← configuration.getOptional[String]("auth.oauth2.grantType") authorizationUrl ← configuration.getOptional[String]("auth.oauth2.authorizationUrl") - userUrl ← configuration.getOptional[String]("auth.oauth2.userUrl") - tokenUrl ← configuration.getOptional[String]("auth.oauth2.tokenUrl") - scope ← configuration.getOptional[String]("auth.oauth2.scope") + userUrl ← configuration.getOptional[String]("auth.oauth2.userUrl") + tokenUrl ← configuration.getOptional[String]("auth.oauth2.tokenUrl") + scope ← configuration.getOptional[String]("auth.oauth2.scope") autocreate = configuration.getOptional[Boolean]("auth.sso.autocreate").getOrElse(false) } yield OAuth2Config(clientId, clientSecret, redirectUri, responseType, grantType, authorizationUrl, tokenUrl, userUrl, scope, autocreate) - } } @Singleton @@ -51,42 +52,30 @@ class OAuth2Srv( ssoMapper: UserMapper, oauth2Config: Option[OAuth2Config], implicit val ec: ExecutionContext, - implicit val mat: Materializer) - extends AuthSrv { - - @Inject() def this( - ws: WSClient, - ssoMapper: UserMapper, - userSrv: UserSrv, - configuration: Configuration, - ec: ExecutionContext, - mat: Materializer) = this( - ws, - userSrv, - ssoMapper, - OAuth2Config(configuration), - ec, - mat) + implicit val mat: Materializer +) extends AuthSrv { + + @Inject() def this(ws: WSClient, ssoMapper: UserMapper, userSrv: UserSrv, configuration: Configuration, ec: ExecutionContext, mat: Materializer) = + this(ws, userSrv, ssoMapper, OAuth2Config(configuration), ec, mat) override val name: String = "oauth2" - private val logger = Logger(getClass) + private val logger = Logger(getClass) val Oauth2TokenQueryString = "code" - private def withOAuth2Config[A](body: OAuth2Config ⇒ Future[A]): Future[A] = { + private def withOAuth2Config[A](body: OAuth2Config ⇒ Future[A]): Future[A] = oauth2Config.fold[Future[A]](Future.failed(AuthenticationError("OAuth2 not configured properly")))(body) - } - override def authenticate()(implicit request: RequestHeader): Future[AuthContext] = { + override def authenticate()(implicit request: RequestHeader): Future[AuthContext] = withOAuth2Config { cfg ⇒ - request.queryString + request + .queryString .get(Oauth2TokenQueryString) .flatMap(_.headOption) .fold(createOauth2Redirect(cfg.clientId)) { code ⇒ getAuthTokenAndAuthenticate(cfg.clientId, code) } } - } private def getAuthTokenAndAuthenticate(clientId: String, code: String)(implicit request: RequestHeader): Future[AuthContext] = { logger.debug("Getting user token with the code from the response!") @@ -94,12 +83,15 @@ class OAuth2Srv( val acceptHeader = "Accept" → cfg.responseType ws.url(cfg.tokenUrl) .addHttpHeaders(acceptHeader) - .post(Map( - "code" → code, - "grant_type" → cfg.grantType, - "client_secret" → cfg.clientSecret, - "redirect_uri" → cfg.redirectUri, - "client_id" → clientId)) + .post( + Map( + "code" → code, + "grant_type" → cfg.grantType, + "client_secret" → cfg.clientSecret, + "redirect_uri" → cfg.redirectUri, + "client_id" → clientId + ) + ) .recoverWith { case error ⇒ logger.error(s"Token verification failure", error) @@ -109,14 +101,14 @@ class OAuth2Srv( r.status match { case Status.OK ⇒ val accessToken = (r.json \ "access_token").asOpt[String].getOrElse("") - val authHeader = "Authorization" → s"bearer $accessToken" + val authHeader = "Authorization" → s"bearer $accessToken" ws.url(cfg.userUrl) .addHttpHeaders(authHeader) - .get().flatMap { userResponse ⇒ + .get() + .flatMap { userResponse ⇒ if (userResponse.status != Status.OK) { Future.failed(AuthenticationError(s"unexpected response from server: ${userResponse.status} ${userResponse.body}")) - } - else { + } else { val response = userResponse.json.asInstanceOf[JsObject] getOrCreateUser(response, authHeader) } @@ -129,35 +121,37 @@ class OAuth2Srv( } } - private def getOrCreateUser(response: JsValue, authHeader: (String, String))(implicit request: RequestHeader): Future[AuthContext] = { + private def getOrCreateUser(response: JsValue, authHeader: (String, String))(implicit request: RequestHeader): Future[AuthContext] = withOAuth2Config { cfg ⇒ - ssoMapper.getUserFields(response, Some(authHeader)).flatMap { - userFields ⇒ - val userId = userFields.getString("login").getOrElse("") - userSrv.get(userId).flatMap(user ⇒ { + ssoMapper.getUserFields(response, Some(authHeader)).flatMap { userFields ⇒ + val userId = userFields.getString("login").getOrElse("") + userSrv + .get(userId) + .flatMap(user ⇒ { userSrv.getFromUser(request, user, name) - }).recoverWith { + }) + .recoverWith { case authErr: AuthorizationError ⇒ Future.failed(authErr) case _ if cfg.autocreate ⇒ userSrv.inInitAuthContext { implicit authContext ⇒ - userSrv.create(userFields).flatMap(user ⇒ { - userSrv.getFromUser(request, user, name) - }) + userSrv + .create(userFields) + .flatMap(user ⇒ { + userSrv.getFromUser(request, user, name) + }) } } } } - } - private def createOauth2Redirect(clientId: String): Future[AuthContext] = { + private def createOauth2Redirect(clientId: String): Future[AuthContext] = withOAuth2Config { cfg ⇒ val queryStringParams = Map[String, Seq[String]]( - "scope" → Seq(cfg.scope), + "scope" → Seq(cfg.scope), "response_type" → Seq(cfg.responseType), - "redirect_uri" → Seq(cfg.redirectUri), - "client_id" → Seq(clientId)) + "redirect_uri" → Seq(cfg.redirectUri), + "client_id" → Seq(clientId) + ) Future.failed(OAuth2Redirect(cfg.authorizationUrl, queryStringParams)) } - } } - diff --git a/app/org/thp/cortex/services/OrganizationSrv.scala b/app/org/thp/cortex/services/OrganizationSrv.scala index a972df085..c0a62bdfe 100644 --- a/app/org/thp/cortex/services/OrganizationSrv.scala +++ b/app/org/thp/cortex/services/OrganizationSrv.scala @@ -1,6 +1,6 @@ package org.thp.cortex.services -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import scala.concurrent.Future import scala.concurrent.duration.Duration @@ -11,7 +11,7 @@ import play.api.libs.json.JsObject import akka.NotUsed import akka.stream.scaladsl.Source -import org.thp.cortex.models.{ Organization, OrganizationModel } +import org.thp.cortex.models.{Organization, OrganizationModel} import org.elastic4play.controllers.Fields import org.elastic4play.database.ModifyConfig @@ -26,7 +26,8 @@ class OrganizationSrv( findSrv: FindSrv, deleteSrv: DeleteSrv, createSrv: CreateSrv, - cache: AsyncCacheApi) { + cache: AsyncCacheApi +) { @Inject() def this( config: Configuration, @@ -36,19 +37,11 @@ class OrganizationSrv( findSrv: FindSrv, deleteSrv: DeleteSrv, createSrv: CreateSrv, - cache: AsyncCacheApi) = this( - config.get[Duration]("cache.organization"), - organizationModel, - getSrv, - updateSrv, - findSrv, - deleteSrv, - createSrv, - cache) - - def create(fields: Fields)(implicit authContext: AuthContext): Future[Organization] = { + cache: AsyncCacheApi + ) = this(config.get[Duration]("cache.organization"), organizationModel, getSrv, updateSrv, findSrv, deleteSrv, createSrv, cache) + + def create(fields: Fields)(implicit authContext: AuthContext): Future[Organization] = createSrv[OrganizationModel, Organization](organizationModel, fields) - } def get(orgId: String): Future[Organization] = cache.getOrElseUpdate(s"org-$orgId", cacheExpiration) { getSrv[OrganizationModel, Organization](organizationModel, orgId) @@ -75,9 +68,8 @@ class OrganizationSrv( deleteSrv[OrganizationModel, Organization](organizationModel, orgId) } - def find(queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Organization, NotUsed], Future[Long]) = { + def find(queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Organization, NotUsed], Future[Long]) = findSrv[OrganizationModel, Organization](organizationModel, queryDef, range, sortBy) - } def stats(queryDef: QueryDef, aggs: Seq[Agg]): Future[JsObject] = findSrv(organizationModel, queryDef, aggs: _*) } diff --git a/app/org/thp/cortex/services/ProcessJobRunnerSrv.scala b/app/org/thp/cortex/services/ProcessJobRunnerSrv.scala index ff4edbc71..976e5abce 100644 --- a/app/org/thp/cortex/services/ProcessJobRunnerSrv.scala +++ b/app/org/thp/cortex/services/ProcessJobRunnerSrv.scala @@ -1,16 +1,16 @@ package org.thp.cortex.services import java.nio.charset.StandardCharsets -import java.nio.file.{ Files, Path, Paths } +import java.nio.file.{Files, Path, Paths} import scala.concurrent.duration.FiniteDuration -import scala.concurrent.{ ExecutionContext, Future } -import scala.sys.process.{ Process, ProcessLogger } +import scala.concurrent.{ExecutionContext, Future} +import scala.sys.process.{Process, ProcessLogger} import play.api.Logger import akka.actor.ActorSystem -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import org.thp.cortex.models._ import org.elastic4play.utils.RichFuture @@ -20,11 +20,12 @@ import scala.util.Try import play.api.libs.json.Json @Singleton -class ProcessJobRunnerSrv @Inject() (implicit val system: ActorSystem) { +class ProcessJobRunnerSrv @Inject()(implicit val system: ActorSystem) { lazy val logger = Logger(getClass) private val pythonPackageVersionRegex = "^Version: ([0-9]*)\\.([0-9]*)\\.([0-9]*)".r + def checkCortexUtilsVersion(pythonVersion: String): Option[(Int, Int, Int)] = Try { (s"pip$pythonVersion" :: "show" :: "cortexutils" :: Nil) @@ -48,9 +49,7 @@ class ProcessJobRunnerSrv @Inject() (implicit val system: ActorSystem) { case error ⇒ logger.error(s"Execution of command $command failed", error) Future.apply { - val report = Json.obj( - "success" -> false, - "errorMessage" -> error.getMessage) + val report = Json.obj("success" → false, "errorMessage" → error.getMessage) Files.write(jobDirectory.resolve("output").resolve("output.json"), report.toString.getBytes(StandardCharsets.UTF_8)) () } diff --git a/app/org/thp/cortex/services/ResponderConfigSrv.scala b/app/org/thp/cortex/services/ResponderConfigSrv.scala index aa3e6baba..6da517243 100644 --- a/app/org/thp/cortex/services/ResponderConfigSrv.scala +++ b/app/org/thp/cortex/services/ResponderConfigSrv.scala @@ -1,17 +1,17 @@ package org.thp.cortex.services -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import play.api.Configuration import akka.stream.Materializer -import javax.inject.{ Inject, Singleton } -import org.thp.cortex.models.{ BaseConfig, WorkerConfigModel, WorkerType } +import javax.inject.{Inject, Singleton} +import org.thp.cortex.models.{BaseConfig, WorkerConfigModel, WorkerType} -import org.elastic4play.services.{ CreateSrv, FindSrv, UpdateSrv } +import org.elastic4play.services.{CreateSrv, FindSrv, UpdateSrv} @Singleton -class ResponderConfigSrv @Inject() ( +class ResponderConfigSrv @Inject()( val configuration: Configuration, val workerConfigModel: WorkerConfigModel, val userSrv: UserSrv, @@ -21,8 +21,9 @@ class ResponderConfigSrv @Inject() ( val updateSrv: UpdateSrv, val findSrv: FindSrv, implicit val ec: ExecutionContext, - implicit val mat: Materializer) extends WorkerConfigSrv { + implicit val mat: Materializer +) extends WorkerConfigSrv { - override val workerType: WorkerType.Type = WorkerType.responder + override val workerType: WorkerType.Type = WorkerType.responder def definitions: Future[Map[String, BaseConfig]] = buildDefinitionMap(workerSrv.listResponderDefinitions._1) } diff --git a/app/org/thp/cortex/services/StreamMessage.scala b/app/org/thp/cortex/services/StreamMessage.scala index b02575650..826ae0c8c 100644 --- a/app/org/thp/cortex/services/StreamMessage.scala +++ b/app/org/thp/cortex/services/StreamMessage.scala @@ -1,12 +1,12 @@ package org.thp.cortex.services -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import play.api.Logger import play.api.libs.json.Json.toJsFieldJsValueWrapper -import play.api.libs.json.{ JsObject, Json } +import play.api.libs.json.{JsObject, Json} -import org.elastic4play.services.{ AuditOperation, AuxSrv, MigrationEvent } +import org.elastic4play.services.{AuditOperation, AuxSrv, MigrationEvent} trait StreamMessageGroup[M] { def :+(message: M): StreamMessageGroup[M] @@ -20,12 +20,17 @@ case class AuditOperationGroup( operation: AuditOperation, auditedAttributes: JsObject, obj: Future[JsObject], - summary: Map[String, Map[String, Int]], isReady: Boolean) extends StreamMessageGroup[AuditOperation] { + summary: Map[String, Map[String, Int]], + isReady: Boolean +) extends StreamMessageGroup[AuditOperation] { + def :+(operation: AuditOperation): AuditOperationGroup = { val modelSummary = summary.getOrElse(operation.entity.model.modelName, Map.empty[String, Int]) - val actionCount = modelSummary.getOrElse(operation.action.toString, 0) - copy(summary = summary + (operation.entity.model.modelName → (modelSummary + - (operation.action.toString → (actionCount + 1))))) + val actionCount = modelSummary.getOrElse(operation.action.toString, 0) + copy( + summary = summary + (operation.entity.model.modelName → (modelSummary + + (operation.action.toString → (actionCount + 1)))) + ) } def makeReady: AuditOperationGroup = copy(isReady = true) @@ -33,18 +38,20 @@ case class AuditOperationGroup( def toJson(implicit ec: ExecutionContext): Future[JsObject] = obj.map { o ⇒ Json.obj( "base" → Json.obj( - "objectId" → operation.entity.id, + "objectId" → operation.entity.id, "objectType" → operation.entity.model.modelName, - "operation" → operation.action, - "startDate" → operation.date, - "rootId" → operation.entity.routing, - "user" → operation.authContext.userId, - "createdBy" → operation.authContext.userId, - "createdAt" → operation.date, - "requestId" → operation.authContext.requestId, - "object" → o, - "details" → auditedAttributes), - "summary" → summary) + "operation" → operation.action, + "startDate" → operation.date, + "rootId" → operation.entity.routing, + "user" → operation.authContext.userId, + "createdBy" → operation.authContext.userId, + "createdAt" → operation.date, + "requestId" → operation.authContext.requestId, + "object" → o, + "details" → auditedAttributes + ), + "summary" → summary + ) } } @@ -53,7 +60,9 @@ object AuditOperationGroup { def apply(auxSrv: AuxSrv, operation: AuditOperation)(implicit ec: ExecutionContext): AuditOperationGroup = { val auditedAttributes = JsObject { - operation.details.fields + operation + .details + .fields .map { case (name, value) ⇒ val baseName = name.split("\\.").head @@ -73,11 +82,13 @@ object AuditOperationGroup { auditedAttributes, obj, Map(operation.entity.model.modelName → Map(operation.action.toString → 1)), - false) + false + ) } } case class MigrationEventGroup(tableName: String, current: Long, total: Long) extends StreamMessageGroup[MigrationEvent] { + def :+(event: MigrationEvent): MigrationEventGroup = { assert(event.modelName == tableName) if (current < event.current) @@ -85,18 +96,16 @@ case class MigrationEventGroup(tableName: String, current: Long, total: Long) ex else this } - val isReady = true + val isReady = true def makeReady: MigrationEventGroup = this - def toJson(implicit ec: ExecutionContext): Future[JsObject] = Future.successful(Json.obj( - "base" → Json.obj( - "rootId" → current, - "objectType" → "migration", - "tableName" → tableName, - "current" → current, - "total" → total))) + + def toJson(implicit ec: ExecutionContext): Future[JsObject] = + Future.successful( + Json.obj("base" → Json.obj("rootId" → current, "objectType" → "migration", "tableName" → tableName, "current" → current, "total" → total)) + ) } object MigrationEventGroup { def apply(event: MigrationEvent) = new MigrationEventGroup(event.modelName, event.current, event.total) - def endOfMigration = new MigrationEventGroup("end", 0, 0) + def endOfMigration = new MigrationEventGroup("end", 0, 0) } diff --git a/app/org/thp/cortex/services/StreamSrv.scala b/app/org/thp/cortex/services/StreamSrv.scala index 95d35e205..335029b98 100644 --- a/app/org/thp/cortex/services/StreamSrv.scala +++ b/app/org/thp/cortex/services/StreamSrv.scala @@ -1,23 +1,23 @@ package org.thp.cortex.services -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} -import akka.actor.{ Actor, ActorLogging, ActorRef, ActorSystem, Cancellable, DeadLetter, PoisonPill, actorRef2Scala } +import akka.actor.{actorRef2Scala, Actor, ActorLogging, ActorRef, ActorSystem, Cancellable, DeadLetter, PoisonPill} import akka.stream.Materializer import org.elastic4play.services._ import org.elastic4play.utils.Instance import play.api.Logger import play.api.libs.json.JsObject -import play.api.mvc.{ Filter, RequestHeader, Result } +import play.api.mvc.{Filter, RequestHeader, Result} import scala.concurrent.duration.FiniteDuration -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} /** * This actor monitors dead messages and log them */ @Singleton -class DeadLetterMonitoringActor @Inject() (system: ActorSystem) extends Actor { +class DeadLetterMonitoringActor @Inject()(system: ActorSystem) extends Actor { private[DeadLetterMonitoringActor] lazy val logger = Logger(getClass) override def preStart(): Unit = { @@ -59,46 +59,38 @@ class StreamActor( nextItemMaxWait: FiniteDuration, globalMaxWait: FiniteDuration, eventSrv: EventSrv, - auxSrv: AuxSrv) extends Actor with ActorLogging { + auxSrv: AuxSrv +) extends Actor + with ActorLogging { import context.dispatcher import org.thp.cortex.services.StreamActor._ private[StreamActor] lazy val logger = Logger(getClass) private object FakeCancellable extends Cancellable { - def cancel() = true + def cancel() = true def isCancelled = true } private class WaitingRequest(senderRef: ActorRef, itemCancellable: Cancellable, globalCancellable: Cancellable, hasResult: Boolean) { - def this(senderRef: ActorRef) = this( - senderRef, - FakeCancellable, - context.system.scheduler.scheduleOnce(refresh, self, Submit), - false) + def this(senderRef: ActorRef) = this(senderRef, FakeCancellable, context.system.scheduler.scheduleOnce(refresh, self, Submit), false) /** * Renew timers */ - def renew: WaitingRequest = { + def renew: WaitingRequest = if (itemCancellable.cancel()) { if (!hasResult && globalCancellable.cancel()) { new WaitingRequest( senderRef, context.system.scheduler.scheduleOnce(nextItemMaxWait, self, Submit), context.system.scheduler.scheduleOnce(globalMaxWait, self, Submit), - true) - } - else - new WaitingRequest( - senderRef, - context.system.scheduler.scheduleOnce(nextItemMaxWait, self, Submit), - globalCancellable, - true) - } - else + true + ) + } else + new WaitingRequest(senderRef, context.system.scheduler.scheduleOnce(nextItemMaxWait, self, Submit), globalCancellable, true) + } else this - } /** * Send message @@ -115,10 +107,9 @@ class StreamActor( /** * renew global timer and rearm it */ - def renewExpiration(): Unit = { + def renewExpiration(): Unit = if (killCancel.cancel()) killCancel = context.system.scheduler.scheduleOnce(cacheExpiration, self, PoisonPill) - } override def preStart(): Unit = { renewExpiration() @@ -169,7 +160,7 @@ class StreamActor( /* */ case operation: AuditOperation ⇒ - val requestId = operation.authContext.requestId + val requestId = operation.authContext.requestId val normalizedOperation = normalizeOperation(operation) logger.debug(s"Receiving audit operation : $operation ⇒ $normalizedOperation") val updatedOperationGroup = currentMessages.get(requestId) match { @@ -214,12 +205,10 @@ class StreamActor( } @Singleton -class StreamFilter @Inject() ( - eventSrv: EventSrv, - implicit val mat: Materializer, - implicit val ec: ExecutionContext) extends Filter { +class StreamFilter @Inject()(eventSrv: EventSrv, implicit val mat: Materializer, implicit val ec: ExecutionContext) extends Filter { private[StreamFilter] lazy val logger = Logger(getClass) + def apply(nextFilter: RequestHeader ⇒ Future[Result])(requestHeader: RequestHeader): Future[Result] = { val requestId = Instance.getRequestId(requestHeader) eventSrv.publish(StreamActor.Initialize(requestId)) @@ -227,4 +216,4 @@ class StreamFilter @Inject() ( case _ ⇒ eventSrv.publish(StreamActor.Commit(requestId)) } } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/services/UserSrv.scala b/app/org/thp/cortex/services/UserSrv.scala index e88fa1b4a..47f137de3 100644 --- a/app/org/thp/cortex/services/UserSrv.scala +++ b/app/org/thp/cortex/services/UserSrv.scala @@ -1,9 +1,9 @@ package org.thp.cortex.services -import javax.inject.{ Inject, Provider, Singleton } +import javax.inject.{Inject, Provider, Singleton} import scala.concurrent.duration.Duration -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import play.api.Configuration import play.api.cache.AsyncCacheApi @@ -14,10 +14,10 @@ import akka.stream.scaladsl.Source import org.thp.cortex.models._ import org.elastic4play.controllers.Fields -import org.elastic4play.database.{ DBIndex, ModifyConfig } -import org.elastic4play.services.{ User ⇒ _, _ } +import org.elastic4play.database.{DBIndex, ModifyConfig} +import org.elastic4play.services.{User ⇒ EUser, UserSrv ⇒ EUserSrv, _} import org.elastic4play.utils.Instance -import org.elastic4play.{ AuthenticationError, AuthorizationError, NotFoundError } +import org.elastic4play.{AuthenticationError, AuthorizationError, NotFoundError} @Singleton class UserSrv( @@ -33,7 +33,8 @@ class UserSrv( organizationSrv: OrganizationSrv, dbIndex: DBIndex, cache: AsyncCacheApi, - implicit val ec: ExecutionContext) extends org.elastic4play.services.UserSrv { + implicit val ec: ExecutionContext +) extends EUserSrv { @Inject() def this( config: Configuration, @@ -48,20 +49,23 @@ class UserSrv( organizationSrv: OrganizationSrv, dbIndex: DBIndex, cache: AsyncCacheApi, - ec: ExecutionContext) = this( - config.get[Duration]("cache.user"), - userModel, - createSrv, - getSrv, - updateSrv, - deleteSrv, - findSrv, - eventSrv, - authSrv, - organizationSrv, - dbIndex, - cache, - ec) + ec: ExecutionContext + ) = + this( + config.get[Duration]("cache.user"), + userModel, + createSrv, + getSrv, + updateSrv, + deleteSrv, + findSrv, + eventSrv, + authSrv, + organizationSrv, + dbIndex, + cache, + ec + ) private case class AuthContextImpl(userId: String, userName: String, requestId: String, roles: Seq[Role], authMethod: String) extends AuthContext @@ -70,22 +74,22 @@ class UserSrv( cache.remove(s"user-org-$userId") } - override def getFromId(request: RequestHeader, userId: String, authMethod: String): Future[AuthContext] = { - get(userId).flatMap { user ⇒ getFromUser(request, user, authMethod) } - } + override def getFromId(request: RequestHeader, userId: String, authMethod: String): Future[AuthContext] = + get(userId).flatMap { user ⇒ + getFromUser(request, user, authMethod) + } - override def getFromUser(request: RequestHeader, user: org.elastic4play.services.User, authMethod: String): Future[AuthContext] = { + override def getFromUser(request: RequestHeader, user: EUser, authMethod: String): Future[AuthContext] = user match { case u: User if u.status() == UserStatus.Ok ⇒ organizationSrv.get(u.organization()).flatMap { - case o if o.status() == OrganizationStatus.Active ⇒ Future.successful(AuthContextImpl(user.id, user.getUserName, Instance.getRequestId(request), user.getRoles, authMethod)) - case _ ⇒ Future.failed(AuthorizationError("Your account is locked")) + case o if o.status() == OrganizationStatus.Active ⇒ + Future.successful(AuthContextImpl(user.id, user.getUserName, Instance.getRequestId(request), user.getRoles, authMethod)) + case _ ⇒ Future.failed(AuthorizationError("Your account is locked")) } case _ ⇒ Future.failed(AuthorizationError("Your account is locked")) } - } - override def getInitialUser(request: RequestHeader): Future[AuthContext] = dbIndex.getSize(userModel.modelName).map { case size if size > 0 ⇒ throw AuthenticationError(s"Use of initial user is forbidden because users exist in database") @@ -100,14 +104,14 @@ class UserSrv( } } - def create(fields: Fields)(implicit authContext: AuthContext): Future[User] = { + def create(fields: Fields)(implicit authContext: AuthContext): Future[User] = fields.getString("password") match { case None ⇒ createSrv[UserModel, User](userModel, fields) - case Some(password) ⇒ createSrv[UserModel, User](userModel, fields.unset("password")).flatMap { user ⇒ - authSrv.get.setPassword(user.userId(), password).map(_ ⇒ user) - } + case Some(password) ⇒ + createSrv[UserModel, User](userModel, fields.unset("password")).flatMap { user ⇒ + authSrv.get.setPassword(user.userId(), password).map(_ ⇒ user) + } } - } override def get(userId: String): Future[User] = cache.getOrElseUpdate(s"user-$userId", cacheExpiration) { getSrv[UserModel, User](userModel, userId) @@ -138,11 +142,15 @@ class UserSrv( deleteSrv[UserModel, User](userModel, userId) } - def find(queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[User, NotUsed], Future[Long]) = { + def find(queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[User, NotUsed], Future[Long]) = findSrv[UserModel, User](userModel, queryDef, range, sortBy) - } - def findForOrganization(organizationId: String, queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[User, NotUsed], Future[Long]) = { + def findForOrganization( + organizationId: String, + queryDef: QueryDef, + range: Option[String], + sortBy: Seq[String] + ): (Source[User, NotUsed], Future[Long]) = { import org.elastic4play.services.QueryDSL._ find(and("organization" ~= organizationId, queryDef), range, sortBy) } @@ -155,7 +163,7 @@ class UserSrv( .recover { case NotFoundError("user init not found") ⇒ Source.empty → Future.successful(0L) } val userSource = Source.fromFutureSource(users.map(_._1)).mapMaterializedValue(_ ⇒ NotUsed) - val userTotal = users.flatMap(_._2) + val userTotal = users.flatMap(_._2) userSource → userTotal } } diff --git a/app/org/thp/cortex/services/WorkerConfigSrv.scala b/app/org/thp/cortex/services/WorkerConfigSrv.scala index ecda03f79..02208b50a 100644 --- a/app/org/thp/cortex/services/WorkerConfigSrv.scala +++ b/app/org/thp/cortex/services/WorkerConfigSrv.scala @@ -1,17 +1,17 @@ package org.thp.cortex.services -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import play.api.Configuration import play.api.libs.json._ import akka.NotUsed import akka.stream.Materializer -import akka.stream.scaladsl.{ Sink, Source } +import akka.stream.scaladsl.{Sink, Source} import org.thp.cortex.models._ import org.scalactic.Accumulation._ -import org.elastic4play.{ AttributeCheckingError, NotFoundError } +import org.elastic4play.{AttributeCheckingError, NotFoundError} import org.elastic4play.controllers.Fields import org.elastic4play.database.ModifyConfig import org.elastic4play.services._ @@ -31,7 +31,7 @@ trait WorkerConfigSrv { def definitions: Future[Map[String, BaseConfig]] - protected def buildDefinitionMap(definitionSource: Source[WorkerDefinition, NotUsed]): Future[Map[String, BaseConfig]] = { + protected def buildDefinitionMap(definitionSource: Source[WorkerDefinition, NotUsed]): Future[Map[String, BaseConfig]] = definitionSource .filter(_.baseConfiguration.isDefined) .map(d ⇒ d.copy(configurationItems = d.configurationItems.map(_.copy(required = false)))) @@ -47,12 +47,11 @@ trait WorkerConfigSrv { .map(c ⇒ c.name → c) .toMap } - } - def getForUser(userId: String, configName: String): Future[BaseConfig] = { - userSrv.getOrganizationId(userId) + def getForUser(userId: String, configName: String): Future[BaseConfig] = + userSrv + .getOrganizationId(userId) .flatMap(organizationId ⇒ getForOrganization(organizationId, configName)) - } def getForOrganization(organizationId: String, configName: String): Future[BaseConfig] = { import org.elastic4play.services.QueryDSL._ @@ -60,37 +59,39 @@ trait WorkerConfigSrv { workerConfig ← findForOrganization(organizationId, "name" ~= configName, Some("0-1"), Nil) ._1 .runWith(Sink.headOption) - d ← definitions + d ← definitions baseConfig ← d.get(configName).fold[Future[BaseConfig]](Future.failed(NotFoundError(s"config $configName not found")))(Future.successful) } yield baseConfig.copy(config = workerConfig) } - def create(organization: Organization, fields: Fields)(implicit authContext: AuthContext): Future[WorkerConfig] = { + def create(organization: Organization, fields: Fields)(implicit authContext: AuthContext): Future[WorkerConfig] = createSrv[WorkerConfigModel, WorkerConfig, Organization](workerConfigModel, organization, fields.set("type", workerType.toString)) - } - def update(workerConfig: WorkerConfig, fields: Fields)(implicit authContext: AuthContext): Future[WorkerConfig] = { + def update(workerConfig: WorkerConfig, fields: Fields)(implicit authContext: AuthContext): Future[WorkerConfig] = updateSrv(workerConfig, fields, ModifyConfig.default) - } - def updateOrCreate(userId: String, workerConfigName: String, config: JsObject)(implicit authContext: AuthContext): Future[BaseConfig] = { + def updateOrCreate(userId: String, workerConfigName: String, config: JsObject)(implicit authContext: AuthContext): Future[BaseConfig] = for { organizationId ← userSrv.getOrganizationId(userId) - organization ← organizationSrv.get(organizationId) - baseConfig ← getForOrganization(organizationId, workerConfigName) - validatedConfig ← baseConfig.items.validatedBy(_.read(config)) + organization ← organizationSrv.get(organizationId) + baseConfig ← getForOrganization(organizationId, workerConfigName) + validatedConfig ← baseConfig + .items + .validatedBy(_.read(config)) .map(_.filterNot(_._2 == JsNull)) - .fold(c ⇒ Future.successful(Fields.empty.set("config", JsObject(c).toString).set("name", workerConfigName)), errors ⇒ Future.failed(AttributeCheckingError("workerConfig", errors.toSeq))) + .fold( + c ⇒ Future.successful(Fields.empty.set("config", JsObject(c).toString).set("name", workerConfigName)), + errors ⇒ Future.failed(AttributeCheckingError("workerConfig", errors.toSeq)) + ) newWorkerConfig ← baseConfig.config.fold(create(organization, validatedConfig))(workerConfig ⇒ update(workerConfig, validatedConfig)) } yield baseConfig.copy(config = Some(newWorkerConfig)) - } - private def updateDefinitionConfig(definitionConfig: Map[String, BaseConfig], workerConfig: WorkerConfig): Map[String, BaseConfig] = { - definitionConfig.get(workerConfig.name()) + private def updateDefinitionConfig(definitionConfig: Map[String, BaseConfig], workerConfig: WorkerConfig): Map[String, BaseConfig] = + definitionConfig + .get(workerConfig.name()) .fold(definitionConfig) { baseConfig ⇒ definitionConfig + (workerConfig.name() → baseConfig.copy(config = Some(workerConfig))) } - } def listConfigForUser(userId: String): Future[Seq[BaseConfig]] = { import org.elastic4play.services.QueryDSL._ @@ -98,24 +99,31 @@ trait WorkerConfigSrv { configItems ← definitions workerConfigs ← findForUser(userId, any, Some("all"), Nil) ._1 - .runFold(configItems) { (definitionConfig, workerConfig) ⇒ updateDefinitionConfig(definitionConfig, workerConfig) } + .runFold(configItems) { (definitionConfig, workerConfig) ⇒ + updateDefinitionConfig(definitionConfig, workerConfig) + } } yield workerConfigs.values.toSeq } def findForUser(userId: String, queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[WorkerConfig, NotUsed], Future[Long]) = { - val configs = userSrv.getOrganizationId(userId) + val configs = userSrv + .getOrganizationId(userId) .map(organizationId ⇒ findForOrganization(organizationId, queryDef, range, sortBy)) val configSource = Source.fromFutureSource(configs.map(_._1)).mapMaterializedValue(_ ⇒ NotUsed) - val configTotal = configs.flatMap(_._2) + val configTotal = configs.flatMap(_._2) configSource → configTotal } - def findForOrganization(organizationId: String, queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[WorkerConfig, NotUsed], Future[Long]) = { + def findForOrganization( + organizationId: String, + queryDef: QueryDef, + range: Option[String], + sortBy: Seq[String] + ): (Source[WorkerConfig, NotUsed], Future[Long]) = { import org.elastic4play.services.QueryDSL._ find(and(withParent("organization", organizationId), "type" ~= workerType, queryDef), range, sortBy) } - def find(queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[WorkerConfig, NotUsed], Future[Long]) = { + def find(queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[WorkerConfig, NotUsed], Future[Long]) = findSrv[WorkerConfigModel, WorkerConfig](workerConfigModel, queryDef, range, sortBy) - } } diff --git a/app/org/thp/cortex/services/WorkerSrv.scala b/app/org/thp/cortex/services/WorkerSrv.scala index 457256964..cb8203a18 100644 --- a/app/org/thp/cortex/services/WorkerSrv.scala +++ b/app/org/thp/cortex/services/WorkerSrv.scala @@ -1,24 +1,24 @@ package org.thp.cortex.services import java.net.URL -import java.nio.file.{ Files, Path, Paths } +import java.nio.file.{Files, Path, Paths} -import javax.inject.{ Inject, Provider, Singleton } +import javax.inject.{Inject, Provider, Singleton} import scala.collection.JavaConverters._ -import scala.concurrent.{ ExecutionContext, Future } -import scala.util.{ Failure, Success, Try } +import scala.concurrent.{ExecutionContext, Future} +import scala.util.{Failure, Success, Try} -import play.api.libs.json.{ JsObject, JsString, Json } +import play.api.libs.json.{JsObject, JsString, Json} import play.api.libs.ws.WSClient -import play.api.{ Configuration, Logger } +import play.api.{Configuration, Logger} import akka.NotUsed import akka.stream.Materializer -import akka.stream.scaladsl.{ Sink, Source } +import akka.stream.scaladsl.{Sink, Source} import org.thp.cortex.models._ import org.elastic4play._ -import org.elastic4play.controllers.{ Fields, StringInputValue } +import org.elastic4play.controllers.{Fields, StringInputValue} import org.elastic4play.services._ import org.scalactic._ import org.scalactic.Accumulation._ @@ -26,7 +26,7 @@ import org.scalactic.Accumulation._ import org.elastic4play.database.ModifyConfig @Singleton -class WorkerSrv @Inject() ( +class WorkerSrv @Inject()( config: Configuration, workerModel: WorkerModel, organizationSrv: OrganizationSrv, @@ -39,13 +39,14 @@ class WorkerSrv @Inject() ( findSrv: FindSrv, ws: WSClient, implicit val ec: ExecutionContext, - implicit val mat: Materializer) { + implicit val mat: Materializer +) { - private lazy val logger = Logger(getClass) - private val analyzersURLs: Seq[String] = config.getDeprecated[Seq[String]]("analyzer.urls", "analyzer.path") - private val respondersURLs: Seq[String] = config.getDeprecated[Seq[String]]("responder.urls", "responder.path") + private lazy val logger = Logger(getClass) + private val analyzersURLs: Seq[String] = config.getDeprecated[Seq[String]]("analyzer.urls", "analyzer.path") + private val respondersURLs: Seq[String] = config.getDeprecated[Seq[String]]("responder.urls", "responder.path") private lazy val jobRunnerSrv: JobRunnerSrv = jobRunnerSrvProvider.get - private var workerMap = Map.empty[String, WorkerDefinition] + private var workerMap = Map.empty[String, WorkerDefinition] private object workerMapLock rescan() @@ -69,70 +70,85 @@ class WorkerSrv @Inject() ( def get(workerId: String): Future[Worker] = getSrv[WorkerModel, Worker](workerModel, workerId) - def getForUser(userId: String, workerId: String): Future[Worker] = { - userSrv.getOrganizationId(userId) + def getForUser(userId: String, workerId: String): Future[Worker] = + userSrv + .getOrganizationId(userId) .flatMap(organization ⇒ getForOrganization(organization, workerId)) - } def getForOrganization(organizationId: String, workerId: String): Future[Worker] = { import org.elastic4play.services.QueryDSL._ - find( - and(withParent("organization", organizationId), withId(workerId)), - Some("0-1"), Nil)._1 + find(and(withParent("organization", organizationId), withId(workerId)), Some("0-1"), Nil) + ._1 .runWith(Sink.headOption) .map(_.getOrElse(throw NotFoundError(s"worker $workerId not found"))) } - def findAnalyzersForUser(userId: String, queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Worker, NotUsed], Future[Long]) = { + def findAnalyzersForUser( + userId: String, + queryDef: QueryDef, + range: Option[String], + sortBy: Seq[String] + ): (Source[Worker, NotUsed], Future[Long]) = { import org.elastic4play.services.QueryDSL._ val analyzers = for { user ← userSrv.get(userId) organizationId = user.organization() } yield findForOrganization(organizationId, and(queryDef, "type" ~= WorkerType.analyzer), range, sortBy) val analyserSource = Source.fromFutureSource(analyzers.map(_._1)).mapMaterializedValue(_ ⇒ NotUsed) - val analyserTotal = analyzers.flatMap(_._2) + val analyserTotal = analyzers.flatMap(_._2) analyserSource → analyserTotal } - def findRespondersForUser(userId: String, queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Worker, NotUsed], Future[Long]) = { + def findRespondersForUser( + userId: String, + queryDef: QueryDef, + range: Option[String], + sortBy: Seq[String] + ): (Source[Worker, NotUsed], Future[Long]) = { import org.elastic4play.services.QueryDSL._ val responders = for { user ← userSrv.get(userId) organizationId = user.organization() } yield findForOrganization(organizationId, and(queryDef, "type" ~= WorkerType.responder), range, sortBy) val analyserSource = Source.fromFutureSource(responders.map(_._1)).mapMaterializedValue(_ ⇒ NotUsed) - val analyserTotal = responders.flatMap(_._2) + val analyserTotal = responders.flatMap(_._2) analyserSource → analyserTotal } - private def findForOrganization(organizationId: String, queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Worker, NotUsed], Future[Long]) = { + private def findForOrganization( + organizationId: String, + queryDef: QueryDef, + range: Option[String], + sortBy: Seq[String] + ): (Source[Worker, NotUsed], Future[Long]) = { import org.elastic4play.services.QueryDSL._ find(and(withParent("organization", organizationId), queryDef), range, sortBy) } - private def find(queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Worker, NotUsed], Future[Long]) = { + private def find(queryDef: QueryDef, range: Option[String], sortBy: Seq[String]): (Source[Worker, NotUsed], Future[Long]) = findSrv[WorkerModel, Worker](workerModel, queryDef, range, sortBy) - } - def rescan(): Unit = { - scan(analyzersURLs.map(_ → WorkerType.analyzer) ++ - respondersURLs.map(_ → WorkerType.responder)) - } + def rescan(): Unit = + scan( + analyzersURLs.map(_ → WorkerType.analyzer) ++ + respondersURLs.map(_ → WorkerType.responder) + ) def scan(workerUrls: Seq[(String, WorkerType.Type)]): Unit = { - def readUrl(url: URL, workerType: WorkerType.Type): Future[Seq[WorkerDefinition]] = { + def readUrl(url: URL, workerType: WorkerType.Type): Future[Seq[WorkerDefinition]] = url.getProtocol match { case "file" ⇒ Future.successful(readFile(Paths.get(url.toURI), workerType)) case "http" | "https" ⇒ val reads = WorkerDefinition.reads(workerType) - ws.url(url.toString).get().map(response ⇒ response.json.as(reads)) + ws.url(url.toString) + .get() + .map(response ⇒ response.json.as(reads)) .map(_.filterNot(_.command.isDefined)) } - } def readFile(path: Path, workerType: WorkerType.Type): Seq[WorkerDefinition] = { - val reads = WorkerDefinition.reads(workerType) - val source = scala.io.Source.fromFile(path.toFile) + val reads = WorkerDefinition.reads(workerType) + val source = scala.io.Source.fromFile(path.toFile) lazy val basePath = path.getParent.getParent val workerDefinitions = for { @@ -148,28 +164,29 @@ class WorkerSrv @Inject() ( case w if w.command.isDefined && jobRunnerSrv.processRunnerIsEnable ⇒ true case w if w.dockerImage.isDefined && jobRunnerSrv.dockerRunnerIsEnable ⇒ true case w ⇒ - val reason = if (w.command.isDefined) "process runner is disabled" - else if (w.dockerImage.isDefined) "Docker runner is disabled" - else "it doesn't have image nor command" + val reason = + if (w.command.isDefined) "process runner is disabled" + else if (w.dockerImage.isDefined) "Docker runner is disabled" + else "it doesn't have image nor command" logger.warn(s"$workerType ${w.name} is disabled because $reason") false } } - def readDirectory(path: Path, workerType: WorkerType.Type): Seq[WorkerDefinition] = { + def readDirectory(path: Path, workerType: WorkerType.Type): Seq[WorkerDefinition] = for { workerDir ← Files.newDirectoryStream(path).asScala.toSeq if Files.isDirectory(workerDir) - infoFile ← Files.newDirectoryStream(workerDir, "*.json").asScala + infoFile ← Files.newDirectoryStream(workerDir, "*.json").asScala workerDefinition ← readFile(infoFile, workerType) } yield workerDefinition - } Future .traverse(workerUrls) { case (workerUrl, workerType) ⇒ - Future(new URL(workerUrl)).flatMap(readUrl(_, workerType)) + Future(new URL(workerUrl)) + .flatMap(readUrl(_, workerType)) .recover { case _ ⇒ val path = Paths.get(workerUrl) @@ -182,16 +199,20 @@ class WorkerSrv @Inject() ( } } .foreach { worker ⇒ - val wmap = worker.flatten.map(w ⇒ w.id -> w).toMap + val wmap = worker.flatten.map(w ⇒ w.id → w).toMap workerMapLock.synchronized(workerMap = wmap) logger.info(s"New worker list:\n\n\t${workerMap.values.map(a ⇒ s"${a.name} ${a.version}").mkString("\n\t")}\n") } } - def create(organization: Organization, workerDefinition: WorkerDefinition, workerFields: Fields)(implicit authContext: AuthContext): Future[Worker] = { + def create(organization: Organization, workerDefinition: WorkerDefinition, workerFields: Fields)( + implicit authContext: AuthContext + ): Future[Worker] = { val rawConfig = workerFields.getValue("configuration").fold(JsObject.empty)(_.as[JsObject]) - val configItems = workerDefinition.configurationItems ++ BaseConfig.global(workerDefinition.tpe, config).items ++ BaseConfig.tlp.items ++ BaseConfig.pap.items + val configItems = workerDefinition.configurationItems ++ BaseConfig.global(workerDefinition.tpe, config).items ++ BaseConfig + .tlp + .items ++ BaseConfig.pap.items val configOrErrors = configItems .validatedBy(_.read(rawConfig)) .map(JsObject.apply) @@ -203,33 +224,38 @@ class WorkerSrv @Inject() ( } withGood(configOrErrors, unknownConfigItems)((c, _) ⇒ c) - .fold(cfg ⇒ { - createSrv[WorkerModel, Worker, Organization](workerModel, organization, workerFields - .set("workerDefinitionId", workerDefinition.id) - .set("description", workerDefinition.description) - .set("author", workerDefinition.author) - .set("version", workerDefinition.version) - .set("dockerImage", workerDefinition.dockerImage.map(JsString)) - .set("command", workerDefinition.command.map(p ⇒ JsString(p.toString))) - .set("url", workerDefinition.url) - .set("license", workerDefinition.license) - .set("baseConfig", workerDefinition.baseConfiguration.map(JsString.apply)) - .set("configuration", cfg.toString) - .set("type", workerDefinition.tpe.toString) - .addIfAbsent("dataTypeList", StringInputValue(workerDefinition.dataTypeList))) - - }, { - case One(e) ⇒ Future.failed(e) - case Every(es @ _*) ⇒ Future.failed(AttributeCheckingError(s"worker(${workerDefinition.name}).configuration", es)) - }) + .fold( + cfg ⇒ { + createSrv[WorkerModel, Worker, Organization]( + workerModel, + organization, + workerFields + .set("workerDefinitionId", workerDefinition.id) + .set("description", workerDefinition.description) + .set("author", workerDefinition.author) + .set("version", workerDefinition.version) + .set("dockerImage", workerDefinition.dockerImage.map(JsString)) + .set("command", workerDefinition.command.map(p ⇒ JsString(p.toString))) + .set("url", workerDefinition.url) + .set("license", workerDefinition.license) + .set("baseConfig", workerDefinition.baseConfiguration.map(JsString.apply)) + .set("configuration", cfg.toString) + .set("type", workerDefinition.tpe.toString) + .addIfAbsent("dataTypeList", StringInputValue(workerDefinition.dataTypeList)) + ) + + }, { + case One(e) ⇒ Future.failed(e) + case Every(es @ _*) ⇒ Future.failed(AttributeCheckingError(s"worker(${workerDefinition.name}).configuration", es)) + } + ) } - def create(organizationId: String, workerDefinition: WorkerDefinition, workerFields: Fields)(implicit authContext: AuthContext): Future[Worker] = { + def create(organizationId: String, workerDefinition: WorkerDefinition, workerFields: Fields)(implicit authContext: AuthContext): Future[Worker] = for { organization ← organizationSrv.get(organizationId) - worker ← create(organization, workerDefinition, workerFields) + worker ← create(organization, workerDefinition, workerFields) } yield worker - } def delete(worker: Worker)(implicit authContext: AuthContext): Future[Unit] = deleteSrv.realDelete(worker) @@ -246,7 +272,6 @@ class WorkerSrv @Inject() ( def update(workerId: String, fields: Fields)(implicit authContext: AuthContext): Future[Worker] = update(workerId, fields, ModifyConfig.default) - def update(workerId: String, fields: Fields, modifyConfig: ModifyConfig)(implicit authContext: AuthContext): Future[Worker] = { + def update(workerId: String, fields: Fields, modifyConfig: ModifyConfig)(implicit authContext: AuthContext): Future[Worker] = get(workerId).flatMap(worker ⇒ update(worker, fields, modifyConfig)) - } -} \ No newline at end of file +} diff --git a/app/org/thp/cortex/services/mappers/GroupUserMapper.scala b/app/org/thp/cortex/services/mappers/GroupUserMapper.scala index 3c940d4d4..7dcd91698 100644 --- a/app/org/thp/cortex/services/mappers/GroupUserMapper.scala +++ b/app/org/thp/cortex/services/mappers/GroupUserMapper.scala @@ -1,6 +1,6 @@ package org.thp.cortex.services.mappers -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import play.api.Configuration import play.api.libs.json._ @@ -22,24 +22,23 @@ class GroupUserMapper( groupsUrl: String, mappings: Map[String, Seq[String]], ws: WSClient, - implicit val ec: ExecutionContext) extends UserMapper { + implicit val ec: ExecutionContext +) extends UserMapper { - @Inject() def this( - - configuration: Configuration, - ws: WSClient, - ec: ExecutionContext) = this( - configuration.getOptional[String]("auth.sso.attributes.login").getOrElse("name"), - configuration.getOptional[String]("auth.sso.attributes.name").getOrElse("username"), - configuration.getOptional[String]("auth.sso.attributes.roles"), - configuration.getOptional[String]("auth.sso.attributes.groups").getOrElse(""), - configuration.getOptional[String]("auth.sso.attributes.organization"), - configuration.getOptional[Seq[String]]("auth.sso.defaultRoles").getOrElse(Seq()), - configuration.getOptional[String]("auth.sso.defaultOrganization"), - configuration.getOptional[String]("auth.sso.groups.url").getOrElse(""), - configuration.getOptional[Map[String, Seq[String]]]("auth.sso.groups.mappings").getOrElse(Map()), - ws, - ec) + @Inject() def this(configuration: Configuration, ws: WSClient, ec: ExecutionContext) = + this( + configuration.getOptional[String]("auth.sso.attributes.login").getOrElse("name"), + configuration.getOptional[String]("auth.sso.attributes.name").getOrElse("username"), + configuration.getOptional[String]("auth.sso.attributes.roles"), + configuration.getOptional[String]("auth.sso.attributes.groups").getOrElse(""), + configuration.getOptional[String]("auth.sso.attributes.organization"), + configuration.getOptional[Seq[String]]("auth.sso.defaultRoles").getOrElse(Seq()), + configuration.getOptional[String]("auth.sso.defaultOrganization"), + configuration.getOptional[String]("auth.sso.groups.url").getOrElse(""), + configuration.getOptional[Map[String, Seq[String]]]("auth.sso.groups.mappings").getOrElse(Map()), + ws, + ec + ) override val name: String = "group" @@ -47,22 +46,18 @@ class GroupUserMapper( val apiCall = authHeader.fold(ws.url(groupsUrl))(headers ⇒ ws.url(groupsUrl).addHttpHeaders(headers)) apiCall.get.flatMap { r ⇒ - val jsonGroups = (r.json \ groupAttrName).as[Seq[String]] + val jsonGroups = (r.json \ groupAttrName).as[Seq[String]] val mappedRoles = jsonGroups.flatMap(mappings.get).maxBy(_.length) - val roles = if (mappedRoles.nonEmpty) mappedRoles else defaultRoles + val roles = if (mappedRoles.nonEmpty) mappedRoles else defaultRoles val fields = for { login ← (jsValue \ loginAttrName).validate[String] - name ← (jsValue \ nameAttrName).validate[String] + name ← (jsValue \ nameAttrName).validate[String] organization ← organizationAttrName .flatMap(o ⇒ (jsValue \ o).asOpt[String]) .orElse(defaultOrganization) .fold[JsResult[String]](JsError())(o ⇒ JsSuccess(o)) - } yield Fields(Json.obj( - "login" → login, - "name" → name, - "roles" → roles, - "organization" → organization)) + } yield Fields(Json.obj("login" → login, "name" → name, "roles" → roles, "organization" → organization)) fields match { case JsSuccess(f, _) ⇒ Future.successful(f) case JsError(errors) ⇒ Future.failed(AuthenticationError(s"User info fails: ${errors.map(_._1).mkString}")) diff --git a/app/org/thp/cortex/services/mappers/MultiUserMapperSrv.scala b/app/org/thp/cortex/services/mappers/MultiUserMapperSrv.scala index 238605b2f..f574e0e07 100644 --- a/app/org/thp/cortex/services/mappers/MultiUserMapperSrv.scala +++ b/app/org/thp/cortex/services/mappers/MultiUserMapperSrv.scala @@ -6,11 +6,12 @@ import scala.concurrent.Future import play.api.Configuration import play.api.libs.json.JsValue -import javax.inject.{ Inject, Singleton } +import javax.inject.{Inject, Singleton} import org.elastic4play.controllers.Fields object MultiUserMapperSrv { + def getMapper(configuration: Configuration, ssoMapperModules: immutable.Set[UserMapper]): UserMapper = { val name = configuration.getOptional[String]("auth.sso.mapper").getOrElse("simple") ssoMapperModules.find(_.name == name).get @@ -18,15 +19,12 @@ object MultiUserMapperSrv { } @Singleton -class MultiUserMapperSrv @Inject() ( - configuration: Configuration, - ssoMapperModules: immutable.Set[UserMapper]) extends UserMapper { +class MultiUserMapperSrv @Inject()(configuration: Configuration, ssoMapperModules: immutable.Set[UserMapper]) extends UserMapper { - override val name: String = "usermapper" + override val name: String = "usermapper" private lazy val mapper: UserMapper = MultiUserMapperSrv.getMapper(configuration, ssoMapperModules) - override def getUserFields(jsValue: JsValue, authHeader: Option[(String, String)]): Future[Fields] = { + override def getUserFields(jsValue: JsValue, authHeader: Option[(String, String)]): Future[Fields] = mapper.getUserFields(jsValue, authHeader) - } } diff --git a/app/org/thp/cortex/services/mappers/SimpleUserMapper.scala b/app/org/thp/cortex/services/mappers/SimpleUserMapper.scala index b7e6919fe..bd3bd54c3 100644 --- a/app/org/thp/cortex/services/mappers/SimpleUserMapper.scala +++ b/app/org/thp/cortex/services/mappers/SimpleUserMapper.scala @@ -1,6 +1,6 @@ package org.thp.cortex.services.mappers -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} import play.api.Configuration import play.api.libs.json._ @@ -17,33 +17,32 @@ class SimpleUserMapper( organizationAttrName: Option[String], defaultRoles: Seq[String], defaultOrganization: Option[String], - implicit val ec: ExecutionContext) extends UserMapper { - - @Inject() def this(configuration: Configuration, ec: ExecutionContext) = this( - configuration.getOptional[String]("auth.sso.attributes.login").getOrElse("name"), - configuration.getOptional[String]("auth.sso.attributes.name").getOrElse("username"), - configuration.getOptional[String]("auth.sso.attributes.roles"), - configuration.getOptional[String]("auth.sso.attributes.organization"), - configuration.getOptional[Seq[String]]("auth.sso.defaultRoles").getOrElse(Seq()), - configuration.getOptional[String]("auth.sso.defaultOrganization"), - ec) + implicit val ec: ExecutionContext +) extends UserMapper { + + @Inject() def this(configuration: Configuration, ec: ExecutionContext) = + this( + configuration.getOptional[String]("auth.sso.attributes.login").getOrElse("name"), + configuration.getOptional[String]("auth.sso.attributes.name").getOrElse("username"), + configuration.getOptional[String]("auth.sso.attributes.roles"), + configuration.getOptional[String]("auth.sso.attributes.organization"), + configuration.getOptional[Seq[String]]("auth.sso.defaultRoles").getOrElse(Seq()), + configuration.getOptional[String]("auth.sso.defaultOrganization"), + ec + ) override val name: String = "simple" override def getUserFields(jsValue: JsValue, authHeader: Option[(String, String)]): Future[Fields] = { val fields = for { login ← (jsValue \ loginAttrName).validate[String] - name ← (jsValue \ nameAttrName).validate[String] + name ← (jsValue \ nameAttrName).validate[String] roles = rolesAttrName.fold(defaultRoles)(r ⇒ (jsValue \ r).asOpt[Seq[String]].getOrElse(defaultRoles)) organization ← organizationAttrName .flatMap(o ⇒ (jsValue \ o).asOpt[String]) .orElse(defaultOrganization) .fold[JsResult[String]](JsError())(o ⇒ JsSuccess(o)) - } yield Fields(Json.obj( - "login" → login, - "name" → name, - "roles" → roles, - "organization" → organization)) + } yield Fields(Json.obj("login" → login, "name" → name, "roles" → roles, "organization" → organization)) fields match { case JsSuccess(f, _) ⇒ Future.successful(f) case JsError(errors) ⇒ Future.failed(AuthenticationError(s"User info fails: ${errors.map(_._1).mkString}")) diff --git a/app/org/thp/cortex/util/JsonConfig.scala b/app/org/thp/cortex/util/JsonConfig.scala index 57720a723..d30a5637a 100644 --- a/app/org/thp/cortex/util/JsonConfig.scala +++ b/app/org/thp/cortex/util/JsonConfig.scala @@ -1,23 +1,26 @@ package org.thp.cortex.util -import com.typesafe.config.ConfigValueType.{ BOOLEAN, NULL, NUMBER, STRING } -import com.typesafe.config.{ ConfigList, ConfigObject, ConfigValue } +import com.typesafe.config.ConfigValueType.{BOOLEAN, NULL, NUMBER, STRING} +import com.typesafe.config.{ConfigList, ConfigObject, ConfigValue} import play.api.Configuration import play.api.libs.json._ import scala.collection.JavaConverters._ object JsonConfig { - implicit val configValueWrites: Writes[ConfigValue] = Writes((value: ConfigValue) ⇒ value match { - case v: ConfigObject ⇒ configWrites.writes(Configuration(v.toConfig)) - case v: ConfigList ⇒ JsArray(v.asScala.map(x ⇒ configValueWrites.writes(x))) - case v if v.valueType == NUMBER ⇒ JsNumber(BigDecimal(v.unwrapped.asInstanceOf[java.lang.Number].toString)) - case v if v.valueType == BOOLEAN ⇒ JsBoolean(v.unwrapped.asInstanceOf[Boolean]) - case v if v.valueType == NULL ⇒ JsNull - case v if v.valueType == STRING ⇒ JsString(v.unwrapped.asInstanceOf[String]) - }) + implicit val configValueWrites: Writes[ConfigValue] = Writes( + (value: ConfigValue) ⇒ + value match { + case v: ConfigObject ⇒ configWrites.writes(Configuration(v.toConfig)) + case v: ConfigList ⇒ JsArray(v.asScala.map(x ⇒ configValueWrites.writes(x))) + case v if v.valueType == NUMBER ⇒ JsNumber(BigDecimal(v.unwrapped.asInstanceOf[Number].toString)) + case v if v.valueType == BOOLEAN ⇒ JsBoolean(v.unwrapped.asInstanceOf[Boolean]) + case v if v.valueType == NULL ⇒ JsNull + case v if v.valueType == STRING ⇒ JsString(v.unwrapped.asInstanceOf[String]) + } + ) implicit def configWrites = OWrites { (cfg: Configuration) ⇒ JsObject(cfg.subKeys.map(key ⇒ key → configValueWrites.writes(cfg.underlying.getValue(key))).toSeq) } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index fc456bdd3..000000000 --- a/package-lock.json +++ /dev/null @@ -1,4291 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "thehive-kit": { - "version": "1.0.0", - "requires": { - "angular": "1.6.8" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.0.0-beta.31", - "bundled": true, - "requires": { - "chalk": "2.3.0", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.0", - "bundled": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "chalk": { - "version": "2.3.0", - "bundled": true, - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" - } - }, - "supports-color": { - "version": "4.5.0", - "bundled": true, - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "@babel/helper-function-name": { - "version": "7.0.0-beta.31", - "bundled": true, - "requires": { - "@babel/helper-get-function-arity": "7.0.0-beta.31", - "@babel/template": "7.0.0-beta.31", - "@babel/traverse": "7.0.0-beta.31", - "@babel/types": "7.0.0-beta.31" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0-beta.31", - "bundled": true, - "requires": { - "@babel/types": "7.0.0-beta.31" - } - }, - "@babel/template": { - "version": "7.0.0-beta.31", - "bundled": true, - "requires": { - "@babel/code-frame": "7.0.0-beta.31", - "@babel/types": "7.0.0-beta.31", - "babylon": "7.0.0-beta.31", - "lodash": "4.17.4" - }, - "dependencies": { - "babylon": { - "version": "7.0.0-beta.31", - "bundled": true - } - } - }, - "@babel/traverse": { - "version": "7.0.0-beta.31", - "bundled": true, - "requires": { - "@babel/code-frame": "7.0.0-beta.31", - "@babel/helper-function-name": "7.0.0-beta.31", - "@babel/types": "7.0.0-beta.31", - "babylon": "7.0.0-beta.31", - "debug": "3.1.0", - "globals": "10.4.0", - "invariant": "2.2.2", - "lodash": "4.17.4" - }, - "dependencies": { - "babylon": { - "version": "7.0.0-beta.31", - "bundled": true - }, - "debug": { - "version": "3.1.0", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "globals": { - "version": "10.4.0", - "bundled": true - } - } - }, - "@babel/types": { - "version": "7.0.0-beta.31", - "bundled": true, - "requires": { - "esutils": "2.0.2", - "lodash": "4.17.4", - "to-fast-properties": "2.0.0" - }, - "dependencies": { - "to-fast-properties": { - "version": "2.0.0", - "bundled": true - } - } - }, - "acorn": { - "version": "5.2.1", - "bundled": true - }, - "acorn-dynamic-import": { - "version": "2.0.2", - "bundled": true, - "requires": { - "acorn": "4.0.13" - }, - "dependencies": { - "acorn": { - "version": "4.0.13", - "bundled": true - } - } - }, - "acorn-jsx": { - "version": "3.0.1", - "bundled": true, - "requires": { - "acorn": "3.3.0" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "bundled": true - } - } - }, - "ajv": { - "version": "5.5.2", - "bundled": true, - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.0.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - }, - "ajv-keywords": { - "version": "2.1.1", - "bundled": true - }, - "align-text": { - "version": "0.1.4", - "bundled": true, - "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" - } - }, - "angular": { - "version": "1.6.8", - "bundled": true - }, - "ansi-escapes": { - "version": "3.0.0", - "bundled": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "ansi-styles": { - "version": "2.2.1", - "bundled": true - }, - "anymatch": { - "version": "1.3.2", - "bundled": true, - "requires": { - "micromatch": "2.3.11", - "normalize-path": "2.1.1" - } - }, - "argparse": { - "version": "1.0.9", - "bundled": true, - "requires": { - "sprintf-js": "1.0.3" - } - }, - "arr-diff": { - "version": "2.0.0", - "bundled": true, - "requires": { - "arr-flatten": "1.1.0" - } - }, - "arr-flatten": { - "version": "1.1.0", - "bundled": true - }, - "array-union": { - "version": "1.0.2", - "bundled": true, - "requires": { - "array-uniq": "1.0.3" - } - }, - "array-uniq": { - "version": "1.0.3", - "bundled": true - }, - "array-unique": { - "version": "0.2.1", - "bundled": true - }, - "arrify": { - "version": "1.0.1", - "bundled": true - }, - "asn1.js": { - "version": "4.9.2", - "bundled": true, - "requires": { - "bn.js": "4.11.8", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.0" - } - }, - "assert": { - "version": "1.4.1", - "bundled": true, - "requires": { - "util": "0.10.3" - } - }, - "assertion-error": { - "version": "1.0.2", - "bundled": true - }, - "async": { - "version": "2.6.0", - "bundled": true, - "requires": { - "lodash": "4.17.4" - } - }, - "async-each": { - "version": "1.0.1", - "bundled": true - }, - "babel-cli": { - "version": "6.26.0", - "bundled": true, - "requires": { - "babel-core": "6.26.0", - "babel-polyfill": "6.26.0", - "babel-register": "6.26.0", - "babel-runtime": "6.26.0", - "chokidar": "1.7.0", - "commander": "2.12.2", - "convert-source-map": "1.5.1", - "fs-readdir-recursive": "1.1.0", - "glob": "7.1.2", - "lodash": "4.17.4", - "output-file-sync": "1.1.2", - "path-is-absolute": "1.0.1", - "slash": "1.0.0", - "source-map": "0.5.7", - "v8flags": "2.1.1" - } - }, - "babel-code-frame": { - "version": "6.26.0", - "bundled": true, - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - } - }, - "babel-core": { - "version": "6.26.0", - "bundled": true, - "requires": { - "babel-code-frame": "6.26.0", - "babel-generator": "6.26.0", - "babel-helpers": "6.24.1", - "babel-messages": "6.23.0", - "babel-register": "6.26.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "convert-source-map": "1.5.1", - "debug": "2.6.9", - "json5": "0.5.1", - "lodash": "4.17.4", - "minimatch": "3.0.4", - "path-is-absolute": "1.0.1", - "private": "0.1.8", - "slash": "1.0.0", - "source-map": "0.5.7" - } - }, - "babel-eslint": { - "version": "8.1.2", - "bundled": true, - "requires": { - "@babel/code-frame": "7.0.0-beta.31", - "@babel/traverse": "7.0.0-beta.31", - "@babel/types": "7.0.0-beta.31", - "babylon": "7.0.0-beta.31", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0" - }, - "dependencies": { - "babylon": { - "version": "7.0.0-beta.31", - "bundled": true - } - } - }, - "babel-generator": { - "version": "6.26.0", - "bundled": true, - "requires": { - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "detect-indent": "4.0.0", - "jsesc": "1.3.0", - "lodash": "4.17.4", - "source-map": "0.5.7", - "trim-right": "1.0.1" - } - }, - "babel-helper-builder-binary-assignment-operator-visitor": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-explode-assignable-expression": "6.24.1", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-hoist-variables": "6.24.1", - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-define-map": { - "version": "6.26.0", - "bundled": true, - "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.4" - } - }, - "babel-helper-explode-assignable-expression": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-function-name": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-get-function-arity": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-regex": { - "version": "6.26.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.4" - } - }, - "babel-helper-remap-async-to-generator": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-optimise-call-expression": "6.24.1", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-helpers": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-loader": { - "version": "7.1.2", - "bundled": true, - "requires": { - "find-cache-dir": "1.0.0", - "loader-utils": "1.1.0", - "mkdirp": "0.5.1" - } - }, - "babel-messages": { - "version": "6.23.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-add-module-exports": { - "version": "0.2.1", - "bundled": true - }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-syntax-async-functions": { - "version": "6.13.0", - "bundled": true - }, - "babel-plugin-syntax-exponentiation-operator": { - "version": "6.13.0", - "bundled": true - }, - "babel-plugin-syntax-trailing-function-commas": { - "version": "6.22.0", - "bundled": true - }, - "babel-plugin-transform-async-to-generator": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-remap-async-to-generator": "6.24.1", - "babel-plugin-syntax-async-functions": "6.13.0", - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "lodash": "4.17.4" - } - }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-define-map": "6.26.0", - "babel-helper-function-name": "6.24.1", - "babel-helper-optimise-call-expression": "6.24.1", - "babel-helper-replace-supers": "6.24.1", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-function-name": "6.24.1", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.0", - "bundled": true, - "requires": { - "babel-plugin-transform-strict-mode": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-hoist-variables": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-plugin-transform-es2015-modules-amd": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" - } - }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-replace-supers": "6.24.1", - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-call-delegate": "6.24.1", - "babel-helper-get-function-arity": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-regex": "6.26.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-regex": "6.26.0", - "babel-runtime": "6.26.0", - "regexpu-core": "2.0.0" - } - }, - "babel-plugin-transform-exponentiation-operator": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-helper-builder-binary-assignment-operator-visitor": "6.24.1", - "babel-plugin-syntax-exponentiation-operator": "6.13.0", - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-regenerator": { - "version": "6.26.0", - "bundled": true, - "requires": { - "regenerator-transform": "0.10.1" - } - }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" - } - }, - "babel-polyfill": { - "version": "6.26.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "core-js": "2.5.3", - "regenerator-runtime": "0.10.5" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.10.5", - "bundled": true - } - } - }, - "babel-preset-env": { - "version": "1.6.1", - "bundled": true, - "requires": { - "babel-plugin-check-es2015-constants": "6.22.0", - "babel-plugin-syntax-trailing-function-commas": "6.22.0", - "babel-plugin-transform-async-to-generator": "6.24.1", - "babel-plugin-transform-es2015-arrow-functions": "6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", - "babel-plugin-transform-es2015-block-scoping": "6.26.0", - "babel-plugin-transform-es2015-classes": "6.24.1", - "babel-plugin-transform-es2015-computed-properties": "6.24.1", - "babel-plugin-transform-es2015-destructuring": "6.23.0", - "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", - "babel-plugin-transform-es2015-for-of": "6.23.0", - "babel-plugin-transform-es2015-function-name": "6.24.1", - "babel-plugin-transform-es2015-literals": "6.22.0", - "babel-plugin-transform-es2015-modules-amd": "6.24.1", - "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", - "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", - "babel-plugin-transform-es2015-modules-umd": "6.24.1", - "babel-plugin-transform-es2015-object-super": "6.24.1", - "babel-plugin-transform-es2015-parameters": "6.24.1", - "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", - "babel-plugin-transform-es2015-spread": "6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "6.24.1", - "babel-plugin-transform-es2015-template-literals": "6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", - "babel-plugin-transform-es2015-unicode-regex": "6.24.1", - "babel-plugin-transform-exponentiation-operator": "6.24.1", - "babel-plugin-transform-regenerator": "6.26.0", - "browserslist": "2.10.0", - "invariant": "2.2.2", - "semver": "5.4.1" - } - }, - "babel-register": { - "version": "6.26.0", - "bundled": true, - "requires": { - "babel-core": "6.26.0", - "babel-runtime": "6.26.0", - "core-js": "2.5.3", - "home-or-tmp": "2.0.0", - "lodash": "4.17.4", - "mkdirp": "0.5.1", - "source-map-support": "0.4.18" - } - }, - "babel-runtime": { - "version": "6.26.0", - "bundled": true, - "requires": { - "core-js": "2.5.3", - "regenerator-runtime": "0.11.1" - } - }, - "babel-template": { - "version": "6.26.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "bundled": true, - "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.2", - "lodash": "4.17.4" - } - }, - "babel-types": { - "version": "6.26.0", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.4", - "to-fast-properties": "1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "bundled": true - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "base64-js": { - "version": "1.2.1", - "bundled": true - }, - "big.js": { - "version": "3.2.0", - "bundled": true - }, - "binary-extensions": { - "version": "1.11.0", - "bundled": true - }, - "bn.js": { - "version": "4.11.8", - "bundled": true - }, - "brace-expansion": { - "version": "1.1.8", - "bundled": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "1.8.5", - "bundled": true, - "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.2" - } - }, - "brorand": { - "version": "1.1.0", - "bundled": true - }, - "browser-stdout": { - "version": "1.3.0", - "bundled": true - }, - "browserify-aes": { - "version": "1.1.1", - "bundled": true, - "requires": { - "buffer-xor": "1.0.3", - "cipher-base": "1.0.4", - "create-hash": "1.1.3", - "evp_bytestokey": "1.0.3", - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - }, - "browserify-cipher": { - "version": "1.0.0", - "bundled": true, - "requires": { - "browserify-aes": "1.1.1", - "browserify-des": "1.0.0", - "evp_bytestokey": "1.0.3" - } - }, - "browserify-des": { - "version": "1.0.0", - "bundled": true, - "requires": { - "cipher-base": "1.0.4", - "des.js": "1.0.0", - "inherits": "2.0.3" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "bundled": true, - "requires": { - "bn.js": "4.11.8", - "randombytes": "2.0.5" - } - }, - "browserify-sign": { - "version": "4.0.4", - "bundled": true, - "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.1.3", - "create-hmac": "1.1.6", - "elliptic": "6.4.0", - "inherits": "2.0.3", - "parse-asn1": "5.1.0" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "bundled": true, - "requires": { - "pako": "1.0.6" - } - }, - "browserslist": { - "version": "2.10.0", - "bundled": true, - "requires": { - "caniuse-lite": "1.0.30000784", - "electron-to-chromium": "1.3.30" - } - }, - "buffer": { - "version": "4.9.1", - "bundled": true, - "requires": { - "base64-js": "1.2.1", - "ieee754": "1.1.8", - "isarray": "1.0.0" - } - }, - "buffer-xor": { - "version": "1.0.3", - "bundled": true - }, - "builtin-modules": { - "version": "1.1.1", - "bundled": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "bundled": true - }, - "caller-path": { - "version": "0.1.0", - "bundled": true, - "requires": { - "callsites": "0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "bundled": true - }, - "camelcase": { - "version": "1.2.1", - "bundled": true - }, - "caniuse-lite": { - "version": "1.0.30000784", - "bundled": true - }, - "center-align": { - "version": "0.1.3", - "bundled": true, - "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" - } - }, - "chai": { - "version": "4.1.2", - "bundled": true, - "requires": { - "assertion-error": "1.0.2", - "check-error": "1.0.2", - "deep-eql": "3.0.1", - "get-func-name": "2.0.0", - "pathval": "1.1.0", - "type-detect": "4.0.5" - } - }, - "chalk": { - "version": "1.1.3", - "bundled": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "chardet": { - "version": "0.4.2", - "bundled": true - }, - "check-error": { - "version": "1.0.2", - "bundled": true - }, - "chokidar": { - "version": "1.7.0", - "bundled": true, - "requires": { - "anymatch": "1.3.2", - "async-each": "1.0.1", - "fsevents": "1.1.3", - "glob-parent": "2.0.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "2.0.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.1.0" - } - }, - "cipher-base": { - "version": "1.0.4", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - }, - "circular-json": { - "version": "0.3.3", - "bundled": true - }, - "cli-cursor": { - "version": "2.1.0", - "bundled": true, - "requires": { - "restore-cursor": "2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "bundled": true - }, - "cliui": { - "version": "2.1.0", - "bundled": true, - "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", - "wordwrap": "0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.2", - "bundled": true - } - } - }, - "co": { - "version": "4.6.0", - "bundled": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "color-convert": { - "version": "1.9.1", - "bundled": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "bundled": true - }, - "commander": { - "version": "2.12.2", - "bundled": true - }, - "commondir": { - "version": "1.0.1", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "concat-stream": { - "version": "1.6.0", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "typedarray": "0.0.6" - } - }, - "console-browserify": { - "version": "1.1.0", - "bundled": true, - "requires": { - "date-now": "0.1.4" - } - }, - "constants-browserify": { - "version": "1.0.0", - "bundled": true - }, - "convert-source-map": { - "version": "1.5.1", - "bundled": true - }, - "core-js": { - "version": "2.5.3", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "create-ecdh": { - "version": "4.0.0", - "bundled": true, - "requires": { - "bn.js": "4.11.8", - "elliptic": "6.4.0" - } - }, - "create-hash": { - "version": "1.1.3", - "bundled": true, - "requires": { - "cipher-base": "1.0.4", - "inherits": "2.0.3", - "ripemd160": "2.0.1", - "sha.js": "2.4.9" - } - }, - "create-hmac": { - "version": "1.1.6", - "bundled": true, - "requires": { - "cipher-base": "1.0.4", - "create-hash": "1.1.3", - "inherits": "2.0.3", - "ripemd160": "2.0.1", - "safe-buffer": "5.1.1", - "sha.js": "2.4.9" - } - }, - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" - } - }, - "crypto-browserify": { - "version": "3.12.0", - "bundled": true, - "requires": { - "browserify-cipher": "1.0.0", - "browserify-sign": "4.0.4", - "create-ecdh": "4.0.0", - "create-hash": "1.1.3", - "create-hmac": "1.1.6", - "diffie-hellman": "5.0.2", - "inherits": "2.0.3", - "pbkdf2": "3.0.14", - "public-encrypt": "4.0.0", - "randombytes": "2.0.5", - "randomfill": "1.0.3" - } - }, - "d": { - "version": "1.0.0", - "bundled": true, - "requires": { - "es5-ext": "0.10.37" - } - }, - "date-now": { - "version": "0.1.4", - "bundled": true - }, - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "bundled": true - }, - "deep-eql": { - "version": "3.0.1", - "bundled": true, - "requires": { - "type-detect": "4.0.5" - } - }, - "deep-is": { - "version": "0.1.3", - "bundled": true - }, - "del": { - "version": "2.2.2", - "bundled": true, - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.0", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "bundled": true - } - } - }, - "des.js": { - "version": "1.0.0", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.0" - } - }, - "detect-indent": { - "version": "4.0.0", - "bundled": true, - "requires": { - "repeating": "2.0.1" - } - }, - "diff": { - "version": "3.3.1", - "bundled": true - }, - "diffie-hellman": { - "version": "5.0.2", - "bundled": true, - "requires": { - "bn.js": "4.11.8", - "miller-rabin": "4.0.1", - "randombytes": "2.0.5" - } - }, - "doctrine": { - "version": "2.0.2", - "bundled": true, - "requires": { - "esutils": "2.0.2" - } - }, - "domain-browser": { - "version": "1.1.7", - "bundled": true - }, - "electron-releases": { - "version": "2.1.0", - "bundled": true - }, - "electron-to-chromium": { - "version": "1.3.30", - "bundled": true, - "requires": { - "electron-releases": "2.1.0" - } - }, - "elliptic": { - "version": "6.4.0", - "bundled": true, - "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0", - "hash.js": "1.1.3", - "hmac-drbg": "1.0.1", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.0", - "minimalistic-crypto-utils": "1.0.1" - } - }, - "emojis-list": { - "version": "2.1.0", - "bundled": true - }, - "enhanced-resolve": { - "version": "3.4.1", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "memory-fs": "0.4.1", - "object-assign": "4.1.1", - "tapable": "0.2.8" - } - }, - "errno": { - "version": "0.1.6", - "bundled": true, - "requires": { - "prr": "1.0.1" - } - }, - "error-ex": { - "version": "1.3.1", - "bundled": true, - "requires": { - "is-arrayish": "0.2.1" - } - }, - "es5-ext": { - "version": "0.10.37", - "bundled": true, - "requires": { - "es6-iterator": "2.0.3", - "es6-symbol": "3.1.1" - } - }, - "es6-iterator": { - "version": "2.0.3", - "bundled": true, - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.37", - "es6-symbol": "3.1.1" - } - }, - "es6-map": { - "version": "0.1.5", - "bundled": true, - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.37", - "es6-iterator": "2.0.3", - "es6-set": "0.1.5", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" - } - }, - "es6-set": { - "version": "0.1.5", - "bundled": true, - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.37", - "es6-iterator": "2.0.3", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" - } - }, - "es6-symbol": { - "version": "3.1.1", - "bundled": true, - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.37" - } - }, - "es6-weak-map": { - "version": "2.0.2", - "bundled": true, - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.37", - "es6-iterator": "2.0.3", - "es6-symbol": "3.1.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true - }, - "escope": { - "version": "3.6.0", - "bundled": true, - "requires": { - "es6-map": "0.1.5", - "es6-weak-map": "2.0.2", - "esrecurse": "4.2.0", - "estraverse": "4.2.0" - } - }, - "eslint": { - "version": "4.14.0", - "bundled": true, - "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.3.0", - "concat-stream": "1.6.0", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.0.2", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.2", - "esquery": "1.0.0", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.1.0", - "ignore": "3.3.7", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.0.1", - "js-yaml": "3.10.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.4", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "require-uncached": "1.0.3", - "semver": "5.4.1", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "4.0.2", - "text-table": "0.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true - }, - "ansi-styles": { - "version": "3.2.0", - "bundled": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "chalk": { - "version": "2.3.0", - "bundled": true, - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" - } - }, - "debug": { - "version": "3.1.0", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "globals": { - "version": "11.1.0", - "bundled": true - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "requires": { - "ansi-regex": "3.0.0" - } - }, - "supports-color": { - "version": "4.5.0", - "bundled": true, - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "eslint-loader": { - "version": "1.9.0", - "bundled": true, - "requires": { - "loader-fs-cache": "1.0.1", - "loader-utils": "1.1.0", - "object-assign": "4.1.1", - "object-hash": "1.2.0", - "rimraf": "2.6.2" - } - }, - "eslint-scope": { - "version": "3.7.1", - "bundled": true, - "requires": { - "esrecurse": "4.2.0", - "estraverse": "4.2.0" - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "bundled": true - }, - "espree": { - "version": "3.5.2", - "bundled": true, - "requires": { - "acorn": "5.2.1", - "acorn-jsx": "3.0.1" - } - }, - "esprima": { - "version": "4.0.0", - "bundled": true - }, - "esquery": { - "version": "1.0.0", - "bundled": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "esrecurse": { - "version": "4.2.0", - "bundled": true, - "requires": { - "estraverse": "4.2.0", - "object-assign": "4.1.1" - } - }, - "estraverse": { - "version": "4.2.0", - "bundled": true - }, - "esutils": { - "version": "2.0.2", - "bundled": true - }, - "event-emitter": { - "version": "0.3.5", - "bundled": true, - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.37" - } - }, - "events": { - "version": "1.1.1", - "bundled": true - }, - "evp_bytestokey": { - "version": "1.0.3", - "bundled": true, - "requires": { - "md5.js": "1.3.4", - "safe-buffer": "5.1.1" - } - }, - "execa": { - "version": "0.7.0", - "bundled": true, - "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" - } - }, - "expand-brackets": { - "version": "0.1.5", - "bundled": true, - "requires": { - "is-posix-bracket": "0.1.1" - } - }, - "expand-range": { - "version": "1.8.2", - "bundled": true, - "requires": { - "fill-range": "2.2.3" - } - }, - "external-editor": { - "version": "2.1.0", - "bundled": true, - "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.19", - "tmp": "0.0.33" - } - }, - "extglob": { - "version": "0.3.2", - "bundled": true, - "requires": { - "is-extglob": "1.0.0" - } - }, - "fast-deep-equal": { - "version": "1.0.0", - "bundled": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "bundled": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "bundled": true - }, - "figures": { - "version": "2.0.0", - "bundled": true, - "requires": { - "escape-string-regexp": "1.0.5" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "bundled": true, - "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" - } - }, - "filename-regex": { - "version": "2.0.1", - "bundled": true - }, - "fill-range": { - "version": "2.2.3", - "bundled": true, - "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "1.1.7", - "repeat-element": "1.1.2", - "repeat-string": "1.6.1" - } - }, - "find-cache-dir": { - "version": "1.0.0", - "bundled": true, - "requires": { - "commondir": "1.0.1", - "make-dir": "1.1.0", - "pkg-dir": "2.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "bundled": true, - "requires": { - "locate-path": "2.0.0" - } - }, - "flat-cache": { - "version": "1.3.0", - "bundled": true, - "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - } - }, - "for-in": { - "version": "1.0.2", - "bundled": true - }, - "for-own": { - "version": "0.1.5", - "bundled": true, - "requires": { - "for-in": "1.0.2" - } - }, - "fs-readdir-recursive": { - "version": "1.1.0", - "bundled": true - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "fsevents": { - "version": "1.1.3", - "bundled": true, - "optional": true, - "requires": { - "nan": "2.8.0", - "node-pre-gyp": "0.6.39" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.39", - "bundled": true, - "optional": true, - "requires": { - "detect-libc": "1.0.2", - "hawk": "3.1.3", - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "optional": true, - "requires": { - "string-width": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - } - } - }, - "functional-red-black-tree": { - "version": "1.0.1", - "bundled": true - }, - "get-caller-file": { - "version": "1.0.2", - "bundled": true - }, - "get-func-name": { - "version": "2.0.0", - "bundled": true - }, - "get-stream": { - "version": "3.0.0", - "bundled": true - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "glob-base": { - "version": "0.3.0", - "bundled": true, - "requires": { - "glob-parent": "2.0.0", - "is-glob": "2.0.1" - } - }, - "glob-parent": { - "version": "2.0.0", - "bundled": true, - "requires": { - "is-glob": "2.0.1" - } - }, - "globals": { - "version": "9.18.0", - "bundled": true - }, - "globby": { - "version": "5.0.0", - "bundled": true, - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "bundled": true - } - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "growl": { - "version": "1.10.3", - "bundled": true - }, - "has-ansi": { - "version": "2.0.0", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "has-flag": { - "version": "2.0.0", - "bundled": true - }, - "hash-base": { - "version": "2.0.2", - "bundled": true, - "requires": { - "inherits": "2.0.3" - } - }, - "hash.js": { - "version": "1.1.3", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.0" - } - }, - "he": { - "version": "1.1.1", - "bundled": true - }, - "hmac-drbg": { - "version": "1.0.1", - "bundled": true, - "requires": { - "hash.js": "1.1.3", - "minimalistic-assert": "1.0.0", - "minimalistic-crypto-utils": "1.0.1" - } - }, - "home-or-tmp": { - "version": "2.0.0", - "bundled": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "hosted-git-info": { - "version": "2.5.0", - "bundled": true - }, - "https-browserify": { - "version": "1.0.0", - "bundled": true - }, - "iconv-lite": { - "version": "0.4.19", - "bundled": true - }, - "ieee754": { - "version": "1.1.8", - "bundled": true - }, - "ignore": { - "version": "3.3.7", - "bundled": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true - }, - "indexof": { - "version": "0.0.1", - "bundled": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "inquirer": { - "version": "3.3.0", - "bundled": true, - "requires": { - "ansi-escapes": "3.0.0", - "chalk": "2.3.0", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.1.0", - "figures": "2.0.0", - "lodash": "4.17.4", - "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true - }, - "ansi-styles": { - "version": "3.2.0", - "bundled": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "chalk": { - "version": "2.3.0", - "bundled": true, - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "requires": { - "ansi-regex": "3.0.0" - } - }, - "supports-color": { - "version": "4.5.0", - "bundled": true, - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "interpret": { - "version": "1.1.0", - "bundled": true - }, - "invariant": { - "version": "2.2.2", - "bundled": true, - "requires": { - "loose-envify": "1.3.1" - } - }, - "invert-kv": { - "version": "1.0.0", - "bundled": true - }, - "is-arrayish": { - "version": "0.2.1", - "bundled": true - }, - "is-binary-path": { - "version": "1.0.1", - "bundled": true, - "requires": { - "binary-extensions": "1.11.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "bundled": true - }, - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "requires": { - "builtin-modules": "1.1.1" - } - }, - "is-dotfile": { - "version": "1.0.3", - "bundled": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "bundled": true, - "requires": { - "is-primitive": "2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "bundled": true - }, - "is-extglob": { - "version": "1.0.0", - "bundled": true - }, - "is-finite": { - "version": "1.0.2", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true - }, - "is-glob": { - "version": "2.0.1", - "bundled": true, - "requires": { - "is-extglob": "1.0.0" - } - }, - "is-number": { - "version": "2.1.0", - "bundled": true, - "requires": { - "kind-of": "3.2.2" - } - }, - "is-path-cwd": { - "version": "1.0.0", - "bundled": true - }, - "is-path-in-cwd": { - "version": "1.0.0", - "bundled": true, - "requires": { - "is-path-inside": "1.0.1" - } - }, - "is-path-inside": { - "version": "1.0.1", - "bundled": true, - "requires": { - "path-is-inside": "1.0.2" - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "bundled": true - }, - "is-primitive": { - "version": "2.0.0", - "bundled": true - }, - "is-promise": { - "version": "2.1.0", - "bundled": true - }, - "is-resolvable": { - "version": "1.0.1", - "bundled": true - }, - "is-stream": { - "version": "1.1.0", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true - }, - "isobject": { - "version": "2.1.0", - "bundled": true, - "requires": { - "isarray": "1.0.0" - } - }, - "js-tokens": { - "version": "3.0.2", - "bundled": true - }, - "js-yaml": { - "version": "3.10.0", - "bundled": true, - "requires": { - "argparse": "1.0.9", - "esprima": "4.0.0" - } - }, - "jsesc": { - "version": "1.3.0", - "bundled": true - }, - "json-loader": { - "version": "0.5.7", - "bundled": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "bundled": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "bundled": true - }, - "json5": { - "version": "0.5.1", - "bundled": true - }, - "kind-of": { - "version": "3.2.2", - "bundled": true, - "requires": { - "is-buffer": "1.1.6" - } - }, - "lazy-cache": { - "version": "1.0.4", - "bundled": true - }, - "lcid": { - "version": "1.0.0", - "bundled": true, - "requires": { - "invert-kv": "1.0.0" - } - }, - "levn": { - "version": "0.3.0", - "bundled": true, - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - } - }, - "load-json-file": { - "version": "2.0.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "bundled": true - } - } - }, - "loader-fs-cache": { - "version": "1.0.1", - "bundled": true, - "requires": { - "find-cache-dir": "0.1.1", - "mkdirp": "0.5.1" - }, - "dependencies": { - "find-cache-dir": { - "version": "0.1.1", - "bundled": true, - "requires": { - "commondir": "1.0.1", - "mkdirp": "0.5.1", - "pkg-dir": "1.0.0" - } - }, - "find-up": { - "version": "1.1.2", - "bundled": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "path-exists": { - "version": "2.1.0", - "bundled": true, - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "pkg-dir": { - "version": "1.0.0", - "bundled": true, - "requires": { - "find-up": "1.1.2" - } - } - } - }, - "loader-runner": { - "version": "2.3.0", - "bundled": true - }, - "loader-utils": { - "version": "1.1.0", - "bundled": true, - "requires": { - "big.js": "3.2.0", - "emojis-list": "2.1.0", - "json5": "0.5.1" - } - }, - "locate-path": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - } - }, - "lodash": { - "version": "4.17.4", - "bundled": true - }, - "longest": { - "version": "1.0.1", - "bundled": true - }, - "loose-envify": { - "version": "1.3.1", - "bundled": true, - "requires": { - "js-tokens": "3.0.2" - } - }, - "lru-cache": { - "version": "4.1.1", - "bundled": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - }, - "make-dir": { - "version": "1.1.0", - "bundled": true, - "requires": { - "pify": "3.0.0" - } - }, - "md5.js": { - "version": "1.3.4", - "bundled": true, - "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.3" - }, - "dependencies": { - "hash-base": { - "version": "3.0.4", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - } - } - }, - "mem": { - "version": "1.1.0", - "bundled": true, - "requires": { - "mimic-fn": "1.1.0" - } - }, - "memory-fs": { - "version": "0.4.1", - "bundled": true, - "requires": { - "errno": "0.1.6", - "readable-stream": "2.3.3" - } - }, - "micromatch": { - "version": "2.3.11", - "bundled": true, - "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" - } - }, - "miller-rabin": { - "version": "4.0.1", - "bundled": true, - "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0" - } - }, - "mimic-fn": { - "version": "1.1.0", - "bundled": true - }, - "minimalistic-assert": { - "version": "1.0.0", - "bundled": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "bundled": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.8" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "mocha": { - "version": "4.0.1", - "bundled": true, - "requires": { - "browser-stdout": "1.3.0", - "commander": "2.11.0", - "debug": "3.1.0", - "diff": "3.3.1", - "escape-string-regexp": "1.0.5", - "glob": "7.1.2", - "growl": "1.10.3", - "he": "1.1.1", - "mkdirp": "0.5.1", - "supports-color": "4.4.0" - }, - "dependencies": { - "commander": { - "version": "2.11.0", - "bundled": true - }, - "debug": { - "version": "3.1.0", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "supports-color": { - "version": "4.4.0", - "bundled": true, - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "ms": { - "version": "2.0.0", - "bundled": true - }, - "mute-stream": { - "version": "0.0.7", - "bundled": true - }, - "nan": { - "version": "2.8.0", - "bundled": true, - "optional": true - }, - "natural-compare": { - "version": "1.4.0", - "bundled": true - }, - "node-libs-browser": { - "version": "2.1.0", - "bundled": true, - "requires": { - "assert": "1.4.1", - "browserify-zlib": "0.2.0", - "buffer": "4.9.1", - "console-browserify": "1.1.0", - "constants-browserify": "1.0.0", - "crypto-browserify": "3.12.0", - "domain-browser": "1.1.7", - "events": "1.1.1", - "https-browserify": "1.0.0", - "os-browserify": "0.3.0", - "path-browserify": "0.0.0", - "process": "0.11.10", - "punycode": "1.4.1", - "querystring-es3": "0.2.1", - "readable-stream": "2.3.3", - "stream-browserify": "2.0.1", - "stream-http": "2.7.2", - "string_decoder": "1.0.3", - "timers-browserify": "2.0.4", - "tty-browserify": "0.0.0", - "url": "0.11.0", - "util": "0.10.3", - "vm-browserify": "0.0.4" - } - }, - "normalize-package-data": { - "version": "2.4.0", - "bundled": true, - "requires": { - "hosted-git-info": "2.5.0", - "is-builtin-module": "1.0.0", - "semver": "5.4.1", - "validate-npm-package-license": "3.0.1" - } - }, - "normalize-path": { - "version": "2.1.1", - "bundled": true, - "requires": { - "remove-trailing-separator": "1.1.0" - } - }, - "npm-run-path": { - "version": "2.0.2", - "bundled": true, - "requires": { - "path-key": "2.0.1" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true - }, - "object-hash": { - "version": "1.2.0", - "bundled": true - }, - "object.omit": { - "version": "2.0.1", - "bundled": true, - "requires": { - "for-own": "0.1.5", - "is-extendable": "0.1.1" - } - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "onetime": { - "version": "2.0.1", - "bundled": true, - "requires": { - "mimic-fn": "1.1.0" - } - }, - "optionator": { - "version": "0.8.2", - "bundled": true, - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - } - }, - "os-browserify": { - "version": "0.3.0", - "bundled": true - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true - }, - "os-locale": { - "version": "2.1.0", - "bundled": true, - "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true - }, - "output-file-sync": { - "version": "1.1.2", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "mkdirp": "0.5.1", - "object-assign": "4.1.1" - } - }, - "p-finally": { - "version": "1.0.0", - "bundled": true - }, - "p-limit": { - "version": "1.1.0", - "bundled": true - }, - "p-locate": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-limit": "1.1.0" - } - }, - "pako": { - "version": "1.0.6", - "bundled": true - }, - "parse-asn1": { - "version": "5.1.0", - "bundled": true, - "requires": { - "asn1.js": "4.9.2", - "browserify-aes": "1.1.1", - "create-hash": "1.1.3", - "evp_bytestokey": "1.0.3", - "pbkdf2": "3.0.14" - } - }, - "parse-glob": { - "version": "3.0.4", - "bundled": true, - "requires": { - "glob-base": "0.3.0", - "is-dotfile": "1.0.3", - "is-extglob": "1.0.0", - "is-glob": "2.0.1" - } - }, - "parse-json": { - "version": "2.2.0", - "bundled": true, - "requires": { - "error-ex": "1.3.1" - } - }, - "path-browserify": { - "version": "0.0.0", - "bundled": true - }, - "path-exists": { - "version": "3.0.0", - "bundled": true - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "path-is-inside": { - "version": "1.0.2", - "bundled": true - }, - "path-key": { - "version": "2.0.1", - "bundled": true - }, - "path-type": { - "version": "2.0.0", - "bundled": true, - "requires": { - "pify": "2.3.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "bundled": true - } - } - }, - "pathval": { - "version": "1.1.0", - "bundled": true - }, - "pbkdf2": { - "version": "3.0.14", - "bundled": true, - "requires": { - "create-hash": "1.1.3", - "create-hmac": "1.1.6", - "ripemd160": "2.0.1", - "safe-buffer": "5.1.1", - "sha.js": "2.4.9" - } - }, - "pify": { - "version": "3.0.0", - "bundled": true - }, - "pinkie": { - "version": "2.0.4", - "bundled": true - }, - "pinkie-promise": { - "version": "2.0.1", - "bundled": true, - "requires": { - "pinkie": "2.0.4" - } - }, - "pkg-dir": { - "version": "2.0.0", - "bundled": true, - "requires": { - "find-up": "2.1.0" - } - }, - "pluralize": { - "version": "7.0.0", - "bundled": true - }, - "prelude-ls": { - "version": "1.1.2", - "bundled": true - }, - "preserve": { - "version": "0.2.0", - "bundled": true - }, - "private": { - "version": "0.1.8", - "bundled": true - }, - "process": { - "version": "0.11.10", - "bundled": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "progress": { - "version": "2.0.0", - "bundled": true - }, - "prr": { - "version": "1.0.1", - "bundled": true - }, - "pseudomap": { - "version": "1.0.2", - "bundled": true - }, - "public-encrypt": { - "version": "4.0.0", - "bundled": true, - "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.1.3", - "parse-asn1": "5.1.0", - "randombytes": "2.0.5" - } - }, - "punycode": { - "version": "1.4.1", - "bundled": true - }, - "querystring": { - "version": "0.2.0", - "bundled": true - }, - "querystring-es3": { - "version": "0.2.1", - "bundled": true - }, - "randomatic": { - "version": "1.1.7", - "bundled": true, - "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "bundled": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "bundled": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "randombytes": { - "version": "2.0.5", - "bundled": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "randomfill": { - "version": "1.0.3", - "bundled": true, - "requires": { - "randombytes": "2.0.5", - "safe-buffer": "5.1.1" - } - }, - "read-pkg": { - "version": "2.0.0", - "bundled": true, - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "bundled": true, - "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" - } - }, - "readable-stream": { - "version": "2.3.3", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" - } - }, - "readdirp": { - "version": "2.1.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "minimatch": "3.0.4", - "readable-stream": "2.3.3", - "set-immediate-shim": "1.0.1" - } - }, - "regenerate": { - "version": "1.3.3", - "bundled": true - }, - "regenerator-runtime": { - "version": "0.11.1", - "bundled": true - }, - "regenerator-transform": { - "version": "0.10.1", - "bundled": true, - "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "private": "0.1.8" - } - }, - "regex-cache": { - "version": "0.4.4", - "bundled": true, - "requires": { - "is-equal-shallow": "0.1.3" - } - }, - "regexpu-core": { - "version": "2.0.0", - "bundled": true, - "requires": { - "regenerate": "1.3.3", - "regjsgen": "0.2.0", - "regjsparser": "0.1.5" - } - }, - "regjsgen": { - "version": "0.2.0", - "bundled": true - }, - "regjsparser": { - "version": "0.1.5", - "bundled": true, - "requires": { - "jsesc": "0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "bundled": true - } - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "bundled": true - }, - "repeat-element": { - "version": "1.1.2", - "bundled": true - }, - "repeat-string": { - "version": "1.6.1", - "bundled": true - }, - "repeating": { - "version": "2.0.1", - "bundled": true, - "requires": { - "is-finite": "1.0.2" - } - }, - "require-directory": { - "version": "2.1.1", - "bundled": true - }, - "require-main-filename": { - "version": "1.0.1", - "bundled": true - }, - "require-uncached": { - "version": "1.0.3", - "bundled": true, - "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" - } - }, - "resolve-from": { - "version": "1.0.1", - "bundled": true - }, - "restore-cursor": { - "version": "2.0.0", - "bundled": true, - "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" - } - }, - "right-align": { - "version": "0.1.3", - "bundled": true, - "requires": { - "align-text": "0.1.4" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "requires": { - "glob": "7.1.2" - } - }, - "ripemd160": { - "version": "2.0.1", - "bundled": true, - "requires": { - "hash-base": "2.0.2", - "inherits": "2.0.3" - } - }, - "run-async": { - "version": "2.3.0", - "bundled": true, - "requires": { - "is-promise": "2.1.0" - } - }, - "rx-lite": { - "version": "4.0.8", - "bundled": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "bundled": true, - "requires": { - "rx-lite": "4.0.8" - } - }, - "safe-buffer": { - "version": "5.1.1", - "bundled": true - }, - "semver": { - "version": "5.4.1", - "bundled": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true - }, - "set-immediate-shim": { - "version": "1.0.1", - "bundled": true - }, - "setimmediate": { - "version": "1.0.5", - "bundled": true - }, - "sha.js": { - "version": "2.4.9", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "requires": { - "shebang-regex": "1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true - }, - "slash": { - "version": "1.0.0", - "bundled": true - }, - "slice-ansi": { - "version": "1.0.0", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0" - } - }, - "source-list-map": { - "version": "2.0.0", - "bundled": true - }, - "source-map": { - "version": "0.5.7", - "bundled": true - }, - "source-map-support": { - "version": "0.4.18", - "bundled": true, - "requires": { - "source-map": "0.5.7" - } - }, - "spdx-correct": { - "version": "1.0.2", - "bundled": true, - "requires": { - "spdx-license-ids": "1.2.2" - } - }, - "spdx-expression-parse": { - "version": "1.0.4", - "bundled": true - }, - "spdx-license-ids": { - "version": "1.2.2", - "bundled": true - }, - "sprintf-js": { - "version": "1.0.3", - "bundled": true - }, - "stream-browserify": { - "version": "2.0.1", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3" - } - }, - "stream-http": { - "version": "2.7.2", - "bundled": true, - "requires": { - "builtin-status-codes": "3.0.0", - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "to-arraybuffer": "1.0.1", - "xtend": "4.0.1" - } - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "requires": { - "ansi-regex": "3.0.0" - } - } - } - }, - "string_decoder": { - "version": "1.0.3", - "bundled": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-bom": { - "version": "3.0.0", - "bundled": true - }, - "strip-eof": { - "version": "1.0.0", - "bundled": true - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true - }, - "supports-color": { - "version": "2.0.0", - "bundled": true - }, - "table": { - "version": "4.0.2", - "bundled": true, - "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.3.0", - "lodash": "4.17.4", - "slice-ansi": "1.0.0", - "string-width": "2.1.1" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.0", - "bundled": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "chalk": { - "version": "2.3.0", - "bundled": true, - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" - } - }, - "supports-color": { - "version": "4.5.0", - "bundled": true, - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "tapable": { - "version": "0.2.8", - "bundled": true - }, - "text-table": { - "version": "0.2.0", - "bundled": true - }, - "through": { - "version": "2.3.8", - "bundled": true - }, - "timers-browserify": { - "version": "2.0.4", - "bundled": true, - "requires": { - "setimmediate": "1.0.5" - } - }, - "tmp": { - "version": "0.0.33", - "bundled": true, - "requires": { - "os-tmpdir": "1.0.2" - } - }, - "to-arraybuffer": { - "version": "1.0.1", - "bundled": true - }, - "to-fast-properties": { - "version": "1.0.3", - "bundled": true - }, - "trim-right": { - "version": "1.0.1", - "bundled": true - }, - "tty-browserify": { - "version": "0.0.0", - "bundled": true - }, - "type-check": { - "version": "0.3.2", - "bundled": true, - "requires": { - "prelude-ls": "1.1.2" - } - }, - "type-detect": { - "version": "4.0.5", - "bundled": true - }, - "typedarray": { - "version": "0.0.6", - "bundled": true - }, - "uglify-js": { - "version": "2.8.29", - "bundled": true, - "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" - }, - "dependencies": { - "yargs": { - "version": "3.10.0", - "bundled": true, - "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", - "window-size": "0.1.0" - } - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "uglifyjs-webpack-plugin": { - "version": "0.4.6", - "bundled": true, - "requires": { - "source-map": "0.5.7", - "uglify-js": "2.8.29", - "webpack-sources": "1.1.0" - } - }, - "url": { - "version": "0.11.0", - "bundled": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "bundled": true - } - } - }, - "user-home": { - "version": "1.1.1", - "bundled": true - }, - "util": { - "version": "0.10.3", - "bundled": true, - "requires": { - "inherits": "2.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "bundled": true - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "v8flags": { - "version": "2.1.1", - "bundled": true, - "requires": { - "user-home": "1.1.1" - } - }, - "validate-npm-package-license": { - "version": "3.0.1", - "bundled": true, - "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.4" - } - }, - "vm-browserify": { - "version": "0.0.4", - "bundled": true, - "requires": { - "indexof": "0.0.1" - } - }, - "watchpack": { - "version": "1.4.0", - "bundled": true, - "requires": { - "async": "2.6.0", - "chokidar": "1.7.0", - "graceful-fs": "4.1.11" - } - }, - "webpack": { - "version": "3.10.0", - "bundled": true, - "requires": { - "acorn": "5.2.1", - "acorn-dynamic-import": "2.0.2", - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "async": "2.6.0", - "enhanced-resolve": "3.4.1", - "escope": "3.6.0", - "interpret": "1.1.0", - "json-loader": "0.5.7", - "json5": "0.5.1", - "loader-runner": "2.3.0", - "loader-utils": "1.1.0", - "memory-fs": "0.4.1", - "mkdirp": "0.5.1", - "node-libs-browser": "2.1.0", - "source-map": "0.5.7", - "supports-color": "4.5.0", - "tapable": "0.2.8", - "uglifyjs-webpack-plugin": "0.4.6", - "watchpack": "1.4.0", - "webpack-sources": "1.1.0", - "yargs": "8.0.2" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "bundled": true - }, - "cliui": { - "version": "3.2.0", - "bundled": true, - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - } - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "supports-color": { - "version": "4.5.0", - "bundled": true, - "requires": { - "has-flag": "2.0.0" - } - }, - "yargs": { - "version": "8.0.2", - "bundled": true, - "requires": { - "camelcase": "4.1.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "read-pkg-up": "2.0.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "7.0.0" - } - } - } - }, - "webpack-sources": { - "version": "1.1.0", - "bundled": true, - "requires": { - "source-list-map": "2.0.0", - "source-map": "0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "bundled": true - } - } - }, - "which": { - "version": "1.3.0", - "bundled": true, - "requires": { - "isexe": "2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "bundled": true - }, - "window-size": { - "version": "0.1.0", - "bundled": true - }, - "wordwrap": { - "version": "1.0.0", - "bundled": true - }, - "wrap-ansi": { - "version": "2.1.0", - "bundled": true, - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "write": { - "version": "0.2.1", - "bundled": true, - "requires": { - "mkdirp": "0.5.1" - } - }, - "xtend": { - "version": "4.0.1", - "bundled": true - }, - "y18n": { - "version": "3.2.1", - "bundled": true - }, - "yallist": { - "version": "2.1.2", - "bundled": true - }, - "yargs": { - "version": "10.0.3", - "bundled": true, - "requires": { - "cliui": "3.2.0", - "decamelize": "1.2.0", - "find-up": "2.1.0", - "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "8.1.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "bundled": true - }, - "cliui": { - "version": "3.2.0", - "bundled": true, - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - } - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "yargs-parser": { - "version": "8.1.0", - "bundled": true, - "requires": { - "camelcase": "4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "7.0.0", - "bundled": true, - "requires": { - "camelcase": "4.1.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "bundled": true - } - } - } - } - } - } -} diff --git a/project/plugins.sbt b/project/plugins.sbt index 5c35a4bb3..e6f947ee0 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,8 +2,6 @@ logLevel := Level.Info // The Play plugin -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.21") - -addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.1") - -addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.8.2") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.22") +addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.1") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.0.0") \ No newline at end of file From 6c7ba25d019dd2795fe9feda2286950d609440d5 Mon Sep 17 00:00:00 2001 From: To-om Date: Fri, 24 May 2019 10:18:56 +0200 Subject: [PATCH 07/17] Update elastic4play to solve updates --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 147b2bbfa..b83aaf6bd 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -18,7 +18,7 @@ object Dependencies { val reflections = "org.reflections" % "reflections" % "0.9.11" val zip4j = "net.lingala.zip4j" % "zip4j" % "1.3.2" - val elastic4play = "org.thehive-project" %% "elastic4play" % "1.11.1" + val elastic4play = "org.thehive-project" %% "elastic4play" % "1.11.2" val dockerClient = "com.spotify" % "docker-client" % "8.14.4" } From 199bbf3b5a289284af70b92e3cc7abbe25411c3f Mon Sep 17 00:00:00 2001 From: To-om Date: Mon, 27 May 2019 15:54:14 +0200 Subject: [PATCH 08/17] Update elastic4play and playframework --- app/org/thp/cortex/controllers/JobCtrl.scala | 21 +++++++++++--------- project/Dependencies.scala | 2 +- project/plugins.sbt | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/app/org/thp/cortex/controllers/JobCtrl.scala b/app/org/thp/cortex/controllers/JobCtrl.scala index 40e0b349a..a9521526d 100644 --- a/app/org/thp/cortex/controllers/JobCtrl.scala +++ b/app/org/thp/cortex/controllers/JobCtrl.scala @@ -108,15 +108,18 @@ class JobCtrl @Inject()( "tlp" → artifact.tlp() ) case artifact if artifact.attachment().isDefined ⇒ - artifact.attachment().fold(JsObject.empty) { a ⇒ - Json.obj( - "attachment" → - Json.obj("contentType" → a.contentType, "id" → a.id, "name" → a.name, "size" → a.size), - "message" → artifact.message(), - "tags" → artifact.tags(), - "tlp" → artifact.tlp() - ) - } + val attachment = artifact.attachment().get + Json.obj( + "dataType" → artifact.dataType(), + "message" → artifact.message(), + "tags" → artifact.tags(), + "tlp" → artifact.tlp(), + "attachment" → Json.obj( + "contentType" → attachment.contentType, + "id" → attachment.id, + "name" → attachment.name, + "size" → attachment.size) + ) } .runWith(Sink.seq) } yield Json.obj( diff --git a/project/Dependencies.scala b/project/Dependencies.scala index b83aaf6bd..d3168aaec 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -18,7 +18,7 @@ object Dependencies { val reflections = "org.reflections" % "reflections" % "0.9.11" val zip4j = "net.lingala.zip4j" % "zip4j" % "1.3.2" - val elastic4play = "org.thehive-project" %% "elastic4play" % "1.11.2" + val elastic4play = "org.thehive-project" %% "elastic4play" % "1.11.3-SNAPSHOT" val dockerClient = "com.spotify" % "docker-client" % "8.14.4" } diff --git a/project/plugins.sbt b/project/plugins.sbt index e6f947ee0..838f26ac7 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,6 +2,6 @@ logLevel := Level.Info // The Play plugin -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.22") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.23") addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.1") addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.0.0") \ No newline at end of file From 7dc788128639c1ff32ea958d4145182ef5e81770 Mon Sep 17 00:00:00 2001 From: To-om Date: Mon, 27 May 2019 16:45:44 +0200 Subject: [PATCH 09/17] Fix errorMessage in job --- app/org/thp/cortex/models/Job.scala | 2 +- app/org/thp/cortex/services/JobRunnerSrv.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/org/thp/cortex/models/Job.scala b/app/org/thp/cortex/models/Job.scala index 4fa5deb91..2bdfe17e2 100644 --- a/app/org/thp/cortex/models/Job.scala +++ b/app/org/thp/cortex/models/Job.scala @@ -31,7 +31,7 @@ trait JobAttributes { val tlp = attribute("tlp", TlpAttributeFormat, "TLP level", 2L) val pap = attribute("pap", TlpAttributeFormat, "PAP level", 2L) val message = optionalAttribute("message", F.textFmt, "Message associated to the analysis") - val errorMessage = optionalAttribute("message", F.textFmt, "Message returned by the worker when it fails") + val errorMessage = optionalAttribute("errorMessage", F.textFmt, "Message returned by the worker when it fails") val parameters = attribute("parameters", F.rawFmt, "Parameters for this job", "{}") val input = optionalAttribute("input", F.rawFmt, "Data sent to worker") val fromCache = optionalAttribute("fromCache", F.booleanFmt, "Indicates if cache is used", O.form) diff --git a/app/org/thp/cortex/services/JobRunnerSrv.scala b/app/org/thp/cortex/services/JobRunnerSrv.scala index 8f6b692c4..b1d172d03 100644 --- a/app/org/thp/cortex/services/JobRunnerSrv.scala +++ b/app/org/thp/cortex/services/JobRunnerSrv.scala @@ -263,7 +263,7 @@ class JobRunnerSrv @Inject()( .set("status", status.toString) .set("endDate", Json.toJson(new Date)) .set("input", input.map(JsString.apply)) - .set("message", errorMessage.map(JsString.apply)) + .set("errorMessage", errorMessage.map(JsString.apply)) updateSrv(job, fields, ModifyConfig.default) } } From 9dcc9d7690fdba15994d277b5f2d4f286da3c805 Mon Sep 17 00:00:00 2001 From: To-om Date: Fri, 31 May 2019 17:17:53 +0200 Subject: [PATCH 10/17] Update elastic4play --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index d3168aaec..7835bd4a4 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -18,7 +18,7 @@ object Dependencies { val reflections = "org.reflections" % "reflections" % "0.9.11" val zip4j = "net.lingala.zip4j" % "zip4j" % "1.3.2" - val elastic4play = "org.thehive-project" %% "elastic4play" % "1.11.3-SNAPSHOT" + val elastic4play = "org.thehive-project" %% "elastic4play" % "1.11.3" val dockerClient = "com.spotify" % "docker-client" % "8.14.4" } From e94933d9c189380579df4a437ae62ae849f04fc9 Mon Sep 17 00:00:00 2001 From: To-om Date: Tue, 28 May 2019 11:51:44 +0200 Subject: [PATCH 11/17] Change file loaded in test analyzer --- test/resources/analyzers/testAnalyzer/testAnalyzer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/resources/analyzers/testAnalyzer/testAnalyzer.py b/test/resources/analyzers/testAnalyzer/testAnalyzer.py index e1d8df86e..eb08ac0ee 100755 --- a/test/resources/analyzers/testAnalyzer/testAnalyzer.py +++ b/test/resources/analyzers/testAnalyzer/testAnalyzer.py @@ -10,7 +10,7 @@ class TestAnalyzer(Analyzer): def artifacts(self, raw): return [ self.build_artifact("ip", "127.0.0.1", tags=["localhost"]), - self.build_artifact("file", "/etc/passwd", tlp=3) + self.build_artifact("file", "/etc/issue.net", tlp=3) ] def summary(self, raw): From 99d20763405b3ea2a827a12c2545a912170bc24f Mon Sep 17 00:00:00 2001 From: To-om Date: Mon, 3 Jun 2019 15:36:41 +0200 Subject: [PATCH 12/17] #175 Add docker daemon in Cortex docker image --- app/org/thp/cortex/controllers/JobCtrl.scala | 7 +-- .../cortex/services/DockerJobRunnerSrv.scala | 25 ++++---- docker.sbt | 19 +++++-- docker/cortex/docker-compose.yml | 5 +- package/docker/entrypoint | 57 +++++++++++++------ test/resources/analyzers/blocker/Dockerfile | 6 ++ test/resources/analyzers/blocker/blocker.sh | 6 ++ 7 files changed, 83 insertions(+), 42 deletions(-) create mode 100644 test/resources/analyzers/blocker/Dockerfile create mode 100755 test/resources/analyzers/blocker/blocker.sh diff --git a/app/org/thp/cortex/controllers/JobCtrl.scala b/app/org/thp/cortex/controllers/JobCtrl.scala index a9521526d..b43142e42 100644 --- a/app/org/thp/cortex/controllers/JobCtrl.scala +++ b/app/org/thp/cortex/controllers/JobCtrl.scala @@ -114,11 +114,8 @@ class JobCtrl @Inject()( "message" → artifact.message(), "tags" → artifact.tags(), "tlp" → artifact.tlp(), - "attachment" → Json.obj( - "contentType" → attachment.contentType, - "id" → attachment.id, - "name" → attachment.name, - "size" → attachment.size) + "attachment" → Json + .obj("contentType" → attachment.contentType, "id" → attachment.id, "name" → attachment.name, "size" → attachment.size) ) } .runWith(Sink.seq) diff --git a/app/org/thp/cortex/services/DockerJobRunnerSrv.scala b/app/org/thp/cortex/services/DockerJobRunnerSrv.scala index 93d0fb475..ee1916531 100644 --- a/app/org/thp/cortex/services/DockerJobRunnerSrv.scala +++ b/app/org/thp/cortex/services/DockerJobRunnerSrv.scala @@ -46,10 +46,11 @@ class DockerJobRunnerSrv(client: DockerClient, autoUpdate: Boolean, implicit val Try { logger.info(s"Docker is available:\n${client.info()}") true - }.getOrElse { - logger.info(s"Docker is not available") + }.recover { + case error ⇒ + logger.info(s"Docker is not available", error) false - } + }.get def run(jobDirectory: Path, dockerImage: String, job: Job, timeout: Option[FiniteDuration])(implicit ec: ExecutionContext): Future[Unit] = { import scala.collection.JavaConverters._ @@ -90,15 +91,15 @@ class DockerJobRunnerSrv(client: DockerClient, autoUpdate: Boolean, implicit val client.waitContainer(containerCreation.id()) () }.andThen { - case r ⇒ - if (!Files.exists(jobDirectory.resolve("output").resolve("output.json"))) { - val message = r.fold(e ⇒ s"Docker creation error: ${e.getMessage}\n", _ ⇒ "") + - Try(client.logs(containerCreation.id(), LogsParam.stdout(), LogsParam.stderr()).readFully()) - .recover { case e ⇒ s"Container logs can't be read (${e.getMessage}" } - val report = Json.obj("success" → false, "errorMessage" → message) - Files.write(jobDirectory.resolve("output").resolve("output.json"), report.toString.getBytes(StandardCharsets.UTF_8)) - } - } + case r ⇒ + if (!Files.exists(jobDirectory.resolve("output").resolve("output.json"))) { + val message = r.fold(e ⇒ s"Docker creation error: ${e.getMessage}\n", _ ⇒ "") + + Try(client.logs(containerCreation.id(), LogsParam.stdout(), LogsParam.stderr()).readFully()) + .recover { case e ⇒ s"Container logs can't be read (${e.getMessage}" } + val report = Json.obj("success" → false, "errorMessage" → message) + Files.write(jobDirectory.resolve("output").resolve("output.json"), report.toString.getBytes(StandardCharsets.UTF_8)) + } + } timeout .fold(execution)(t ⇒ execution.withTimeout(t, client.stopContainer(containerCreation.id(), 3))) .andThen { diff --git a/docker.sbt b/docker.sbt index cc19a9f6e..a5451aa5d 100644 --- a/docker.sbt +++ b/docker.sbt @@ -23,17 +23,26 @@ mappings in Docker ~= (_.filterNot { }) dockerCommands ~= { dc => val (dockerInitCmds, dockerTailCmds) = dc - .collect { - case ExecCmd("RUN", "chown", _*) => ExecCmd("RUN", "chown", "-R", "daemon:root", ".") - case other => other + .flatMap { + case ExecCmd("RUN", "chown", _*) => Some(ExecCmd("RUN", "chown", "-R", "daemon:root", ".")) + case Cmd("USER", _) => None + case other => Some(other) } .splitAt(4) dockerInitCmds ++ Seq( Cmd("USER", "root"), ExecCmd("RUN", "bash", "-c", - "apt-get update && " + - "apt-get install -y --no-install-recommends python-pip python2.7-dev python3-pip python3-dev ssdeep libfuzzy-dev libfuzzy2 libimage-exiftool-perl libmagic1 build-essential git libssl-dev dnsutils && " + + "wget -q -O - https://download.docker.com/linux/static/stable/x86_64/docker-18.09.0.tgz | " + + "tar -xzC /usr/local/bin/ --strip-components 1 && " + + "addgroup --system dockremap && " + + "adduser --system --ingroup dockremap dockremap && " + + "addgroup --system docker && " + + "usermod --append --groups docker daemon &&" + + "echo 'dockremap:165536:65536' >> /etc/subuid && " + + "echo 'dockremap:165536:65536' >> /etc/subgid && " + + "apt-get update && " + + "apt-get install -y --no-install-recommends python-pip python2.7-dev python3-pip python3-dev ssdeep libfuzzy-dev libfuzzy2 libimage-exiftool-perl libmagic1 build-essential git libssl-dev dnsutils iptables && " + "pip2 install -U pip setuptools && " + "pip3 install -U pip setuptools && " + "hash -r && " + diff --git a/docker/cortex/docker-compose.yml b/docker/cortex/docker-compose.yml index 2ba0a692b..1dc8e47c5 100644 --- a/docker/cortex/docker-compose.yml +++ b/docker/cortex/docker-compose.yml @@ -1,13 +1,10 @@ version: "2" services: elasticsearch: - image: docker.elastic.co/elasticsearch/elasticsearch:5.6.0 + image: elasticsearch:6.8.0 environment: - http.host=0.0.0.0 - - transport.host=0.0.0.0 - - xpack.security.enabled=false - cluster.name=hive - - script.inline=true - thread_pool.index.queue_size=100000 - thread_pool.search.queue_size=100000 - thread_pool.bulk.queue_size=100000 diff --git a/package/docker/entrypoint b/package/docker/entrypoint index 5f78fe577..0737fed1c 100755 --- a/package/docker/entrypoint +++ b/package/docker/entrypoint @@ -6,7 +6,10 @@ CONFIG_ES=1 CONFIG=1 CONFIG_FILE=/etc/cortex/application.conf ANALYZER_PATH=/opt/Cortex-Analyzers/analyzers +ANALYZER_URLS=() RESPONDER_PATH=/opt/Cortex-Analyzers/responders +RESPONDER_URLS=() +START_DOCKER=0 function usage { cat <<- _EOF_ @@ -14,11 +17,12 @@ function usage { --no-config | do not try to configure TheHive (add secret and elasticsearch) --no-config-secret | do not add random secret to configuration --no-config-es | do not add elasticsearch hosts to configuration - --es-hosts | use this string to configure elasticsearch hosts (format: ["host1:9300","host2:9300"]) + --es-uri | use this string to configure elasticsearch hosts (format: http(s)://host:port,host:port(/prefix)?querystring) --es-hostname | resolve this hostname to find elasticseach instances --secret | secret to secure sessions - --analyzer-path | where analyzers are located - --responder-path | where responders are located + --analyzer-url | where analyzers are located (url or path) + --responder-url | where responders are located (url or path) + --start-docker | start a internal docker (inside container) to run analyzers/responders _EOF_ exit 1 } @@ -30,13 +34,18 @@ do "--no-config") CONFIG=0;; "--no-config-secret") CONFIG_SECRET=0;; "--no-config-es") CONFIG_ES=0;; - "--es-hosts") shift; ES_HOSTS=$1;; + "--es-hosts") echo "--es-hosts is deprecated, please use --es-uri" + usage;; + "--es-uri") shift; ES_URI=$1;; "--es-hostname") shift; ES_HOSTNAME=$1;; "--secret") shift; SECRET=$1;; "--analyzer-path") shift; ANALYZER_PATH=$1;; "--responder-path") shift; RESPONDER_PATH=$1;; + "--analyzer-url") shift; ANALYZER_URLS+=$1;; + "--responder-url") shift; RESPONDER_URLS+=$1;; + "--start-docker") START_DOCKER=1;; "--") STOP=1;; - *) usage + *) echo "unrecognized option: $1"; usage;; esac shift done @@ -56,12 +65,12 @@ then if test $CONFIG_ES = 1 then - if test -z "$ES_HOSTS" + if test -z "$ES_URI" then function join_es_hosts { - echo -n "[\"$1" + echo -n $1:9200 shift - printf "%s:9300\"]" "${@/#/:9300\",\"}" + printf "%s," "${@/#/:9200}" } ES=$(getent ahostsv4 $ES_HOSTNAME | awk '{ print $1 }' | sort -u) @@ -69,26 +78,42 @@ then then echo "Warning automatic elasticsearch host config fails" else - ES_HOSTS=$(join_es_hosts $ES) + ES_URI=http://$(join_es_hosts $ES) fi fi - if test -n "$ES_HOSTS" + if test -n "$ES_URI" then - echo Using elasticsearch host: $ES_HOSTS - echo search.host=$ES_HOSTS >> $CONFIG_FILE + echo Using elasticsearch uri: $ES_URI + echo search.uri=\"$ES_URI\" >> $CONFIG_FILE else echo elasticsearch host not configured fi fi - echo analyzer.path=[\"$ANALYZER_PATH\"] >> $CONFIG_FILE - echo responder.path=[\"$RESPONDER_PATH\"] >> $CONFIG_FILE + function join_urls { + echo -n \"$1\" + shift + for U do echo -n ,\"$U\"; done +# printf ",\"%s\"" $@ + } + test ${#ANALYZER_URLS} = 0 && ANALYZER_URLS+=$ANALYZER_PATH + test ${#RESPONDER_URLS} = 0 && RESPONDER_URLS+=$RESPONDER_PATH + + echo analyzer.urls=\[$(join_urls ${ANALYZER_URLS[@]})\] >> $CONFIG_FILE + echo responder.urls=\[$(join_urls ${RESPONDER_URLS[@]})\] >> $CONFIG_FILE echo 'include file("/etc/cortex/application.conf")' >> $CONFIG_FILE fi -exec bin/cortex \ +test $START_DOCKER = 1 && dockerd --host=unix:///var/run/docker.sock --host=tcp://0.0.0.0:2375 &> /dev/null & +DOCKER_PID=$! + +echo config file is: +cat $CONFIG_FILE +su -s /bin/sh -c "cd /opt/cortex; bin/cortex \ -Dconfig.file=$CONFIG_FILE \ -Dlogger.file=/etc/cortex/logback.xml \ -Dpidfile.path=/dev/null \ - $@ + $@" daemon + +test $START_DOCKER = 1 && kill ${DOCKER_PID} diff --git a/test/resources/analyzers/blocker/Dockerfile b/test/resources/analyzers/blocker/Dockerfile new file mode 100644 index 000000000..aa281134a --- /dev/null +++ b/test/resources/analyzers/blocker/Dockerfile @@ -0,0 +1,6 @@ +FROM debian:latest + +WORKDIR /analyzer +RUN apt update && apt install -y jq +COPY blocker.sh blocker/blocker.sh +ENTRYPOINT ["blocker/blocker.sh"] diff --git a/test/resources/analyzers/blocker/blocker.sh b/test/resources/analyzers/blocker/blocker.sh new file mode 100755 index 000000000..4ded379f6 --- /dev/null +++ b/test/resources/analyzers/blocker/blocker.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +while true +do + sleep 10 +done From 593377e4b77e90823e3d09e2589751d963e98aff Mon Sep 17 00:00:00 2001 From: Nabil Adouani Date: Tue, 4 Jun 2019 12:02:40 +0200 Subject: [PATCH 13/17] #195 Display report0Danalyzer report taxonomies --- www/src/app/core/core.module.js | 6 +- .../taxonomie/taxonomie.directive.js | 26 ++++++ .../core/directives/taxonomie/taxonomie.html | 15 ++++ .../pages/jobs/components/job.details.html | 86 +++++++++++-------- 4 files changed, 96 insertions(+), 37 deletions(-) create mode 100644 www/src/app/core/directives/taxonomie/taxonomie.directive.js create mode 100644 www/src/app/core/directives/taxonomie/taxonomie.html diff --git a/www/src/app/core/core.module.js b/www/src/app/core/core.module.js index eabdde30c..32f072132 100755 --- a/www/src/app/core/core.module.js +++ b/www/src/app/core/core.module.js @@ -8,6 +8,7 @@ import requireRolesDirective from './directives/require-roles/require-roles.dire import compareToDirective from './directives/compare-to/compare-to.directive'; import userAvatarDirective from './directives/user-avatar/user-avatar.directive'; import tlpDirective from './directives/tlp/tlp.directive'; +import taxonomieDirective from './directives/taxonomie/taxonomie.directive'; import autofocusDirective from './directives/autofocus/autofocus.directive'; import constants from './services/constants'; @@ -37,8 +38,9 @@ fixedHeightDirective(core); fileChooserDirective(core); requireRolesDirective(core); compareToDirective(core); -userAvatarDirective(core); +userAvatarDirective(core) tlpDirective(core); +taxonomieDirective(core); autofocusDirective(core); /* Common services */ @@ -54,4 +56,4 @@ constants(core); /* Filters */ fangFilter(core); -export default core; +export default core; \ No newline at end of file diff --git a/www/src/app/core/directives/taxonomie/taxonomie.directive.js b/www/src/app/core/directives/taxonomie/taxonomie.directive.js new file mode 100644 index 000000000..688865f14 --- /dev/null +++ b/www/src/app/core/directives/taxonomie/taxonomie.directive.js @@ -0,0 +1,26 @@ +'use strict'; + +import _ from 'lodash/core'; + +import tpl from './taxonomie.html'; + +export default function (app) { + app.directive('taxonomie', taxonomie); + + function taxonomie() { + 'ngInject'; + + return { + templateUrl: tpl, + scope: { + taxonomies: '=' + }, + replace: true, + link: linkFn + }; + + function linkFn(scope) { + + } + } +} \ No newline at end of file diff --git a/www/src/app/core/directives/taxonomie/taxonomie.html b/www/src/app/core/directives/taxonomie/taxonomie.html new file mode 100644 index 000000000..6ae97e803 --- /dev/null +++ b/www/src/app/core/directives/taxonomie/taxonomie.html @@ -0,0 +1,15 @@ +
+
+ + {{taxonomy.namespace}}:{{taxonomy.predicate}}{{(taxonomy.value != undefined && taxonomy.value!= null) ? '="'+taxonomy.value+'"': ''}} + +
+ +
+ No summary available +
+
\ No newline at end of file diff --git a/www/src/app/pages/jobs/components/job.details.html b/www/src/app/pages/jobs/components/job.details.html index 75674573c..886228237 100644 --- a/www/src/app/pages/jobs/components/job.details.html +++ b/www/src/app/pages/jobs/components/job.details.html @@ -5,40 +5,56 @@
- Artifact -

- [{{$ctrl.job.dataType | uppercase}}] - {{(($ctrl.job.dataType === 'file') ? $ctrl.job.attachment.name: $ctrl.job.data) | fang}} - {{$ctrl.job.label || 'No Label'}} - -

-

- [{{$ctrl.job.dataType | uppercase}}] {{(($ctrl.job.dataType === 'file') ? $ctrl.job.attachment.name : $ctrl.job.data) | fang}} -

-
- - Date -

- -

-
- - TLP -

- -

-
- - PAP -

- -

-
- - - Status -

- {{$ctrl.job.status}} -

+
+ Artifact +

+ [{{$ctrl.job.dataType | uppercase}}] + {{(($ctrl.job.dataType === 'file') ? $ctrl.job.attachment.name: $ctrl.job.data) | fang}} + {{$ctrl.job.label || 'No Label'}} + +

+

+ [{{$ctrl.job.dataType | uppercase}}] + {{(($ctrl.job.dataType === 'file') ? $ctrl.job.attachment.name : $ctrl.job.data) | fang}} +

+
+ +
+ Date +

+ +

+
+ +
+ TLP +

+ +

+
+ +
+ PAP +

+ +

+
+ +
+ Status +

+ {{$ctrl.job.status}} +

+
+ +
+ Report summary +

+ +

+
+
\ No newline at end of file From f8bd8e7ea5c29169c7ad0a09079dc7cfdd152966 Mon Sep 17 00:00:00 2001 From: To-om Date: Tue, 4 Jun 2019 17:03:23 +0200 Subject: [PATCH 14/17] #195 Add datastore password in status --- app/org/thp/cortex/controllers/StatusCtrl.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/org/thp/cortex/controllers/StatusCtrl.scala b/app/org/thp/cortex/controllers/StatusCtrl.scala index 65f2b84b8..a9d85792a 100644 --- a/app/org/thp/cortex/controllers/StatusCtrl.scala +++ b/app/org/thp/cortex/controllers/StatusCtrl.scala @@ -1,15 +1,15 @@ package org.thp.cortex.controllers -import javax.inject.{Inject, Singleton} import scala.concurrent.ExecutionContext import play.api.Configuration import play.api.http.Status -import play.api.libs.json.{JsBoolean, JsString, Json} import play.api.libs.json.Json.toJsFieldJsValueWrapper +import play.api.libs.json.{JsBoolean, JsString, Json} import play.api.mvc.{AbstractController, Action, AnyContent, ControllerComponents} import com.sksamuel.elastic4s.http.ElasticDsl +import javax.inject.{Inject, Singleton} import org.elasticsearch.client.Node import org.thp.cortex.models.Worker @@ -40,6 +40,7 @@ class StatusCtrl @Inject()( "ElasticSearch client" → getVersion(classOf[Node]) ), "config" → Json.obj( + "protectDownloadsWith" → configuration.get[String]("datastore.attachment.password"), "authType" → (authSrv match { case multiAuthSrv: MultiAuthSrv ⇒ multiAuthSrv.authProviders.map { a ⇒ From 9072f3e1c28fc7661540971c5e607d80f2682d68 Mon Sep 17 00:00:00 2001 From: Nabil Adouani Date: Tue, 4 Jun 2019 17:04:27 +0200 Subject: [PATCH 15/17] #195 Display extracted artifacts from job reports --- .../pages/jobs/components/job.details.html | 5 +++ www/src/app/pages/jobs/job.page.html | 33 +++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/www/src/app/pages/jobs/components/job.details.html b/www/src/app/pages/jobs/components/job.details.html index 886228237..f1c14867e 100644 --- a/www/src/app/pages/jobs/components/job.details.html +++ b/www/src/app/pages/jobs/components/job.details.html @@ -18,6 +18,7 @@ [{{$ctrl.job.dataType | uppercase}}] {{(($ctrl.job.dataType === 'file') ? $ctrl.job.attachment.name : $ctrl.job.data) | fang}}

+
@@ -25,6 +26,7 @@

+
@@ -32,6 +34,7 @@

+
@@ -39,6 +42,7 @@

+
@@ -47,6 +51,7 @@ {{$ctrl.job.status}}

+
diff --git a/www/src/app/pages/jobs/job.page.html b/www/src/app/pages/jobs/job.page.html index d5698c4cd..3551e1247 100644 --- a/www/src/app/pages/jobs/job.page.html +++ b/www/src/app/pages/jobs/job.page.html @@ -1,5 +1,5 @@
-

Job details +

Job details Back to list @@ -22,8 +22,35 @@

Job report

Input details
{{$ctrl.job.data | json}}

-
Report
-
{{$ctrl.job.report | json}}
+ +
+
Report
+
{{$ctrl.job.report | json}}
+
+ +
+
Artifacts
+ + + + + + + + + + + +
#DatatypeValue
{{$index + 1}}{{artifact.dataType}} +
+ {{(artifact.attachment.name || artifact.data) | fang}} +
+
+ {{tag.text}}  +
+
+
From 85e7bb9d9c7bea8869ec140309bedaa8f8f25b2e Mon Sep 17 00:00:00 2001 From: Nabil Adouani Date: Wed, 5 Jun 2019 11:35:50 +0200 Subject: [PATCH 16/17] #195 Add file artifact download link to job report page --- www/src/app/pages/jobs/job.controller.js | 7 ++++++- www/src/app/pages/jobs/job.page.html | 14 ++++++++++++-- www/src/app/pages/jobs/jobs.module.js | 11 ++++++----- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/www/src/app/pages/jobs/job.controller.js b/www/src/app/pages/jobs/job.controller.js index 0cb5980a8..2b50356d2 100644 --- a/www/src/app/pages/jobs/job.controller.js +++ b/www/src/app/pages/jobs/job.controller.js @@ -6,4 +6,9 @@ export default class JobController { this.$log = $log; } -} + + $onInit() { + this.protectDownloadsWith = this.main.config.config.protectDownloadsWith; + this.hasFileArtifact = this.job.report.artifacts.find(item => item.dataType === 'file'); + } +} \ No newline at end of file diff --git a/www/src/app/pages/jobs/job.page.html b/www/src/app/pages/jobs/job.page.html index 3551e1247..b8ceea0b8 100644 --- a/www/src/app/pages/jobs/job.page.html +++ b/www/src/app/pages/jobs/job.page.html @@ -30,6 +30,9 @@
Report
Artifacts
+
+ Zip are protected with password "{{$ctrl.protectDownloadsWith}}" +
@@ -40,8 +43,15 @@
Artifacts
# {{$index + 1}} {{artifact.dataType}} -
- {{(artifact.attachment.name || artifact.data) | fang}} +
+ {{artifact.attachment.name| fang}} + + (Download) + +
+
+ {{artifact.data | fang}}
{ - return AnalyzerService.list() - .then(() => $q.resolve(AnalyzerService.getTypes())) - .catch(err => $q.reject(err)); - }, + datatypes: ($q, AnalyzerService) => AnalyzerService.list() + .then(() => $q.resolve(AnalyzerService.getTypes())) + .catch(err => $q.reject(err)), jobtypes: () => ['analyzer', 'responder'], analyzers: AnalyzerService => AnalyzerService.list().then(analyzers => @@ -97,6 +95,9 @@ const jobsModule = angular templateUrl: jobTpl, bindings: { job: '<' + }, + require: { + main: '^^mainPage' } }) .component('jobDetails', { From 43ebbf160395d7e9355fa737ce2c401ee71efe90 Mon Sep 17 00:00:00 2001 From: To-om Date: Wed, 5 Jun 2019 15:56:39 +0200 Subject: [PATCH 17/17] Update changelog and version --- CHANGELOG.md | 15 ++++++++++++++- version.sbt | 2 +- www/package.json | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c72cfd5c6..694143f52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,20 @@ # Change Log -## [3.0.0-RC2](https://github.com/TheHive-Project/Cortex/tree/3.0.0-RC2) (2019-05-03) +## [3.0.0-RC3](https://github.com/TheHive-Project/Cortex/tree/3.0.0-RC3) (2019-06-05) + +[Full Changelog](https://github.com/TheHive-Project/Cortex/compare/3.0.0-RC2...3.0.0-RC3) + +**Implemented enhancements:** + +- Improve job details page [\#195](https://github.com/TheHive-Project/Cortex/issues/195) +- Add support of ElasticSearch 6 [\#191](https://github.com/TheHive-Project/Cortex/issues/191) +- Upgrade frontend libraries [\#190](https://github.com/TheHive-Project/Cortex/issues/190) +**Fixed bugs:** + +- Get user detials via API is available to non-admin users [\#194](https://github.com/TheHive-Project/Cortex/issues/194) + +## [3.0.0-RC2](https://github.com/TheHive-Project/Cortex/tree/3.0.0-RC2) (2019-05-03) [Full Changelog](https://github.com/TheHive-Project/Cortex/compare/3.0.0-RC1...3.0.0-RC2) **Fixed bugs:** diff --git a/version.sbt b/version.sbt index bbf00929c..cbea8c91a 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -version in ThisBuild := "3.0.0-RC2" +version in ThisBuild := "3.0.0-RC3" diff --git a/www/package.json b/www/package.json index a444e09ee..19d829922 100755 --- a/www/package.json +++ b/www/package.json @@ -1,6 +1,6 @@ { "name": "cortex", - "version": "3.0.0-RC2", + "version": "3.0.0-RC3", "description": "A powerfull observable analysis engine", "license": "AGPL-3.0-or-later", "homepage": "https://github.com/TheHive-Project/Cortex",