From 41b48738470ff7f7b59a4dcc521a935cf100a3cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0est=C3=A1k=20V=C3=ADt?= Date: Mon, 20 Mar 2017 14:34:34 +0100 Subject: [PATCH] Major vulnerable libraries UI redesign --- app/assets/css/main.css | 43 +++++++- app/assets/js/main.js | 13 ++- app/views/dependencyDetailsInner.scala.html | 11 +++ app/views/dependencyList.scala.html | 98 +++++++++++++------ app/views/identifier.scala.html | 3 +- .../libraryIdentificationList.scala.html | 29 ++++++ 6 files changed, 162 insertions(+), 35 deletions(-) create mode 100644 app/views/libraryIdentificationList.scala.html diff --git a/app/assets/css/main.css b/app/assets/css/main.css index 360bd20..16740e9 100644 --- a/app/assets/css/main.css +++ b/app/assets/css/main.css @@ -75,15 +75,24 @@ h3.library-identification{ color: white; font-weight: bold; } +.dependencies-table .identifiers ul, .dependencies-table .identifiers ul li{ + margin-left: 0; + padding-left: 0; + list-style-type: none; +} .severity{ font-size: smaller; margin-bottom: 5px; + width: 10px; } .severity .score{ font-weight: bolder; } +.severity .computation-details{ + display: block; +} .explained{ border-bottom: 1px dashed black; @@ -101,7 +110,7 @@ h3.library-identification{ height: 1.5em; width: 1.5em; margin-left: 0.5em; - font-size: 50%; + font-size: 70%; } .explained:hover{ border-bottom-color: blue; @@ -155,4 +164,36 @@ h3.library-identification{ } .nav > li.collapse.in { display: list-item; +} + +.dependencies-table .vulns{ + text-align: right; +} +.dependencies-table .actions{ + vertical-align: bottom; + width: 10px; +} +.dependencies-table > tbody > tr:nth-of-type(4n+1), .dependencies-table > tbody > tr:nth-of-type(4n+2) { + background-color: #f9f9f9; +} +.dependencies-table > tbody > tr.details > td { + border-top-style: none; +} +.dependencies-table .severity .explained:hover { + color:blue; +} +.dependencies-table .severity .explained:after { + content: ""; + display: none; +} +.dependencies-table .severity .tooltip-inner { + white-space:nowrap; + max-width:none; +} +.dependencies-table .identifiers .tooltip-inner { + max-width: 350px; + width: 350px; +} +.dependencies-table .identifiers .explained{ + border-bottom: none; } \ No newline at end of file diff --git a/app/assets/js/main.js b/app/assets/js/main.js index 44f00d4..78e49b0 100644 --- a/app/assets/js/main.js +++ b/app/assets/js/main.js @@ -64,19 +64,24 @@ function updatePosition(){ } function lazyLoad(el){ var $el = $(el); + var wrapExpr = $el.attr('data-wrapper'); + var targetEl = wrapExpr ? $(wrapExpr) : $el; var url = $el.attr("data-lazyload-url"); function setUrl(newUrl){ - $el.attr("data-lazyload-url", newUrl); + $el.attr("data-lazyload-url", newUrl); } if(url){ - $el.html($('
') + if($el != targetEl){ + $el.html(targetEl); + } + targetEl.html($('
') .append( $('
Loading…
') ) ); - $el.load(url, function( response, status, xhr ) { + targetEl.load(url, function( response, status, xhr ) { if ( status == "error" ) { - $el.html("Error when loading data"); + targetEl.html("Error when loading data"); setUrl(url); } }); diff --git a/app/views/dependencyDetailsInner.scala.html b/app/views/dependencyDetailsInner.scala.html index 4155733..017e6d6 100644 --- a/app/views/dependencyDetailsInner.scala.html +++ b/app/views/dependencyDetailsInner.scala.html @@ -1,5 +1,16 @@ @(depPrefix: String, dep: GroupedDependency, selectorOption: Option[String]) +@dep.cpeIdentifiers.toSeq match { + case Seq() => {} + case cpeIds => { +

+ Look for vulnerabilities in other versions +

+ } +} + @if(dep.descriptions.size > 1){
Multiple descriptions for this dependency!
} diff --git a/app/views/dependencyList.scala.html b/app/views/dependencyList.scala.html index 44ec721..482a557 100644 --- a/app/views/dependencyList.scala.html +++ b/app/views/dependencyList.scala.html @@ -3,32 +3,74 @@ cpe.getBytes("utf-8").mkString("-") } -@for(dep <- list; depPrefix = s"$idPrefix-${dep.sha1}"){ -

- @libraryIdentification(dep, Some(cpe => s"$idPrefix-${dep.sha1}-suppression-cpe-${cpeHtmlId(cpe)}"), addLink = false, addButtons = addButtons) - @for(s <- dep.maxCvssScore) { - - (@s - × @dep.projects.size - = @dep.ysdssScore) - (vulns: @dep.vulnerabilities.size) - - } - @dep.cpeIdentifiers.toSeq match { - case Seq() => {} - case cpeIds => { - - } - } -

- @for(identifier <- dep.identifiers; cpe <- identifier.toCpeIdentifierOption ) { -
@SuppressionXml.forCpe(dep, cpe)
+ + + + + + + + + + @for(dep <- list; depPrefix = s"$idPrefix-${dep.sha1}"){ + + + + + + + } - @dependencyDetails( - depPrefix = depPrefix, - expandByDefault = expandByDefault, - selectorOption = selectorOption, - dep = dep - ) - -} +
SeverityIdentifiersVulns
+ @for(s <- dep.maxCvssScore) { + @dep.ysdssScore.map("%.2f".format(_)) + + = @s × @dep.projects.size + + } + + @libraryIdentificationList(dep, Some(cpe => s"$idPrefix-${dep.sha1}-suppression-cpe-${cpeHtmlId(cpe)}"), addLink = false, addButtons = addButtons) + @for(s <- dep.maxCvssScore) {@dep.vulnerabilities.size} + +
+ diff --git a/app/views/identifier.scala.html b/app/views/identifier.scala.html index d40ebca..facf294 100644 --- a/app/views/identifier.scala.html +++ b/app/views/identifier.scala.html @@ -1,3 +1,2 @@ @(identifier: Identifier, addLink: Boolean = true) -@identifier.confidence.toString.toLowerCase: -@secureLink(if(addLink) identifier.url else ""){@identifier.name} \ No newline at end of file +@secureLink(if(addLink) identifier.url else ""){@identifier.name} \ No newline at end of file diff --git a/app/views/libraryIdentificationList.scala.html b/app/views/libraryIdentificationList.scala.html new file mode 100644 index 0000000..58ab835 --- /dev/null +++ b/app/views/libraryIdentificationList.scala.html @@ -0,0 +1,29 @@ +@(dep: GroupedDependency, suppressionXmlIdOption: Option[String => String] = None, addLink: Boolean = true, addButtons: Boolean = true) +@import com.ysoft.odc.Confidence +@implicitOrdering = @{ + // This implicit should not be theoretically needed, but missing this used to cause somehow non-deterministic scalac behavior: + // The first ….sortBy expression used to pass, while the second one used to fail sometimes. Even though both expressions are essentially the same. + // When these expressions are swapped, still the first (after swapping) one passes and the second one fails, no matter which one is the first and + // which is the second. So, it looks like some compiler bug related to mutable state. + // It also seems to be related to some compiler cache. It is somehow possible to compile it by incremental compilation and some code changes, but + // clean build deterministically fails at the second expression. + // So, making the implicit explicit is a workaround for this issue. + Ordering.Tuple4[Confidence.Value, String, String, String] +} +
    +@if(!dep.identifiers.exists(_.confidence >= Confidence.High)){ +
  • @dep.fileNames.toSeq.sorted.mkString(", ")@if(addButtons){ }
  • +} +@for(id <- dep.identifiers.toSeq.sortBy(i => (i.confidence, i.identifierType, i.name, i.url)).reverse){ +
  • + @identifier(id, addLink) + @for(cpe <- id.toCpeIdentifierOption; suppressionXmlId <- suppressionXmlIdOption; if addButtons){ + + } + @if(addButtons && suppressionXmlIdOption.isDefined){ } +
  • +} +@for(id <- dep.suppressedIdentifiers.toSeq.sortBy(i => (i.confidence, i.identifierType, i.name, i.url)).reverse){ +
  • @identifier(id, addLink)
  • +} +
\ No newline at end of file