diff --git a/CHANGELOG.md b/CHANGELOG.md index e6a31a21b..01d5f6263 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,34 @@ # Change Log -## [1.1.3](https://github.com/CERT-BDF/Cortex/tree/1.1.3) +## [1.1.4](https://github.com/CERT-BDF/Cortex/tree/1.1.4) (2017-09-15) +[Full Changelog](https://github.com/CERT-BDF/Cortex/compare/1.1.3...1.1.4) -[Full Changelog](https://github.com/CERT-BDF/Cortex/compare/debian/1.1.2...1.1.3) +**Implemented enhancements:** + +- Group ownership in Docker image prevents running on OpenShift [\#42](https://github.com/CERT-BDF/Cortex/issues/42) + +**Fixed bugs:** + +- Display a error notification on analyzer start fail [\#39](https://github.com/CERT-BDF/Cortex/issues/39) +- Cortex removes the input details from failure reports [\#38](https://github.com/CERT-BDF/Cortex/issues/38) + +**Closed issues:** + +- Disable analyzer in configuration file [\#32](https://github.com/CERT-BDF/Cortex/issues/32) + +## [1.1.3](https://github.com/CERT-BDF/Cortex/tree/1.1.3) (2017-06-14) +[Full Changelog](https://github.com/CERT-BDF/Cortex/compare/debian/1.1.2-2...1.1.3) **Fixed bugs:** - Problem Start Cortex on Ubuntu 16.04 [\#35](https://github.com/CERT-BDF/Cortex/issues/35) - Error when parsing analyzer failure report [\#33](https://github.com/CERT-BDF/Cortex/issues/33) +## [debian/1.1.2-2](https://github.com/CERT-BDF/Cortex/tree/debian/1.1.2-2) (2017-05-24) +[Full Changelog](https://github.com/CERT-BDF/Cortex/compare/1.1.2...debian/1.1.2-2) ## [1.1.2](https://github.com/CERT-BDF/Cortex/tree/1.1.2) (2017-05-24) -[Full Changelog](https://github.com/CERT-BDF/Cortex/compare/debian/1.1.1...1.1.2) +[Full Changelog](https://github.com/CERT-BDF/Cortex/compare/debian/1.1.1-2...1.1.2) **Implemented enhancements:** @@ -24,13 +41,22 @@ - Cortex and MISP unclear and error-loop [\#29](https://github.com/CERT-BDF/Cortex/issues/29) - Error 500 in TheHive when a job is submited to Cortex [\#27](https://github.com/CERT-BDF/Cortex/issues/27) +## [debian/1.1.1-2](https://github.com/CERT-BDF/Cortex/tree/debian/1.1.1-2) (2017-05-19) +[Full Changelog](https://github.com/CERT-BDF/Cortex/compare/rpm/1.1.1-2...debian/1.1.1-2) + +## [rpm/1.1.1-2](https://github.com/CERT-BDF/Cortex/tree/rpm/1.1.1-2) (2017-05-19) +[Full Changelog](https://github.com/CERT-BDF/Cortex/compare/1.1.1...rpm/1.1.1-2) + +**Fixed bugs:** + +- After Upgrade from Cortex 1.0.2 to 1.1.1 system does not come up [\#26](https://github.com/CERT-BDF/Cortex/issues/26) + ## [1.1.1](https://github.com/CERT-BDF/Cortex/tree/1.1.1) (2017-05-17) [Full Changelog](https://github.com/CERT-BDF/Cortex/compare/1.1.0...1.1.1) **Fixed bugs:** - Missing logos and favicons [\#25](https://github.com/CERT-BDF/Cortex/issues/25) -- After Upgrade from Cortex 1.0.2 to 1.1.1 system does not come up [\#26](https://github.com/CERT-BDF/Cortex/issues/26) **Closed issues:** diff --git a/app/models/Job.scala b/app/models/Job.scala index bdc90644d..70e212aa2 100644 --- a/app/models/Job.scala +++ b/app/models/Job.scala @@ -15,7 +15,7 @@ case class Job(id: String, analyzer: Analyzer, artifact: Artifact, report: Futur def status: JobStatus.Type = report.value match { case Some(Success(SuccessReport(_, _, _))) ⇒ JobStatus.Success - case Some(Success(FailureReport(_))) ⇒ JobStatus.Failure + case Some(Success(FailureReport(_, _))) ⇒ JobStatus.Failure case Some(Failure(_)) ⇒ JobStatus.Failure case None ⇒ JobStatus.InProgress } diff --git a/app/models/JsonFormat.scala b/app/models/JsonFormat.scala index 7d5f33b76..5e95288ce 100644 --- a/app/models/JsonFormat.scala +++ b/app/models/JsonFormat.scala @@ -50,9 +50,11 @@ object JsonFormat { full ← (json \ "full").asOpt[JsObject] summary ← (json \ "summary").asOpt[JsObject] } yield SuccessReport(artifacts, full, summary)) - .getOrElse(FailureReport(s"Invalid analyzer output format : $json")) + .getOrElse(FailureReport(s"Invalid analyzer output format : $json", JsNull)) else - FailureReport((json \ "errorMessage").asOpt[String].getOrElse(json.toString)) + FailureReport( + (json \ "errorMessage").asOpt[String].getOrElse(json.toString), + (json \ "input").asOpt[JsObject].getOrElse(JsNull)) } } @@ -62,8 +64,9 @@ object JsonFormat { "full" → full, "summary" → summary, "success" → true) - case FailureReport(message) ⇒ Json.obj( + case FailureReport(message, input) ⇒ Json.obj( "errorMessage" → message, + "input" → input, "success" → false) } diff --git a/app/models/Report.scala b/app/models/Report.scala index 296466413..52fb066b8 100644 --- a/app/models/Report.scala +++ b/app/models/Report.scala @@ -1,9 +1,9 @@ package models -import play.api.libs.json.JsObject +import play.api.libs.json.{ JsObject, JsValue } sealed abstract class Report(success: Boolean) case class SuccessReport(artifacts: Seq[Artifact], full: JsObject, summary: JsObject) extends Report(true) -case class FailureReport(message: String) extends Report(false) \ No newline at end of file +case class FailureReport(message: String, input: JsValue) extends Report(false) \ No newline at end of file diff --git a/app/services/ExternalAnalyzerSrv.scala b/app/services/ExternalAnalyzerSrv.scala index 7bdf23063..790e0a5fd 100644 --- a/app/services/ExternalAnalyzerSrv.scala +++ b/app/services/ExternalAnalyzerSrv.scala @@ -21,12 +21,14 @@ import scala.util.{ Failure, Try } @Singleton class ExternalAnalyzerSrv( analyzerPath: Path, + disabledAnalyzers: Seq[String], analyzerConfig: JsObject, akkaSystem: ActorSystem) { @Inject() def this(configuration: Configuration, akkaSystem: ActorSystem) = this( Paths.get(configuration.getString("analyzer.path").getOrElse(".")), + configuration.getStringSeq("analyzer.disabled").getOrElse(Nil), JsonConfig.configWrites.writes(configuration.getConfig("analyzer.config").getOrElse(Configuration.empty)), akkaSystem) @@ -53,7 +55,14 @@ class ExternalAnalyzerSrv( Failure(error) } .toOption - _ = logger.info(s"Register analyzer ${analyzer.name} ${analyzer.version} (${analyzer.id})") + .flatMap { + case a if disabledAnalyzers.contains(a.id) ⇒ + logger.info(s"Analyzer ${a.name} ${a.version} (${a.id}) is disabled") + None + case a ⇒ + logger.info(s"Register analyzer ${a.name} ${a.version} (${a.id})") + Some(a) + } } yield analyzer } @@ -100,12 +109,12 @@ class ExternalAnalyzerSrv( catch { case _: JsonMappingException ⇒ error.append(output) - FailureReport(s"Error: Invalid output\n$error") + FailureReport(s"Error: Invalid output\n$error", JsNull) case _: JsonParseException ⇒ error.append(output) - FailureReport(s"Error: Invalid output\n$error") + FailureReport(s"Error: Invalid output\n$error", JsNull) case t: Throwable ⇒ - FailureReport(t.getMessage + ":" + t.getStackTrace.mkString("", "\n\t", "\n")) + FailureReport(t.getMessage + ":" + t.getStackTrace.mkString("", "\n\t", "\n"), JsNull) } }(analyzeExecutionContext) } diff --git a/app/services/MispSrv.scala b/app/services/MispSrv.scala index c2b9af3ad..636cda8fd 100644 --- a/app/services/MispSrv.scala +++ b/app/services/MispSrv.scala @@ -186,7 +186,7 @@ class MispSrv( } .getOrElse { val message = (mispOutput \ "error").asOpt[String].getOrElse(mispOutput.toString) - FailureReport(message) + FailureReport(message, JsNull) } } @@ -205,7 +205,7 @@ class MispSrv( "values" → Json.arr(Json.toJson(report).toString)) Json.obj("results" → (attributes :+ cortexAttribute)) - case FailureReport(message) ⇒ + case FailureReport(message, _) ⇒ Json.obj("error" → message) } } diff --git a/build.sbt b/build.sbt index dcfab9ed5..a7fc16b3d 100644 --- a/build.sbt +++ b/build.sbt @@ -95,7 +95,7 @@ linuxMakeStartScript in Debian := None // RPM // rpmRelease := "1" -rpmVendor in Rpm := "TheHive Project" +rpmVendor := "TheHive Project" rpmUrl := Some("http://thehive-project.org/") rpmLicense := Some("AGPL") rpmRequirements += "java-1.8.0-openjdk-headless" @@ -130,7 +130,12 @@ mappings in Docker ~= (_.filterNot { }) dockerCommands ~= { dc => - val (dockerInitCmds, dockerTailCmds) = dc.splitAt(4) + val (dockerInitCmds, dockerTailCmds) = dc + .collect { + case ExecCmd("RUN", "chown", _*) => ExecCmd("RUN", "chown", "-R", "daemon:root", ".") + case other => other + } + .splitAt(4) dockerInitCmds ++ Seq( Cmd("USER", "root"), @@ -146,7 +151,8 @@ dockerCommands ~= { dc => "rm -rf misp_modules /var/lib/apt/lists/* /tmp/*"), Cmd("ADD", "var", "/var"), Cmd("ADD", "etc", "/etc"), - ExecCmd("RUN", "chown", "-R", "daemon:daemon", "/var/log/cortex")) ++ + ExecCmd("RUN", "chown", "-R", "daemon:root", "/var/log/cortex"), + ExecCmd("RUN", "chmod", "+x", "/opt/cortex/bin/cortex", "/opt/cortex/entrypoint", "/opt/cortex/contrib/misp-modules-loader.py")) ++ dockerTailCmds } diff --git a/ui/app/scripts/controllers.js b/ui/app/scripts/controllers.js index 25baed434..9385bae28 100644 --- a/ui/app/scripts/controllers.js +++ b/ui/app/scripts/controllers.js @@ -48,6 +48,10 @@ angular.module('cortex') _.each(response, function(resp) { NotificationService.success(resp.data.analyzerId + ' started successfully on ' + (resp.data.artifact.data || resp.data.artifact.attributes.filename)); }); + }).catch(function(err) { + if(err != 'cancel') { + NotificationService.error(('An error occurred: ' + err.statusText) || 'An unexpected error occurred'); + } }); }); }; @@ -83,6 +87,10 @@ angular.module('cortex') }).then(function (response) { $state.go('jobs'); NotificationService.success(response.data.analyzerId + ' started successfully on ' + response.data.artifact.data); + }).catch(function(err) { + if(err != 'cancel') { + NotificationService.error(('An error occurred: ' + err.statusText) || 'An unexpected error occurred'); + } }); }; diff --git a/ui/bower.json b/ui/bower.json index 91e854ef7..c0ac259e0 100644 --- a/ui/bower.json +++ b/ui/bower.json @@ -1,6 +1,6 @@ { "name": "cortex", - "version": "1.1.3", + "version": "1.1.4", "dependencies": { "angular": "1.5.10", "angular-sanitize": "1.5.10", diff --git a/ui/package.json b/ui/package.json index 3eca868ac..55bdc8fae 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "cortex", - "version": "1.1.3", + "version": "1.1.4", "license": "AGPL-3.0", "repository": { "type": "git", diff --git a/version.sbt b/version.sbt index a1014cee4..ec5748018 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -version in ThisBuild := "1.1.3" +version in ThisBuild := "1.1.4"