From da9388826214673c4b8d4211dc463be6f917056d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0est=C3=A1k=20V=C3=ADt?= Date: Mon, 22 Feb 2016 08:36:35 +0100 Subject: [PATCH] Vulnerabilities are now loaded from the vulnDB --- app/controllers/Statistics.scala | 23 +++++++++++++------- app/services/OdcService.scala | 37 +++++++++++++++++++------------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/app/controllers/Statistics.scala b/app/controllers/Statistics.scala index 34bee39..1ffec1a 100644 --- a/app/controllers/Statistics.scala +++ b/app/controllers/Statistics.scala @@ -164,17 +164,24 @@ class Statistics @Inject() ( val relevantReports = selection.result val vulns = relevantReports.vulnerableDependencies.flatMap(dep => dep.vulnerabilities.map(vuln => (vuln, dep))).groupBy(_._1.name).mapValues{case vulnsWithDeps => val (vulnSeq, depSeq) = vulnsWithDeps.unzip - val Seq(vuln) = vulnSeq.toSet.toSeq // Will fail when there are more different descriptions for one vulnerability… - vuln -> depSeq.toSet + //val Seq(vuln) = vulnSeq.toSet.toSeq // Will fail when there are more different descriptions for one vulnerability… TODO: load from database instead + /*vuln -> */depSeq.toSet }// .map(identity) // The .map(identity) materializes lazily mapped Map (because .mapValues is lazy). I am, however, unsure if this is a good idea. Probably not. - vulns.get(name).fold(Future.successful(Ok(views.html.statistics.vulnerabilityNotFound( - name = name, - projectsWithSelection = selection.projectsWithSelection - )))){ case (vuln, vulnerableDependencies) => + vulns.get(name).fold{ + for{ + vulnOption <- odcService.getVulnerabilityDetails(name) + } yield Ok(views.html.statistics.vulnerabilityNotFound( // TODO: the not found page might be replaced by some page explaining that there is no project affected by that vulnerability + name = name, + projectsWithSelection = selection.projectsWithSelection + )) + }{ vulnerableDependencies => for { + vulnOption <- odcService.getVulnerabilityDetails(name) plainLibs <- librariesService.byPlainLibraryIdentifiers(vulnerableDependencies.flatMap(_.plainLibraryIdentifiers)).map(_.keySet) ticketOption <- vulnerabilityNotificationService.issueTrackerExport.ticketForVulnerability(name) - } yield Ok(views.html.statistics.vulnerability( + } yield vulnOption.fold{ + sys.error("The vulnerability is not in the database, you seem to have outdated the local vulnerability database") // TODO: consider fallback or more friendly error message + }{vuln => Ok(views.html.statistics.vulnerability( vulnerability = vuln, affectedProjects = vulnerableDependencies.flatMap(dep => dep.projects.map(proj => (proj, dep))).groupBy(_._1).mapValues(_.map(_._2)), vulnerableDependencies = vulnerableDependencies, @@ -184,7 +191,7 @@ class Statistics @Inject() ( ticket <- ticketOption issueTrackerService <- issueTrackerServiceOption } yield ticket -> issueTrackerService.ticketLink(ticket) - )) + ))} } } diff --git a/app/services/OdcService.scala b/app/services/OdcService.scala index b8971bf..c7ea0fa 100644 --- a/app/services/OdcService.scala +++ b/app/services/OdcService.scala @@ -8,7 +8,7 @@ import _root_.org.owasp.dependencycheck.dependency.VulnerableSoftware import _root_.org.owasp.dependencycheck.utils.{DependencyVersion, DependencyVersionUtil, Settings} import com.github.nscala_time.time.Imports._ import com.google.inject.Inject -import models.odc.OdcProperty +import models.odc.{Vulnerabilities, OdcProperty} import models.odc.tables._ import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider} import play.db.NamedDatabase @@ -29,20 +29,27 @@ class OdcService @Inject()(@NamedDatabase("odc") protected val dbConfigProvider: def getReferences(id: Int): Future[Seq[com.ysoft.odc.Reference]] = db.run(references.filter(_.cveId === id).map(_.base).result) - def getVulnerabilityDetails(id: Int): Future[Option[com.ysoft.odc.Vulnerability]] = { - for { - bareVulnOption <- db.run(vulnerabilities.filter(_.id === id).map(_.base).result).map(_.headOption) - vulnerableSoftware <- getVulnerableSoftware(id) - references <- getReferences(id) - } yield bareVulnOption.map{bareVuln => - com.ysoft.odc.Vulnerability( - name = bareVuln.cve, - cweOption = bareVuln.cweOption, - cvss = bareVuln.cvss, - description = bareVuln.description, - vulnerableSoftware = vulnerableSoftware, - references = references - ) + def getVulnerabilityDetails(id: Int): Future[Option[com.ysoft.odc.Vulnerability]] = getVulnerabilityDetails(_.id === id) + + def getVulnerabilityDetails(name: String): Future[Option[com.ysoft.odc.Vulnerability]] = getVulnerabilityDetails(_.cve === name) + + def getVulnerabilityDetails(cond: Vulnerabilities => Rep[Boolean]): Future[Option[com.ysoft.odc.Vulnerability]] = { + db.run(vulnerabilities.filter(cond).result).map(_.headOption) flatMap { bareVulnOption => + bareVulnOption.fold[Future[Option[com.ysoft.odc.Vulnerability]]](Future.successful(None)) { case (id, bareVuln) => + for { + vulnerableSoftware <- getVulnerableSoftware(id) + references <- getReferences(id) + } yield Some( + com.ysoft.odc.Vulnerability( + name = bareVuln.cve, + cweOption = bareVuln.cweOption, + cvss = bareVuln.cvss, + description = bareVuln.description, + vulnerableSoftware = vulnerableSoftware, + references = references + ) + ) + } } }