diff --git a/app/com/ysoft/odc/OdcParser.scala b/app/com/ysoft/odc/OdcParser.scala index 3376c8f..2d892bb 100644 --- a/app/com/ysoft/odc/OdcParser.scala +++ b/app/com/ysoft/odc/OdcParser.scala @@ -80,6 +80,7 @@ final case class GroupedDependency(dependencies: Map[Dependency, Set[ReportInfo] def hashes = dependencies.keys.head.hashes // valid since all deps in a group have the same hashes val sha1 = hashes.sha1 def identifiers: Set[Identifier] = dependencies.keySet.flatMap(_.identifiers) + def evidenceCollected: Set[Evidence] = dependencies.keySet.flatMap(_.evidenceCollected) def suppressedIdentifiers: Set[Identifier] = dependencies.keySet.flatMap(_.suppressedIdentifiers) def mavenIdentifiers = identifiers.filter(_.identifierType == "maven") def cpeIdentifiers = identifiers.filter(_.identifierType == "cpe") diff --git a/app/controllers/Statistics.scala b/app/controllers/Statistics.scala index d75a081..5faa382 100644 --- a/app/controllers/Statistics.scala +++ b/app/controllers/Statistics.scala @@ -31,6 +31,18 @@ object GroupedDependencyIdentifier{ ) } +final case class GroupedDependencyDetailedIdentifier(hashes: Hashes, identifiers: Seq[Identifier], evidence: Seq[Evidence], fileNames: Seq[String]) + +object GroupedDependencyDetailedIdentifier{ + def fromGroupedDependency(groupedDependency: GroupedDependency) = GroupedDependencyDetailedIdentifier( + hashes = groupedDependency.hashes, + identifiers = groupedDependency.identifiers.toIndexedSeq.sortBy(_.name), + evidence = groupedDependency.evidenceCollected.toIndexedSeq.sortBy(e => (e.name, e.value)), + fileNames = groupedDependency.fileNames.toIndexedSeq.sortBy(_.toLowerCase) + ) + +} + object Statistics{ // TODO: Move this to a better place @@ -39,7 +51,9 @@ object Statistics{ implicit val hashesWrites = Writes[Hashes](h => JsString(s"${h.sha1}-${h.md5}")) implicit val confidenceWrites = Writes[Confidence](c => JsString(c.toString)) implicit val identifierWrites = Json.writes[Identifier] + implicit val evidenceWrites = Json.writes[Evidence] implicit val groupedDependencyIdentifierWrites = Json.writes[GroupedDependencyIdentifier] + implicit val groupedDependencyDetailedIdentifierWrites = Json.writes[GroupedDependencyDetailedIdentifier] //implicit val groupedDependencyFormats = Json.format[GroupedDependency] } @@ -256,6 +270,16 @@ class Statistics @Inject()( } } + def allDependenciesVerbose(selectorOption: Option[String]) = ApiAction(Dependencies).async { implicit req => + val (lastRefreshTime, resultsFuture) = projectReportsProvider.resultsForVersions(versions) + resultsFuture flatMap { allResults => + select(allResults, selectorOption).fold(Future.successful(NotFound(Json.obj("error" -> "not found")))){ selection => + Future.successful(Ok(Json.toJson( + selection.result.groupedDependencies.map(gd => GroupedDependencyDetailedIdentifier.fromGroupedDependency(gd)).sortBy(gdi => (gdi.identifiers.map(_.name).mkString(", "), gdi.fileNames.mkString(", "), gdi.hashes.sha1, gdi.hashes.md5)) + ))) + } + } + } def vulnerableLibraries(selectorOption: Option[String]) = ReadAction.async { implicit req => diff --git a/conf/routes b/conf/routes index bc4841b..6abfb0f 100644 --- a/conf/routes +++ b/conf/routes @@ -6,6 +6,7 @@ GET / controllers.Application.homepage() GET /api/table controllers.Statistics.table() GET /api/all-dependencies.json controllers.Statistics.allDependencies(selector: Option[String]) +GET /api/all-dependencies-verbose.json controllers.Statistics.allDependenciesVerbose(selector: Option[String]) GET /status controllers.Application.index(versions: Map[String, Int] = Map()) GET /versions controllers.Application.index(versions: Map[String, Int]) GET /dependencies controllers.Application.dependencies(classified: Option[Boolean] = None, requiredTags: Seq[Int] ?= Seq(), noTag: Boolean ?= false)