Skip to content

Commit

Permalink
Merge branch 'feature/misp' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
To-om committed May 5, 2017
2 parents 8cfa56b + 01bd553 commit 3ef6e2a
Show file tree
Hide file tree
Showing 23 changed files with 820 additions and 285 deletions.
9 changes: 3 additions & 6 deletions app/Module.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import play.api.{ Configuration, Environment, Mode }
import play.api.libs.concurrent.AkkaGuiceSupport

import com.google.inject.AbstractModule

import net.codingwell.scalaguice.ScalaModule

import controllers.{ AssetCtrl, AssetCtrlDev, AssetCtrlProd }
import net.codingwell.scalaguice.ScalaModule
import play.api.libs.concurrent.AkkaGuiceSupport
import play.api.{ Configuration, Environment, Mode }
import services.JobActor

class Module(environment: Environment, configuration: Configuration) extends AbstractModule with ScalaModule with AkkaGuiceSupport {
Expand Down
13 changes: 6 additions & 7 deletions app/controllers/AnalyzerCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@ package controllers

import javax.inject.Inject

import scala.annotation.implicitNotFound
import scala.concurrent.{ ExecutionContext, Future }

import models.JsonFormat.{ analyzerWrites, dataActifactReads, jobWrites }
import models.{ DataArtifact, FileArtifact }
import play.api.libs.json.{ JsObject, JsString, Json }
import play.api.mvc.{ Action, AnyContent, Controller, Request }

import models.{ DataArtifact, FileArtifact }
import models.JsonFormat.{ analyzerWrites, dataActifactReads, jobWrites }
import services.{ AnalyzerSrv, JobSrv }

import scala.concurrent.{ ExecutionContext, Future }

class AnalyzerCtrl @Inject() (
analyzerSrv: AnalyzerSrv,
jobSrv: JobSrv,
Expand Down Expand Up @@ -51,7 +49,8 @@ class AnalyzerCtrl @Inject() (
readDataArtifact(request)
.orElse(readFileArtifact(request))
.map { artifact
jobSrv.create(artifact, analyzerId)
analyzerSrv.analyze(analyzerId, artifact)
//jobSrv.create(artifact, analyzerId)
.map(j Ok(Json.toJson(j)))
}
.getOrElse(Future.successful(BadRequest("???")))
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/Asset.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import javax.inject.{ Inject, Singleton }

import play.api.Environment
import play.api.http.HttpErrorHandler
import play.api.mvc.{ Action, AnyContent, Controller }
import play.api.mvc.{ Action, AnyContent }

trait AssetCtrl {
def get(file: String): Action[AnyContent]
Expand Down
16 changes: 6 additions & 10 deletions app/controllers/JobCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import scala.concurrent.duration.Duration
import scala.util.{ Failure, Success }
import play.api.libs.json.{ JsString, Json }
import play.api.mvc.{ Action, AnyContent, Controller }
import models.JsonFormat.{ jobStatusWrites, jobWrites }
import models.JsonFormat._
import services.JobSrv

class JobCtrl @Inject() (
Expand All @@ -35,9 +35,9 @@ class JobCtrl @Inject() (
.get(jobId)
.map { job
val report = job.report.value match {
case Some(Success(_report)) _report
case Some(Failure(error)) JsString(error.getMessage)
case None JsString("Running")
case Some(Success(r)) Json.toJson(r)
case Some(Failure(error)) JsString(error.getMessage)
case None JsString("Running")
}
Ok(jobWrites.writes(job) +
("status" jobStatusWrites.writes(job.status)) +
Expand All @@ -46,11 +46,7 @@ class JobCtrl @Inject() (
}

def waitReport(jobId: String, atMost: String): Action[AnyContent] = Action.async { request
for {
job jobSrv.get(jobId)
(status, report) jobSrv.waitReport(jobId, Duration(atMost))
} yield Ok(jobWrites.writes(job) +
("status" jobStatusWrites.writes(job.status)) +
("report" report))
jobSrv.waitReport(jobId, Duration(atMost))
.map { job Ok(Json.toJson(job)) }
}
}
31 changes: 31 additions & 0 deletions app/controllers/MispCtrl.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package controllers

import javax.inject.Inject

import play.api.Logger
import play.api.libs.json.{ JsObject, JsValue }
import play.api.mvc.{ Action, AnyContent, Controller }
import services.MispSrv

import scala.concurrent.ExecutionContext

class MispCtrl @Inject() (mispSrv: MispSrv, implicit val ec: ExecutionContext) extends Controller {

private[MispCtrl] lazy val logger = Logger(getClass)
def modules: Action[AnyContent] = Action { _
Ok(mispSrv.moduleList)
}

def query: Action[JsValue] = Action.async(parse.json) { request
val module = (request.body \ "module").asOpt[String].getOrElse(sys.error("module not present in request"))
val (mispType, dataJson) = request.body.as[JsObject].fields
.collectFirst {
case kv @ (k, _) if k != "module" kv
}
.getOrElse(sys.error("invalid request"))
val data = dataJson.asOpt[String].getOrElse(sys.error("data has invalid type (expected string)"))
mispSrv.query(module, mispType, data)
.map(Ok(_))
}
}

25 changes: 25 additions & 0 deletions app/controllers/StatusCtrl.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package controllers

import javax.inject.{ Inject, Singleton }

import play.api.Configuration
import play.api.libs.json.Json
import play.api.libs.json.Json.toJsFieldJsValueWrapper
import play.api.mvc.{ Action, Controller }

@Singleton
class StatusCtrl @Inject() (
configuration: Configuration) extends Controller {

private[controllers] def getVersion(c: Class[_]) = Option(c.getPackage.getImplementationVersion).getOrElse("SNAPSHOT")

def get = Action { _
Ok(Json.obj(
"versions" Json.obj(
"Cortex" getVersion(classOf[models.Artifact]),
"Play" getVersion(classOf[Controller])),
"config" Json.obj(
"authType" "none",
"capabilities" Json.arr())))
}
}
4 changes: 0 additions & 4 deletions app/models/Analyzer.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package models

import scala.concurrent.Future
import play.api.libs.json.JsObject

abstract class Analyzer {
def analyze(artifact: Artifact): Future[JsObject]
val name: String
val version: String
val description: String
Expand Down
14 changes: 11 additions & 3 deletions app/models/Artifact.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package models

import play.api.libs.json.JsObject
import java.io.File
import java.nio.file.Files

import play.api.libs.json.JsObject

abstract class Artifact(attributes: JsObject) {
def dataTypeFilter(filter: String): Boolean = (attributes \ "dataType").asOpt[String].fold(false)(_.toLowerCase.contains(filter.toLowerCase))
def dataType: String = (attributes \ "dataType").asOpt[String].getOrElse("other")
def dataTypeFilter(filter: String): Boolean = dataType.toLowerCase.contains(filter.toLowerCase)
def dataFilter(filter: String): Boolean = false
}
class FileArtifact(val data: File, val attributes: JsObject) extends Artifact(attributes) {
override def finalize {
override def finalize() {
data.delete()
}
}
Expand All @@ -18,6 +21,11 @@ object FileArtifact {
data.renameTo(tempFile)
new FileArtifact(tempFile, attributes)
}
def apply(data: Array[Byte], attributes: JsObject): FileArtifact = {
val tempFile = File.createTempFile("cortex-", "-datafile")
Files.write(tempFile.toPath, data)
new FileArtifact(tempFile, attributes)
}
def unapply(fileArtifact: FileArtifact) = Some(fileArtifact.data fileArtifact.attributes)
}
case class DataArtifact(data: String, attributes: JsObject) extends Artifact(attributes) {
Expand Down
84 changes: 10 additions & 74 deletions app/models/ExternalAnalyzer.scala
Original file line number Diff line number Diff line change
@@ -1,80 +1,16 @@
package models

import java.io.{ BufferedReader, InputStreamReader }
import java.nio.file.Path

import scala.concurrent.{ ExecutionContext, Future, blocking }
import scala.sys.process.{ BasicIO, Process, ProcessIO }

import akka.stream.Materializer

import play.api.Logger
import play.api.libs.json.{ JsObject, JsString, Json }

import com.fasterxml.jackson.core.JsonParseException
import com.fasterxml.jackson.databind.JsonMappingException
import play.api.libs.json.JsObject

case class ExternalAnalyzer(
name: String,
version: String,
description: String,
dataTypeList: Seq[String],
author: String,
url: String,
license: String,
command: Path,
config: JsObject)(implicit val ec: ExecutionContext) extends Analyzer {

val log = Logger(getClass)
private val osexec = if (System.getProperty("os.name").toLowerCase.contains("win"))
(c: String) s"""cmd /c $c"""
else
(c: String) s"""sh -c "./$c" """

override def analyze(artifact: Artifact): Future[JsObject] = {
Future {
val input = artifact match {
case FileArtifact(file, attributes) attributes + ("file" JsString(file.getAbsoluteFile.toString)) + ("config" config)
case DataArtifact(data, attributes) attributes + ("data" JsString(data)) + ("config" config)
}
val output = new StringBuffer
val error = new StringBuffer
try {
log.info(s"Execute ${osexec(command.getFileName.toString)} in ${command.getParent.toFile.getAbsoluteFile.getName}")
val exitValue = Process(osexec(command.getFileName.toString), command.getParent.toFile).run(
new ProcessIO(
{ stdin
try stdin.write(input.toString.getBytes("UTF-8"))
finally stdin.close()
},
{ stdout
val reader = new BufferedReader(new InputStreamReader(stdout, "UTF-8"))
try BasicIO.processLinesFully { line
output.append(line).append(System.lineSeparator())
()
}(reader.readLine)
finally reader.close()
},
{ stderr
val reader = new BufferedReader(new InputStreamReader(stderr, "UTF-8"))
try BasicIO.processLinesFully { line
error.append(line).append(System.lineSeparator())
()
}(reader.readLine)
finally reader.close()
})).exitValue
Json.parse(output.toString).as[JsObject]
}
catch {
case _: JsonMappingException
error.append(output)
JsObject(Seq("errorMessage" JsString(s"Error: Invalid output\n$error")))
case _: JsonParseException
error.append(output)
JsObject(Seq("errorMessage" JsString(s"Error: Invalid output\n$error")))
case t: Throwable
JsObject(Seq("errorMessage" JsString(t.getMessage + ":" + t.getStackTrace().mkString("", "\n\t", "\n"))))
}
}
}
}
name: String,
version: String,
description: String,
dataTypeList: Seq[String],
author: String,
url: String,
license: String,
command: Path,
config: JsObject) extends Analyzer
20 changes: 9 additions & 11 deletions app/models/Job.scala
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
package models

import play.api.libs.json.JsObject
import scala.concurrent.Future
import java.util.Date
import scala.util.Success
import scala.util.Failure

import scala.concurrent.Future
import scala.util.{ Failure, Success }

object JobStatus extends Enumeration {
type Type = Value
val InProgress, Success, Failure = Value
}
case class Job(id: String, analyzerId: String, artifact: Artifact, report: Future[JsObject]) {

case class Job(id: String, analyzer: Analyzer, artifact: Artifact, report: Future[Report]) {
val date: Date = new Date()

def status: JobStatus.Type = report.value match {
case Some(Success(x)) (x \ "success").asOpt[Boolean] match {
case Some(true) JobStatus.Success
case _ JobStatus.Failure
}
case Some(Failure(_)) JobStatus.Failure
case None JobStatus.InProgress
case Some(Success(SuccessReport(_, _, _))) JobStatus.Success
case Some(Success(FailureReport(_))) JobStatus.Failure
case Some(Failure(_)) JobStatus.Failure
case None JobStatus.InProgress
}
}
Loading

0 comments on commit 3ef6e2a

Please sign in to comment.